diff options
author | Thomas Munro | 2021-05-07 08:17:42 +0000 |
---|---|---|
committer | Thomas Munro | 2021-05-07 09:10:11 +0000 |
commit | ec48314708262d8ea6cdcb83f803fc83dd89e721 (patch) | |
tree | f5b7c82ea571ce78aaa355095dd588dce07349ff /src/backend | |
parent | a288d94c91e345ebeb10ac30f247270c8c8e380a (diff) |
Revert per-index collation version tracking feature.
Design problems were discovered in the handling of composite types and
record types that would cause some relevant versions not to be recorded.
Misgivings were also expressed about the use of the pg_depend catalog
for this purpose. We're out of time for this release so we'll revert
and try again.
Commits reverted:
1bf946bd: Doc: Document known problem with Windows collation versions.
cf002008: Remove no-longer-relevant test case.
ef387bed: Fix bogus collation-version-recording logic.
0fb0a050: Hide internal error for pg_collation_actual_version(<bad OID>).
ff942057: Suppress "warning: variable 'collcollate' set but not used".
d50e3b1f: Fix assertion in collation version lookup.
f24b1569: Rethink extraction of collation dependencies.
257836a7: Track collation versions for indexes.
cd6f479e: Add pg_depend.refobjversion.
7d1297df: Remove pg_collation.collversion.
Discussion: https://postgr.es/m/CA%2BhUKGLhj5t1fcjqAu8iD9B3ixJtsTNqyCCD4V0aTO9kAKAjjA%40mail.gmail.com
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/catalog/dependency.c | 230 | ||||
-rw-r--r-- | src/backend/catalog/heap.c | 7 | ||||
-rw-r--r-- | src/backend/catalog/index.c | 198 | ||||
-rw-r--r-- | src/backend/catalog/pg_collation.c | 5 | ||||
-rw-r--r-- | src/backend/catalog/pg_constraint.c | 2 | ||||
-rw-r--r-- | src/backend/catalog/pg_depend.c | 47 | ||||
-rw-r--r-- | src/backend/catalog/pg_type.c | 69 | ||||
-rw-r--r-- | src/backend/commands/collationcmds.c | 104 | ||||
-rw-r--r-- | src/backend/commands/statscmds.c | 2 | ||||
-rw-r--r-- | src/backend/commands/tablecmds.c | 31 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 14 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 11 | ||||
-rw-r--r-- | src/backend/optimizer/util/plancat.c | 9 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 26 | ||||
-rw-r--r-- | src/backend/tcop/utility.c | 12 | ||||
-rw-r--r-- | src/backend/utils/adt/pg_locale.c | 89 | ||||
-rw-r--r-- | src/backend/utils/adt/pg_upgrade_support.c | 1 | ||||
-rw-r--r-- | src/backend/utils/cache/relcache.c | 2 |
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; |