diff options
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; |