diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 492ed348b3..29ee9605b6 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -2374,6 +2374,17 @@ SCRAM-SHA-256$<iteration count>:&l LC_CTYPE for this collation object + + + + collversion text + + + Provider-specific version of the collation. This is recorded when the + collation is created and then checked when it is used, to detect + changes in the collation definition that could lead to data corruption. + + @@ -3317,18 +3328,6 @@ SCRAM-SHA-256$<iteration count>:&l A code defining the specific semantics of this dependency relationship; see text - - - - refobjversion text - - - An optional version for the referenced object. Currently used for - indexes' collations (see ). - - - - diff --git a/doc/src/sgml/charset.sgml b/doc/src/sgml/charset.sgml index 1c673cc110..98df74d0e1 100644 --- a/doc/src/sgml/charset.sgml +++ b/doc/src/sgml/charset.sgml @@ -948,54 +948,6 @@ CREATE COLLATION ignore_accents (provider = icu, locale = 'und-u-ks-level1-kc-tr - - - Collation Versions - - - The sort order defined by a collation is not necessarily fixed over time. - PostgreSQL relies on external libraries that - are subject to operating system upgrades, and can also differ between - servers involved in binary replication and file-system-level migration. - Persistent data structures such as B-trees that depend on sort order might - be corrupted by any resulting change. - PostgreSQL defends against this by recording the - current version of each referenced collation for any index that depends on - it in the - pg_depend - catalog, if the collation provider makes that information available. If the - provider later begins to report a different version, a warning will be - issued when the index is accessed, until either the - command or the - command is used to update the version. - - - Version information is available from the - icu provider on all operating systems. For the - libc provider, versions are currently only available - on systems using the GNU C library (most Linux systems), FreeBSD and - Windows. - - - - - When using the GNU C library for collations, the C library's version - is used as a proxy for the collation version. Many Linux distributions - change collation definitions only when upgrading the C library, but this - approach is imperfect as maintainers are free to back-port newer - collation definitions to older C library releases. - - - When using Windows collations, version information is only available for - collations defined with BCP 47 language tags such as - en-US. Currently, initdb selects - a default locale using a traditional Windows language and country - string such as English_United States.1252. The - --lc-collate option can be used to provide an explicit - locale name in BCP 47 format. - - - diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 0b5571460d..4d1f1794ca 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -26547,9 +26547,11 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup()); Returns the actual version of the collation object as it is currently - installed in the operating system. null is returned - on operating systems where PostgreSQL - doesn't have support for versions. + installed in the operating system. If this is different from the + value in + pg_collation.collversion, + then objects depending on the collation might need to be rebuilt. See + also . diff --git a/doc/src/sgml/ref/alter_collation.sgml b/doc/src/sgml/ref/alter_collation.sgml index 65429aabe2..af9ff2867b 100644 --- a/doc/src/sgml/ref/alter_collation.sgml +++ b/doc/src/sgml/ref/alter_collation.sgml @@ -21,6 +21,8 @@ PostgreSQL documentation +ALTER COLLATION name REFRESH VERSION + ALTER COLLATION name RENAME TO new_name ALTER COLLATION name OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER } ALTER COLLATION name SET SCHEMA new_schema @@ -86,9 +88,70 @@ ALTER COLLATION name SET SCHEMA new_sche + + REFRESH VERSION + + + Update the collation's version. + See below. + + + + + Notes + + + When using collations provided by the ICU library, the ICU-specific version + of the collator is recorded in the system catalog when the collation object + is created. When the collation is used, the current version is + checked against the recorded version, and a warning is issued when there is + a mismatch, for example: + +WARNING: collation "xx-x-icu" has version mismatch +DETAIL: The collation in the database was created using version 1.2.3.4, but the operating system provides version 2.3.4.5. +HINT: Rebuild all objects affected by this collation and run ALTER COLLATION pg_catalog."xx-x-icu" REFRESH VERSION, or build PostgreSQL with the right library version. + + A change in collation definitions can lead to corrupt indexes and other + problems because the database system relies on stored objects having a + certain sort order. Generally, this should be avoided, but it can happen + in legitimate circumstances, such as when + using pg_upgrade to upgrade to server binaries linked + with a newer version of ICU. When this happens, all objects depending on + the collation should be rebuilt, for example, + using REINDEX. When that is done, the collation version + can be refreshed using the command ALTER COLLATION ... REFRESH + VERSION. This will update the system catalog to record the + current collator version and will make the warning go away. Note that this + does not actually check whether all affected objects have been rebuilt + correctly. + + + When using collations provided by libc and + PostgreSQL was built with the GNU C library, the + C library's version is used as a collation version. Since collation + definitions typically change only with GNU C library releases, this provides + some defense against corruption, but it is not completely reliable. + + + Currently, there is no version tracking for the database default collation. + + + + The following query can be used to identify all collations in the current + database that need to be refreshed and the objects that depend on them: + pg_collation_actual_version(c.oid) + ORDER BY 1, 2; +]]> + + Examples diff --git a/doc/src/sgml/ref/alter_index.sgml b/doc/src/sgml/ref/alter_index.sgml index 4b446384c2..e26efec064 100644 --- a/doc/src/sgml/ref/alter_index.sgml +++ b/doc/src/sgml/ref/alter_index.sgml @@ -25,7 +25,6 @@ ALTER INDEX [ IF EXISTS ] name RENA ALTER INDEX [ IF EXISTS ] name SET TABLESPACE tablespace_name ALTER INDEX name ATTACH PARTITION index_name ALTER INDEX name [ NO ] DEPENDS ON EXTENSION extension_name -ALTER INDEX name ALTER COLLATION collation_name REFRESH VERSION ALTER INDEX [ IF EXISTS ] name SET ( storage_parameter [= value] [, ... ] ) ALTER INDEX [ IF EXISTS ] name RESET ( storage_parameter [, ... ] ) ALTER INDEX [ IF EXISTS ] name ALTER [ COLUMN ] column_number @@ -113,20 +112,6 @@ ALTER INDEX ALL IN TABLESPACE name - - ALTER COLLATION collation_name REFRESH VERSION - - - Silences warnings about mismatched collation versions, by declaring - that the index is compatible with the current collation definition. - Be aware that incorrect use of this command can hide index corruption. - If you don't know whether a collation's definition has changed - incompatibly, is a safe alternative. - See for more information. - - - - SET ( storage_parameter [= value] [, ... ] ) diff --git a/doc/src/sgml/ref/create_collation.sgml b/doc/src/sgml/ref/create_collation.sgml index b97842071f..58f5f0cd63 100644 --- a/doc/src/sgml/ref/create_collation.sgml +++ b/doc/src/sgml/ref/create_collation.sgml @@ -27,6 +27,7 @@ CREATE COLLATION [ IF NOT EXISTS ] name ( [ LC_CTYPE = lc_ctype, ] [ PROVIDER = provider, ] [ DETERMINISTIC = boolean, ] + [ VERSION = version ] ) CREATE COLLATION [ IF NOT EXISTS ] name FROM existing_collation @@ -148,6 +149,26 @@ CREATE COLLATION [ IF NOT EXISTS ] name FROM + + version + + + + Specifies the version string to store with the collation. Normally, + this should be omitted, which will cause the version to be computed + from the actual version of the collation as provided by the operating + system. This option is intended to be used + by pg_upgrade for copying the version from an + existing installation. + + + + See also for how to handle + collation version mismatches. + + + + existing_collation diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml index 4737d97d20..a83c63cd98 100644 --- a/doc/src/sgml/ref/pgupgrade.sgml +++ b/doc/src/sgml/ref/pgupgrade.sgml @@ -215,21 +215,6 @@ PostgreSQL documentation - - - - - When upgrading indexes from releases before 14 that didn't track - collation versions, pg_upgrade - assumes by default that the upgraded indexes are compatible with the - currently installed versions of relevant collations (see - ). Specify - to mark - them as needing to be rebuilt instead. - - - - diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml index 53c362dcd3..e6b25ee670 100644 --- a/doc/src/sgml/ref/reindex.sgml +++ b/doc/src/sgml/ref/reindex.sgml @@ -40,15 +40,6 @@ REINDEX [ ( option [, ...] ) ] { IN several scenarios in which to use REINDEX: - - - The index depends on the sort order of a collation, and the definition - of the collation has changed. This can cause index scans to fail to - find keys that are present. See for - more information. - - - An index has become corrupted, and no longer contains valid diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 41093ea6ae..259cde3397 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" @@ -435,84 +434,6 @@ performMultipleDeletions(const ObjectAddresses *objects, table_close(depRel, RowExclusiveLock); } -/* - * 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' * @@ -1639,38 +1560,6 @@ ReleaseDeletionLock(const ObjectAddress *object) AccessExclusiveLock); } -/* - * 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 * @@ -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, @@ -1906,6 +1779,17 @@ find_expr_references_walker(Node *node, add_object_address(OCLASS_TYPE, con->consttype, 0, 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 @@ -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 42ff175bc8..431e62e389 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 a628b3281c..8ded2b53d4 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. */ + /* placeholder for normal dependencies */ + addrs = new_object_addresses(); + + /* Store dependency on collations */ + + /* The default collation is pinned, so don't bother recording it */ for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++) { - Oid colloid = collationObjectId[i]; - - if (OidIsValid(colloid)) + if (OidIsValid(collationObjectId[i]) && + collationObjectId[i] != DEFAULT_COLLATION_OID) { - Oid opclass = classObjectId[i]; - - /* - * 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 - { - 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 40d98a334a..19068b652a 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 0081558c48..a4e890020f 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 1217c01b8a..54688094f5 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 dc9d28a32c..da65584476 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" @@ -520,74 +519,6 @@ TypeCreate(Oid newTypeOid, return address; } -/* - * 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 * diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c index b8ec6f5756..ebb0994db3 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 df4768952d..acae19176c 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 0da61784d7..3b5d411683 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); @@ -18626,20 +18609,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. */ diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 632cc31a04..f5a7760740 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 a410a29a17..ce76d093dd 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1140,6 +1140,14 @@ _equalAlterTableCmd(const AlterTableCmd *a, const AlterTableCmd *b) return true; } +static bool +_equalAlterCollationStmt(const AlterCollationStmt *a, const AlterCollationStmt *b) +{ + COMPARE_NODE_FIELD(collname); + + return true; +} + static bool _equalAlterDomainStmt(const AlterDomainStmt *a, const AlterDomainStmt *b) { @@ -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 295ce11450..c5194fdbbf 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 b4ab4014c8..aaf1a51f68 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 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 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); @@ -10377,6 +10370,21 @@ drop_option: } ; +/***************************************************************************** + * + * ALTER COLLATION + * + *****************************************************************************/ + +AlterCollationStmt: ALTER COLLATION any_name REFRESH VERSION_P + { + AlterCollationStmt *n = makeNode(AlterCollationStmt); + n->collname = $3; + $$ = (Node *)n; + } + ; + + /***************************************************************************** * * ALTER SYSTEM diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 16c6f17e23..1a8fc16773 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 aa4874163f..eab089f252 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 a575c95079..b5b46d7231 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 31c8e07f2a..bd88f6105b 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; diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h index 3bc86635f7..fc054af5ba 100644 --- a/src/bin/pg_dump/pg_backup.h +++ b/src/bin/pg_dump/pg_backup.h @@ -180,7 +180,6 @@ typedef struct _dumpOptions int sequence_data; /* dump sequence data even in schema-only mode */ int do_nothing; - int coll_unknown; } DumpOptions; /* diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 3cb3598f2b..e384690d94 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -46,7 +46,6 @@ #include "catalog/pg_attribute_d.h" #include "catalog/pg_cast_d.h" #include "catalog/pg_class_d.h" -#include "catalog/pg_collation_d.h" #include "catalog/pg_default_acl_d.h" #include "catalog/pg_largeobject_d.h" #include "catalog/pg_largeobject_metadata_d.h" @@ -296,9 +295,6 @@ static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer, static const char *getAttrName(int attrnum, const TableInfo *tblInfo); static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer); static bool nonemptyReloptions(const char *reloptions); -static void appendIndexCollationVersion(PQExpBuffer buffer, const IndxInfo *indxinfo, - bool coll_unknown, - Archive *fout); static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions, const char *prefix, Archive *fout); static char *get_synchronized_snapshot(Archive *fout); @@ -401,7 +397,6 @@ main(int argc, char **argv) {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1}, {"rows-per-insert", required_argument, NULL, 10}, {"include-foreign-data", required_argument, NULL, 11}, - {"index-collation-versions-unknown", no_argument, &dopt.coll_unknown, 1}, {NULL, 0, NULL, 0} }; @@ -734,10 +729,6 @@ main(int argc, char **argv) if (archiveFormat != archDirectory && numWorkers > 1) fatal("parallel backup only supported by the directory format"); - /* Unknown collation versions only relevant in binary upgrade mode */ - if (dopt.coll_unknown && !dopt.binary_upgrade) - fatal("option --index-collation-versions-unknown only works in binary upgrade mode"); - /* Open the output file */ fout = CreateArchive(filename, archiveFormat, compressLevel, dosync, archiveMode, setupDumpWorker); @@ -7227,9 +7218,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) i_tablespace, i_indreloptions, i_indstatcols, - i_indstatvals, - i_inddependcollnames, - i_inddependcollversions; + i_indstatvals; int ntups; for (i = 0; i < numTables; i++) @@ -7265,7 +7254,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) * is not. */ resetPQExpBuffer(query); - if (fout->remoteVersion >= 140000) + if (fout->remoteVersion >= 110000) { appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, " @@ -7290,66 +7279,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) " " FROM pg_catalog.pg_attribute " " WHERE attrelid = i.indexrelid AND " - " attstattarget >= 0) AS indstatvals, " - "(SELECT pg_catalog.array_agg(quote_ident(ns.nspname) || '.' || quote_ident(c.collname) ORDER BY refobjid) " - " FROM pg_catalog.pg_depend d " - " JOIN pg_catalog.pg_collation c ON (c.oid = d.refobjid) " - " JOIN pg_catalog.pg_namespace ns ON (c.collnamespace = ns.oid) " - " WHERE d.classid = 'pg_catalog.pg_class'::regclass AND " - " d.objid = i.indexrelid AND " - " d.objsubid = 0 AND " - " d.refclassid = 'pg_catalog.pg_collation'::regclass AND " - " d.refobjversion IS NOT NULL) AS inddependcollnames, " - "(SELECT pg_catalog.array_agg(quote_literal(refobjversion) ORDER BY refobjid) " - " FROM pg_catalog.pg_depend " - " WHERE classid = 'pg_catalog.pg_class'::regclass AND " - " objid = i.indexrelid AND " - " objsubid = 0 AND " - " refclassid = 'pg_catalog.pg_collation'::regclass AND " - " refobjversion IS NOT NULL) AS inddependcollversions " - "FROM pg_catalog.pg_index i " - "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) " - "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) " - "LEFT JOIN pg_catalog.pg_constraint c " - "ON (i.indrelid = c.conrelid AND " - "i.indexrelid = c.conindid AND " - "c.contype IN ('p','u','x')) " - "LEFT JOIN pg_catalog.pg_inherits inh " - "ON (inh.inhrelid = indexrelid) " - "WHERE i.indrelid = '%u'::pg_catalog.oid " - "AND (i.indisvalid OR t2.relkind = 'p') " - "AND i.indisready " - "ORDER BY indexname", - tbinfo->dobj.catId.oid); - } - else if (fout->remoteVersion >= 110000) - { - appendPQExpBuffer(query, - "SELECT t.tableoid, t.oid, " - "t.relname AS indexname, " - "inh.inhparent AS parentidx, " - "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, " - "i.indnkeyatts AS indnkeyatts, " - "i.indnatts AS indnatts, " - "i.indkey, i.indisclustered, " - "i.indisreplident, " - "c.contype, c.conname, " - "c.condeferrable, c.condeferred, " - "c.tableoid AS contableoid, " - "c.oid AS conoid, " - "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, " - "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, " - "t.reloptions AS indreloptions, " - "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) " - " FROM pg_catalog.pg_attribute " - " WHERE attrelid = i.indexrelid AND " - " attstattarget >= 0) AS indstatcols," - "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) " - " FROM pg_catalog.pg_attribute " - " WHERE attrelid = i.indexrelid AND " - " attstattarget >= 0) AS indstatvals, " - "'{}' AS inddependcollnames, " - "'{}' AS inddependcollversions " + " attstattarget >= 0) AS indstatvals " "FROM pg_catalog.pg_index i " "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) " "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) " @@ -7388,9 +7318,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, " "t.reloptions AS indreloptions, " "'' AS indstatcols, " - "'' AS indstatvals, " - "'{}' AS inddependcollnames, " - "'{}' AS inddependcollversions " + "'' AS indstatvals " "FROM pg_catalog.pg_index i " "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) " "LEFT JOIN pg_catalog.pg_constraint c " @@ -7425,9 +7353,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, " "t.reloptions AS indreloptions, " "'' AS indstatcols, " - "'' AS indstatvals, " - "'{}' AS inddependcollnames, " - "'{}' AS inddependcollversions " + "'' AS indstatvals " "FROM pg_catalog.pg_index i " "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) " "LEFT JOIN pg_catalog.pg_constraint c " @@ -7458,9 +7384,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, " "t.reloptions AS indreloptions, " "'' AS indstatcols, " - "'' AS indstatvals, " - "'{}' AS inddependcollnames, " - "'{}' AS inddependcollversions " + "'' AS indstatvals " "FROM pg_catalog.pg_index i " "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) " "LEFT JOIN pg_catalog.pg_depend d " @@ -7494,9 +7418,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, " "null AS indreloptions, " "'' AS indstatcols, " - "'' AS indstatvals, " - "'{}' AS inddependcollnames, " - "'{}' AS inddependcollversions " + "'' AS indstatvals " "FROM pg_catalog.pg_index i " "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) " "LEFT JOIN pg_catalog.pg_depend d " @@ -7536,8 +7458,6 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) i_indreloptions = PQfnumber(res, "indreloptions"); i_indstatcols = PQfnumber(res, "indstatcols"); i_indstatvals = PQfnumber(res, "indstatvals"); - i_inddependcollnames = PQfnumber(res, "inddependcollnames"); - i_inddependcollversions = PQfnumber(res, "inddependcollversions"); tbinfo->indexes = indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo)); @@ -7563,8 +7483,6 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions)); indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols)); indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals)); - indxinfo[j].inddependcollnames = pg_strdup(PQgetvalue(res, j, i_inddependcollnames)); - indxinfo[j].inddependcollversions = pg_strdup(PQgetvalue(res, j, i_inddependcollversions)); indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid)); parseOidArray(PQgetvalue(res, j, i_indkey), indxinfo[j].indkeys, indxinfo[j].indnattrs); @@ -13933,10 +13851,12 @@ dumpCollation(Archive *fout, const CollInfo *collinfo) if (fout->remoteVersion >= 100000) appendPQExpBufferStr(query, - "collprovider, "); + "collprovider, " + "collversion, "); else appendPQExpBufferStr(query, - "'c' AS collprovider, "); + "'c' AS collprovider, " + "NULL AS collversion, "); if (fout->remoteVersion >= 120000) appendPQExpBufferStr(query, @@ -13997,6 +13917,24 @@ dumpCollation(Archive *fout, const CollInfo *collinfo) appendStringLiteralAH(q, collctype, fout); } + /* + * For binary upgrade, carry over the collation version. For normal + * dump/restore, omit the version, so that it is computed upon restore. + */ + if (dopt->binary_upgrade) + { + int i_collversion; + + i_collversion = PQfnumber(res, "collversion"); + if (!PQgetisnull(res, 0, i_collversion)) + { + appendPQExpBufferStr(q, ", version = "); + appendStringLiteralAH(q, + PQgetvalue(res, 0, i_collversion), + fout); + } + } + appendPQExpBufferStr(q, ");\n"); if (dopt->binary_upgrade) @@ -16770,8 +16708,7 @@ dumpIndex(Archive *fout, const IndxInfo *indxinfo) /* * If there's an associated constraint, don't dump the index per se, but - * do dump any comment, or in binary upgrade mode dependency on a - * collation version for it. (This is safe because dependency ordering + * do dump any comment for it. (This is safe because dependency ordering * will have ensured the constraint is emitted first.) Note that the * emitted comment has to be shown as depending on the constraint, not the * index, in such cases. @@ -16843,9 +16780,6 @@ dumpIndex(Archive *fout, const IndxInfo *indxinfo) "pg_catalog.pg_class", "INDEX", qqindxname); - if (dopt->binary_upgrade) - appendIndexCollationVersion(q, indxinfo, dopt->coll_unknown, fout); - /* If the index defines identity, we need to record that. */ if (indxinfo->indisreplident) { @@ -16874,20 +16808,6 @@ dumpIndex(Archive *fout, const IndxInfo *indxinfo) if (indstatvalsarray) free(indstatvalsarray); } - else if (dopt->binary_upgrade) - { - appendIndexCollationVersion(q, indxinfo, dopt->coll_unknown, fout); - - if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION) - ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId, - ARCHIVE_OPTS(.tag = indxinfo->dobj.name, - .namespace = tbinfo->dobj.namespace->dobj.name, - .tablespace = indxinfo->tablespace, - .owner = tbinfo->rolname, - .description = "INDEX", - .section = SECTION_POST_DATA, - .createStmt = q->data)); - } /* Dump Index Comments */ if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT) @@ -18896,82 +18816,6 @@ nonemptyReloptions(const char *reloptions) return (reloptions != NULL && strlen(reloptions) > 2); } -/* - * Generate UPDATE statements to import the collation versions into the new - * cluster, during a binary upgrade. - */ -static void -appendIndexCollationVersion(PQExpBuffer buffer, const IndxInfo *indxinfo, - bool coll_unknown, Archive *fout) -{ - char *inddependcollnames = indxinfo->inddependcollnames; - char *inddependcollversions = indxinfo->inddependcollversions; - char **inddependcollnamesarray; - char **inddependcollversionsarray; - int ninddependcollnames; - int ninddependcollversions; - - /* - * By default, the new cluster's index will have pg_depends rows with - * current collation versions, meaning that we assume the index isn't - * corrupted if importing from a release that didn't record versions. - * However, if --index-collation-versions-unknown was passed in, then we - * assume such indexes might be corrupted, and clobber versions with - * 'unknown' to trigger version warnings. - */ - if (coll_unknown) - { - appendPQExpBuffer(buffer, - "\n-- For binary upgrade, clobber new index's collation versions\n"); - appendPQExpBuffer(buffer, - "UPDATE pg_catalog.pg_depend SET refobjversion = 'unknown' WHERE objid = '%u'::pg_catalog.oid AND refclassid = 'pg_catalog.pg_collation'::regclass AND refobjversion IS NOT NULL;\n", - indxinfo->dobj.catId.oid); - } - - /* Restore the versions that were recorded by the old cluster (if any). */ - if (strlen(inddependcollnames) == 0 && strlen(inddependcollversions) == 0) - { - ninddependcollnames = ninddependcollversions = 0; - inddependcollnamesarray = inddependcollversionsarray = NULL; - } - else - { - if (!parsePGArray(inddependcollnames, - &inddependcollnamesarray, - &ninddependcollnames)) - fatal("could not parse index collation name array"); - if (!parsePGArray(inddependcollversions, - &inddependcollversionsarray, - &ninddependcollversions)) - fatal("could not parse index collation version array"); - } - - if (ninddependcollnames != ninddependcollversions) - fatal("mismatched number of collation names and versions for index"); - - if (ninddependcollnames > 0) - appendPQExpBufferStr(buffer, - "\n-- For binary upgrade, restore old index's collation versions\n"); - for (int i = 0; i < ninddependcollnames; i++) - { - /* - * Import refobjversion from the old cluster, being careful to resolve - * the collation OID by name in the new cluster. - */ - appendPQExpBuffer(buffer, - "UPDATE pg_catalog.pg_depend SET refobjversion = %s WHERE objid = '%u'::pg_catalog.oid AND refclassid = 'pg_catalog.pg_collation'::regclass AND refobjversion IS NOT NULL AND refobjid = ", - inddependcollversionsarray[i], - indxinfo->dobj.catId.oid); - appendStringLiteralAH(buffer, inddependcollnamesarray[i], fout); - appendPQExpBuffer(buffer, "::regcollation;\n"); - } - - if (inddependcollnamesarray) - free(inddependcollnamesarray); - if (inddependcollversionsarray) - free(inddependcollversionsarray); -} - /* * Format a reloptions array and append it to the given buffer. * diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 5340843081..49e1b0a09c 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -376,8 +376,6 @@ typedef struct _indxInfo int indnattrs; /* total number of index attributes */ Oid *indkeys; /* In spite of the name 'indkeys' this field * contains both key and nonkey attributes */ - char *inddependcollnames; /* FQ names of depended-on collations */ - char *inddependcollversions; /* versions of the above */ bool indisclustered; bool indisreplident; Oid parentidx; /* if a partition, parent index OID */ diff --git a/src/bin/pg_upgrade/dump.c b/src/bin/pg_upgrade/dump.c index 33d9591f37..90060d0f8e 100644 --- a/src/bin/pg_upgrade/dump.c +++ b/src/bin/pg_upgrade/dump.c @@ -52,11 +52,9 @@ generate_old_dump(void) parallel_exec_prog(log_file_name, NULL, "\"%s/pg_dump\" %s --schema-only --quote-all-identifiers " - "--binary-upgrade --format=custom %s %s --file=\"%s\" %s", + "--binary-upgrade --format=custom %s --file=\"%s\" %s", new_cluster.bindir, cluster_conn_opts(&old_cluster), log_opts.verbose ? "--verbose" : "", - user_opts.ind_coll_unknown ? - "--index-collation-versions-unknown" : "", sql_file_name, escaped_connstr.data); termPQExpBuffer(&escaped_connstr); diff --git a/src/bin/pg_upgrade/option.c b/src/bin/pg_upgrade/option.c index 4b74f9eea7..64bbda5650 100644 --- a/src/bin/pg_upgrade/option.c +++ b/src/bin/pg_upgrade/option.c @@ -56,7 +56,6 @@ parseCommandLine(int argc, char *argv[]) {"socketdir", required_argument, NULL, 's'}, {"verbose", no_argument, NULL, 'v'}, {"clone", no_argument, NULL, 1}, - {"index-collation-versions-unknown", no_argument, NULL, 2}, {NULL, 0, NULL, 0} }; @@ -204,10 +203,6 @@ parseCommandLine(int argc, char *argv[]) user_opts.transfer_mode = TRANSFER_MODE_CLONE; break; - case 2: - user_opts.ind_coll_unknown = true; - break; - default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), os_info.progname); @@ -312,8 +307,6 @@ usage(void) printf(_(" -v, --verbose enable verbose internal logging\n")); printf(_(" -V, --version display version information, then exit\n")); printf(_(" --clone clone instead of copying files to new cluster\n")); - printf(_(" --index-collation-versions-unknown\n" - " mark text indexes as needing to be rebuilt\n")); printf(_(" -?, --help show this help, then exit\n")); printf(_("\n" "Before running pg_upgrade you must:\n" diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h index d7666da3f2..a5f71c5294 100644 --- a/src/bin/pg_upgrade/pg_upgrade.h +++ b/src/bin/pg_upgrade/pg_upgrade.h @@ -292,7 +292,6 @@ typedef struct transferMode transfer_mode; /* copy files or link them? */ int jobs; /* number of processes/threads to use */ char *socketdir; /* directory to use for Unix sockets */ - bool ind_coll_unknown; /* mark unknown index collation versions */ } UserOpts; typedef struct diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 7c4933333b..d917987fd5 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -45,7 +45,6 @@ #include "catalog/pg_am_d.h" #include "catalog/pg_class_d.h" -#include "catalog/pg_collation_d.h" #include "common.h" #include "libpq-fe.h" #include "pqexpbuffer.h" @@ -842,20 +841,6 @@ static const SchemaQuery Query_for_list_of_collations = { " (SELECT tgrelid FROM pg_catalog.pg_trigger "\ " WHERE pg_catalog.quote_ident(tgname)='%s')" -/* the silly-looking length condition is just to eat up the current word */ -#define Query_for_list_of_colls_for_one_index \ -" SELECT DISTINCT pg_catalog.quote_ident(coll.collname) " \ -" FROM pg_catalog.pg_depend d, pg_catalog.pg_collation coll, " \ -" pg_catalog.pg_class c" \ -" WHERE (%d = pg_catalog.length('%s'))" \ -" AND d.refclassid = " CppAsString2(CollationRelationId) \ -" AND d.refobjid = coll.oid " \ -" AND d.classid = " CppAsString2(RelationRelationId) \ -" AND d.objid = c.oid " \ -" AND c.relkind = " CppAsString2(RELKIND_INDEX) \ -" AND pg_catalog.pg_table_is_visible(c.oid) " \ -" AND c.relname = '%s'" - #define Query_for_list_of_ts_configurations \ "SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config "\ " WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'" @@ -1769,15 +1754,14 @@ psql_completion(const char *text, int start, int end) else if (Matches("ALTER", "INDEX", MatchAny)) COMPLETE_WITH("ALTER COLUMN", "OWNER TO", "RENAME TO", "SET", "RESET", "ATTACH PARTITION", - "DEPENDS ON EXTENSION", "NO DEPENDS ON EXTENSION", - "ALTER COLLATION"); + "DEPENDS ON EXTENSION", "NO DEPENDS ON EXTENSION"); else if (Matches("ALTER", "INDEX", MatchAny, "ATTACH")) COMPLETE_WITH("PARTITION"); else if (Matches("ALTER", "INDEX", MatchAny, "ATTACH", "PARTITION")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL); /* ALTER INDEX ALTER */ else if (Matches("ALTER", "INDEX", MatchAny, "ALTER")) - COMPLETE_WITH("COLLATION", "COLUMN"); + COMPLETE_WITH("COLUMN"); /* ALTER INDEX ALTER COLUMN */ else if (Matches("ALTER", "INDEX", MatchAny, "ALTER", "COLUMN")) { @@ -1816,15 +1800,10 @@ psql_completion(const char *text, int start, int end) "buffering =", /* GiST */ "pages_per_range =", "autosummarize =" /* BRIN */ ); - /* ALTER INDEX ALTER COLLATION */ - else if (Matches("ALTER", "INDEX", MatchAny, "ALTER", "COLLATION")) - { - completion_info_charp = prev3_wd; - COMPLETE_WITH_QUERY(Query_for_list_of_colls_for_one_index); - } - /* ALTER INDEX ALTER COLLATION */ - else if (Matches("ALTER", "INDEX", MatchAny, "ALTER", "COLLATION", MatchAny)) - COMPLETE_WITH("REFRESH VERSION"); + else if (Matches("ALTER", "INDEX", MatchAny, "NO", "DEPENDS")) + COMPLETE_WITH("ON EXTENSION"); + else if (Matches("ALTER", "INDEX", MatchAny, "DEPENDS")) + COMPLETE_WITH("ON EXTENSION"); /* ALTER LANGUAGE */ else if (Matches("ALTER", "LANGUAGE", MatchAny)) diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 22dcd0a270..a54be88d7f 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202104271 +#define CATALOG_VERSION_NO 202105051 #endif diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index f272e2c99f..fd44081e74 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -167,8 +167,7 @@ extern void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, - bool reverse_self, - bool record_version); + bool reverse_self); extern ObjectClass getObjectClass(const ObjectAddress *object); @@ -188,30 +187,16 @@ extern void sort_object_addresses(ObjectAddresses *addrs); extern void free_object_addresses(ObjectAddresses *addrs); -typedef bool(*VisitDependenciesOfCB) (const ObjectAddress *otherObject, - const char *version, - char **new_version, - void *data); - -extern void visitDependenciesOf(const ObjectAddress *object, - VisitDependenciesOfCB callback, - void *data); - /* in pg_depend.c */ extern void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior); -extern void recordDependencyOnCollations(ObjectAddress *myself, - List *collations, - bool record_version); - extern void recordMultipleDependencies(const ObjectAddress *depender, const ObjectAddress *referenced, int nreferenced, - DependencyType behavior, - bool record_version); + DependencyType behavior); extern void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace); @@ -232,6 +217,7 @@ extern long changeDependencyFor(Oid classId, Oid objectId, extern long changeDependenciesOf(Oid classId, Oid oldObjectId, Oid newObjectId); + extern long changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId); diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index e22d506436..008f723e10 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -136,9 +136,6 @@ extern void FormIndexDatum(IndexInfo *indexInfo, Datum *values, bool *isnull); -extern void index_check_collation_versions(Oid relid); -extern void index_update_collation_versions(Oid relid, Oid coll); - extern void index_build(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, diff --git a/src/include/catalog/pg_collation.h b/src/include/catalog/pg_collation.h index c6394ca222..52bfd2cb7b 100644 --- a/src/include/catalog/pg_collation.h +++ b/src/include/catalog/pg_collation.h @@ -41,6 +41,11 @@ CATALOG(pg_collation,3456,CollationRelationId) int32 collencoding; /* encoding for this collation; -1 = "all" */ NameData collcollate; /* LC_COLLATE setting */ NameData collctype; /* LC_CTYPE setting */ +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + text collversion BKI_DEFAULT(_null_); /* provider-dependent */ + /* version of */ + /* collation data */ +#endif } FormData_pg_collation; /* ---------------- @@ -50,6 +55,8 @@ CATALOG(pg_collation,3456,CollationRelationId) */ typedef FormData_pg_collation *Form_pg_collation; +DECLARE_TOAST(pg_collation, 8888, 8889); + DECLARE_UNIQUE_INDEX(pg_collation_name_enc_nsp_index, 3164, on pg_collation using btree(collname name_ops, collencoding int4_ops, collnamespace oid_ops)); #define CollationNameEncNspIndexId 3164 DECLARE_UNIQUE_INDEX_PKEY(pg_collation_oid_index, 3085, on pg_collation using btree(oid oid_ops)); @@ -70,6 +77,7 @@ extern Oid 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); diff --git a/src/include/catalog/pg_depend.h b/src/include/catalog/pg_depend.h index 606a2a8e19..e0bc114145 100644 --- a/src/include/catalog/pg_depend.h +++ b/src/include/catalog/pg_depend.h @@ -63,9 +63,6 @@ CATALOG(pg_depend,2608,DependRelationId) * field. See DependencyType in catalog/dependency.h. */ char deptype; /* see codes in dependency.h */ -#ifdef CATALOG_VARLEN - text refobjversion; /* version of referenced object */ -#endif } FormData_pg_depend; /* ---------------- @@ -75,8 +72,6 @@ CATALOG(pg_depend,2608,DependRelationId) */ typedef FormData_pg_depend *Form_pg_depend; -DECLARE_TOAST(pg_depend, 8888, 8889); - DECLARE_INDEX(pg_depend_depender_index, 2673, on pg_depend using btree(classid oid_ops, objid oid_ops, objsubid int4_ops)); #define DependDependerIndexId 2673 DECLARE_INDEX(pg_depend_reference_index, 2674, on pg_depend using btree(refclassid oid_ops, refobjid oid_ops, refobjsubid int4_ops)); diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 8ee5fa0507..33557760e1 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -390,8 +390,6 @@ extern void GenerateTypeDependencies(HeapTuple typeTuple, bool isDependentType, bool rebuild); -extern List *GetTypeCollations(Oid typeObjectid); - extern void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace); diff --git a/src/include/commands/collationcmds.h b/src/include/commands/collationcmds.h index 4e69045880..e49a5db0fb 100644 --- a/src/include/commands/collationcmds.h +++ b/src/include/commands/collationcmds.h @@ -20,5 +20,6 @@ extern ObjectAddress DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_exists); extern void IsThereCollationInNamespace(const char *collname, Oid nspOid); +extern ObjectAddress AlterCollation(AlterCollationStmt *stmt); #endif /* COLLATIONCMDS_H */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 615dfa26aa..fea3123251 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1933,7 +1933,6 @@ typedef enum AlterTableType AT_AddIdentity, /* ADD IDENTITY */ AT_SetIdentity, /* SET identity column options */ AT_DropIdentity, /* DROP IDENTITY */ - AT_AlterCollationRefreshVersion, /* ALTER COLLATION ... REFRESH VERSION */ AT_ReAddStatistics /* internal to commands/tablecmds.c */ } AlterTableType; @@ -1950,7 +1949,6 @@ typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */ AlterTableType subtype; /* Type of table alteration to apply */ char *name; /* column, constraint, or trigger to act on, * or tablespace */ - List *object; /* collation to act on if it's a collation */ int16 num; /* attribute number for columns referenced by * number */ RoleSpec *newowner; @@ -1961,6 +1959,17 @@ typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */ } AlterTableCmd; +/* ---------------------- + * Alter Collation + * ---------------------- + */ +typedef struct AlterCollationStmt +{ + NodeTag type; + List *collname; +} AlterCollationStmt; + + /* ---------------------- * Alter Domain * diff --git a/src/include/utils/pg_locale.h b/src/include/utils/pg_locale.h index 5a37caefbe..2946f46c76 100644 --- a/src/include/utils/pg_locale.h +++ b/src/include/utils/pg_locale.h @@ -103,7 +103,7 @@ typedef struct pg_locale_struct *pg_locale_t; extern pg_locale_t pg_newlocale_from_collation(Oid collid); -extern char *get_collation_version_for_oid(Oid collid, bool missing_ok); +extern char *get_collation_actual_version(char collprovider, const char *collcollate); #ifdef USE_ICU extern int32_t icu_to_uchar(UChar **buff_uchar, const char *buff, size_t nbytes); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 5bd44be9a7..774ac5b2b1 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -63,7 +63,6 @@ typedef struct RelationData bool rd_indexvalid; /* is rd_indexlist valid? (also rd_pkindex and * rd_replidindex) */ bool rd_statvalid; /* is rd_statlist valid? */ - bool rd_version_checked; /* has version check been done yet? */ /*---------- * rd_createSubid is the ID of the highest subtransaction the rel has diff --git a/src/test/Makefile b/src/test/Makefile index f7859c2fd5..46275915ff 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -12,8 +12,7 @@ subdir = src/test top_builddir = ../.. include $(top_builddir)/src/Makefile.global -SUBDIRS = perl regress isolation modules authentication recovery subscription \ - locale +SUBDIRS = perl regress isolation modules authentication recovery subscription # Test suites that are not safe by default but can be run if selected # by the user via the whitespace-separated list in variable diff --git a/src/test/locale/.gitignore b/src/test/locale/.gitignore index 64e1bf2a80..620d3df425 100644 --- a/src/test/locale/.gitignore +++ b/src/test/locale/.gitignore @@ -1,2 +1 @@ /test-ctype -/tmp_check/ diff --git a/src/test/locale/Makefile b/src/test/locale/Makefile index 673e14dcd0..7ba096b542 100644 --- a/src/test/locale/Makefile +++ b/src/test/locale/Makefile @@ -4,7 +4,6 @@ subdir = src/test/locale top_builddir = ../../.. include $(top_builddir)/src/Makefile.global -export with_icu PROGS = test-ctype DIRS = de_DE.ISO8859-1 gr_GR.ISO8859-7 koi8-r koi8-to-win1251 @@ -21,9 +20,3 @@ clean distclean maintainer-clean: # These behave like installcheck targets. check-%: all @$(MAKE) -C `echo $@ | sed 's/^check-//'` test - -check: - $(prove_check) - -installcheck: - $(prove_installcheck) diff --git a/src/test/locale/t/001_index.pl b/src/test/locale/t/001_index.pl deleted file mode 100644 index a67f78cb71..0000000000 --- a/src/test/locale/t/001_index.pl +++ /dev/null @@ -1,67 +0,0 @@ -use strict; -use warnings; - -use Config; -use PostgresNode; -use TestLib; -use Test::More; - -if ($ENV{with_icu} eq 'yes') -{ - plan tests => 10; -} -else -{ - plan skip_all => 'ICU not supported by this build'; -} - -#### Set up the server - -note "setting up data directory"; -my $node = get_new_node('main'); -$node->init(extra => [ '--encoding=UTF8' ]); - -$ENV{PGHOST} = $node->host; -$ENV{PGPORT} = $node->port; -$node->start; - -sub test_index -{ - my ($err_like, $err_comm) = @_; - my ($ret, $out, $err) = $node->psql('postgres', "SELECT * FROM icu1"); - is($ret, 0, 'SELECT should succeed.'); - like($err, $err_like, $err_comm); -} - -$node->safe_psql('postgres', 'CREATE TABLE icu1(val text);'); -$node->safe_psql('postgres', 'CREATE INDEX icu1_fr ON icu1 (val COLLATE "fr-x-icu");'); - -test_index(qr/^$/, 'No warning should be raised'); - -# Simulate different collation version -$node->safe_psql('postgres', - "UPDATE pg_depend SET refobjversion = 'not_a_version'" - . " WHERE refobjversion IS NOT NULL" - . " AND objid::regclass::text = 'icu1_fr';"); - -test_index(qr/index "icu1_fr" depends on collation "fr-x-icu" version "not_a_version", but the current version is/, - 'Different collation version warning should be raised.'); - -$node->safe_psql('postgres', 'ALTER INDEX icu1_fr ALTER COLLATION "fr-x-icu" REFRESH VERSION;'); - -test_index(qr/^$/, 'No warning should be raised'); - -# Simulate different collation version -$node->safe_psql('postgres', - "UPDATE pg_depend SET refobjversion = 'not_a_version'" - . " WHERE refobjversion IS NOT NULL" - . " AND objid::regclass::text = 'icu1_fr';"); - -test_index(qr/index "icu1_fr" depends on collation "fr-x-icu" version "not_a_version", but the current version is/, - 'Different collation version warning should be raised.'); - -$node->safe_psql('postgres', 'REINDEX TABLE icu1;'); - -test_index(qr/^$/, 'No warning should be raised'); - -$node->stop; diff --git a/src/test/regress/expected/collate.icu.utf8.out b/src/test/regress/expected/collate.icu.utf8.out index faf99f76b5..70133df804 100644 --- a/src/test/regress/expected/collate.icu.utf8.out +++ b/src/test/regress/expected/collate.icu.utf8.out @@ -1082,6 +1082,9 @@ SELECT collname FROM pg_collation WHERE collname LIKE 'test%'; DROP SCHEMA test_schema; DROP ROLE regress_test_role; +-- ALTER +ALTER COLLATION "en-x-icu" REFRESH VERSION; +NOTICE: version has not changed -- dependencies CREATE COLLATION test0 FROM "C"; CREATE TABLE collate_dep_test1 (a int, b text COLLATE test0); @@ -1947,184 +1950,6 @@ SELECT (SELECT count(*) FROM test33_0) <> (SELECT count(*) FROM test33_1); t (1 row) --- collation versioning support -CREATE TYPE t_en_fr AS (fr text COLLATE "fr-x-icu", en text COLLATE "en-x-icu"); -CREATE DOMAIN d_en_fr AS t_en_fr; -CREATE DOMAIN d_es AS text COLLATE "es-x-icu"; -CREATE TYPE t_en_fr_ga AS (en_fr t_en_fr, ga text COLLATE "ga-x-icu"); -CREATE DOMAIN d_en_fr_ga AS t_en_fr_ga; -CREATE TYPE t_custom AS (meh text, meh2 text); -CREATE DOMAIN d_custom AS t_custom; -CREATE COLLATION custom ( - LOCALE = 'fr-x-icu', PROVIDER = 'icu' -); -CREATE TYPE myrange AS range (subtype = text, collation = "POSIX"); -CREATE TYPE myrange_en_fr_ga AS range(subtype = t_en_fr_ga); -CREATE TABLE collate_test ( - id integer, - val text COLLATE "fr-x-icu", - t_en_fr t_en_fr, - d_en_fr d_en_fr, - d_es d_es, - t_en_fr_ga t_en_fr_ga, - d_en_fr_ga d_en_fr_ga, - d_en_fr_ga_arr d_en_fr_ga[], - myrange myrange, - myrange_en_fr_ga myrange_en_fr_ga -); -CREATE INDEX icuidx00_val ON collate_test(val); --- shouldn't get duplicated dependencies -CREATE INDEX icuidx00_val_val ON collate_test(val, val); --- shouldn't track version -CREATE INDEX icuidx00_val_pattern ON collate_test(val text_pattern_ops); --- should have single dependency, no version -CREATE INDEX icuidx00_val_pattern_val_pattern ON collate_test(val text_pattern_ops, val text_pattern_ops); --- should have single dependency, with version -CREATE INDEX icuidx00_val_pattern_val ON collate_test(val text_pattern_ops, val); --- should have single dependency, with version -CREATE INDEX icuidx00_val_val_pattern ON collate_test(val, val text_pattern_ops); --- two rows expected, only one a version, because we don't try to merge these yet -CREATE INDEX icuidx00_val_pattern_where ON collate_test(val text_pattern_ops) WHERE val >= val; --- two rows expected with version, because we don't try to merge these yet -CREATE INDEX icuidx00_val_where ON collate_test(val) WHERE val >= val; --- two rows expected with version (expression walker + attribute) -CREATE INDEX icuidx00_val_pattern_expr ON collate_test(val varchar_pattern_ops, (val || val)); --- two rows expected, one with a version (expression walker + attribute) -CREATE INDEX icuidx00_val_pattern_expr_pattern ON collate_test(val varchar_pattern_ops, (val || val) text_pattern_ops); --- should have single dependency, with version tracked -CREATE INDEX icuidx01_t_en_fr__d_es ON collate_test (t_en_fr, d_es); -CREATE INDEX icuidx02_d_en_fr ON collate_test (d_en_fr); -CREATE INDEX icuidx03_t_en_fr_ga ON collate_test (t_en_fr_ga); -CREATE INDEX icuidx04_d_en_fr_ga ON collate_test (d_en_fr_ga); -CREATE INDEX icuidx05_d_en_fr_ga_arr ON collate_test (d_en_fr_ga_arr); -CREATE INDEX icuidx06_d_en_fr_ga ON collate_test(id) WHERE (d_en_fr_ga).en_fr.fr = 'foo'; -CREATE INDEX icuidx07_d_en_fr_ga ON collate_test(id) WHERE (d_en_fr_ga).ga = 'foo'; -CREATE INDEX icuidx08_d_en_fr_ga ON collate_test(id) WHERE (t_en_fr_ga) = ('foo', 'bar', 'baz'); -CREATE INDEX icuidx09_d_en_fr_ga ON collate_test(id) WHERE (d_en_fr_ga) = ('foo', 'bar', 'baz'); -CREATE INDEX icuidx10_d_en_fr_ga_es ON collate_test(id) WHERE (d_en_fr_ga) = ('foo', 'bar', 'baz' COLLATE "es-x-icu"); -CREATE INDEX icuidx11_d_es ON collate_test(id) WHERE (d_es) = ('foo'); -CREATE INDEX icuidx12_custom ON collate_test(id) WHERE ('foo', 'bar')::d_custom = ('foo', 'bar' COLLATE custom)::d_custom; -CREATE INDEX icuidx13_custom ON collate_test(id) WHERE ('foo' COLLATE custom, 'bar')::d_custom = ('foo', 'bar')::d_custom; -CREATE INDEX icuidx14_myrange ON collate_test(myrange); -CREATE INDEX icuidx15_myrange_en_fr_ga ON collate_test USING gist (myrange_en_fr_ga); -CREATE TABLE collate_part(id integer, val text COLLATE "en-x-icu") PARTITION BY range(id); -CREATE TABLE collate_part_0 PARTITION OF collate_part FOR VALUES FROM (0) TO (1); -CREATE TABLE collate_part_1 PARTITION OF collate_part FOR VALUES FROM (1) TO (1000000); -CREATE INDEX icuidx17_part ON collate_part_1 (val); -SELECT objid::regclass::text collate "C", refobjid::regcollation::text collate "C", -CASE -WHEN refobjid = 'default'::regcollation THEN 'XXX' -- depends on libc version support -WHEN refobjversion IS NULL THEN 'version not tracked' -WHEN refobjversion = pg_collation_actual_version(refobjid) THEN 'up to date' -ELSE 'out of date' -END AS version -FROM pg_depend d -LEFT JOIN pg_class c ON c.oid = d.objid -WHERE refclassid = 'pg_collation'::regclass -AND coalesce(relkind, 'i') = 'i' -AND relname LIKE 'icuidx%' -ORDER BY 1, 2, 3; - objid | refobjid | version ------------------------------------+------------+--------------------- - icuidx00_val | "fr-x-icu" | up to date - icuidx00_val_pattern | "fr-x-icu" | version not tracked - icuidx00_val_pattern_expr | "fr-x-icu" | up to date - icuidx00_val_pattern_expr | "fr-x-icu" | up to date - icuidx00_val_pattern_expr_pattern | "fr-x-icu" | up to date - icuidx00_val_pattern_expr_pattern | "fr-x-icu" | version not tracked - icuidx00_val_pattern_val | "fr-x-icu" | up to date - icuidx00_val_pattern_val_pattern | "fr-x-icu" | version not tracked - icuidx00_val_pattern_where | "fr-x-icu" | up to date - icuidx00_val_pattern_where | "fr-x-icu" | version not tracked - icuidx00_val_val | "fr-x-icu" | up to date - icuidx00_val_val_pattern | "fr-x-icu" | up to date - icuidx00_val_where | "fr-x-icu" | up to date - icuidx00_val_where | "fr-x-icu" | up to date - icuidx01_t_en_fr__d_es | "en-x-icu" | up to date - icuidx01_t_en_fr__d_es | "es-x-icu" | up to date - icuidx01_t_en_fr__d_es | "fr-x-icu" | up to date - icuidx02_d_en_fr | "en-x-icu" | up to date - icuidx02_d_en_fr | "fr-x-icu" | up to date - icuidx03_t_en_fr_ga | "en-x-icu" | up to date - icuidx03_t_en_fr_ga | "fr-x-icu" | up to date - icuidx03_t_en_fr_ga | "ga-x-icu" | up to date - icuidx04_d_en_fr_ga | "en-x-icu" | up to date - icuidx04_d_en_fr_ga | "fr-x-icu" | up to date - icuidx04_d_en_fr_ga | "ga-x-icu" | up to date - icuidx05_d_en_fr_ga_arr | "en-x-icu" | up to date - icuidx05_d_en_fr_ga_arr | "fr-x-icu" | up to date - icuidx05_d_en_fr_ga_arr | "ga-x-icu" | up to date - icuidx06_d_en_fr_ga | "fr-x-icu" | up to date - icuidx07_d_en_fr_ga | "ga-x-icu" | up to date - icuidx10_d_en_fr_ga_es | "es-x-icu" | up to date - icuidx11_d_es | "es-x-icu" | up to date - icuidx12_custom | custom | up to date - icuidx13_custom | custom | up to date - icuidx15_myrange_en_fr_ga | "en-x-icu" | up to date - icuidx15_myrange_en_fr_ga | "fr-x-icu" | up to date - icuidx15_myrange_en_fr_ga | "ga-x-icu" | up to date - icuidx17_part | "en-x-icu" | up to date -(38 rows) - --- Validate that REINDEX will update the stored version. -UPDATE pg_depend SET refobjversion = 'not a version' -WHERE refclassid = 'pg_collation'::regclass -AND objid::regclass::text LIKE 'icuidx%' -AND refobjversion IS NOT NULL; -REINDEX TABLE collate_test; -REINDEX TABLE collate_part_0; -REINDEX TABLE collate_part_1; -SELECT objid::regclass FROM pg_depend WHERE refobjversion = 'not a version'; - objid -------- -(0 rows) - --- Validate that REINDEX CONCURRENTLY will update the stored version. -UPDATE pg_depend SET refobjversion = 'not a version' -WHERE refclassid = 'pg_collation'::regclass -AND objid::regclass::text LIKE 'icuidx%' -AND refobjversion IS NOT NULL; -REINDEX TABLE CONCURRENTLY collate_test; -REINDEX TABLE CONCURRENTLY collate_part_0; -REINDEX INDEX CONCURRENTLY icuidx17_part; -SELECT objid::regclass FROM pg_depend WHERE refobjversion = 'not a version'; - objid -------- -(0 rows) - --- Validate that VACUUM FULL will update the stored version. -UPDATE pg_depend SET refobjversion = 'not a version' -WHERE refclassid = 'pg_collation'::regclass -AND objid::regclass::text LIKE 'icuidx%' -AND refobjversion IS NOT NULL; -VACUUM FULL collate_test; -VACUUM FULL collate_part_0; -VACUUM FULL collate_part_1; -SELECT objid::regclass FROM pg_depend WHERE refobjversion = 'not a version'; - objid -------- -(0 rows) - --- Test ALTER INDEX name ALTER COLLATION name REFRESH VERSION -UPDATE pg_depend SET refobjversion = 'not a version' -WHERE refclassid = 'pg_collation'::regclass -AND objid::regclass::text = 'icuidx17_part' -AND refobjversion IS NOT NULL; -SELECT objid::regclass FROM pg_depend WHERE refobjversion = 'not a version'; - objid ---------------- - icuidx17_part -(1 row) - -ALTER INDEX icuidx17_part ALTER COLLATION "en-x-icu" REFRESH VERSION; -SELECT objid::regclass, refobjversion = 'not a version' AS ver FROM pg_depend -WHERE refclassid = 'pg_collation'::regclass -AND objid::regclass::text = 'icuidx17_part'; - objid | ver ----------------+----- - icuidx17_part | f -(1 row) - -- cleanup RESET search_path; SET client_min_messages TO warning; @@ -2132,17 +1957,3 @@ DROP SCHEMA collate_tests CASCADE; RESET client_min_messages; -- leave a collation for pg_upgrade test CREATE COLLATION coll_icu_upgrade FROM "und-x-icu"; --- Test user-visible function for inspecting versions -SELECT pg_collation_actual_version('"en-x-icu"'::regcollation) is not null; - ?column? ----------- - t -(1 row) - --- Invalid OIDs are silently ignored -SELECT pg_collation_actual_version(0) is null; - ?column? ----------- - t -(1 row) - diff --git a/src/test/regress/expected/collate.linux.utf8.out b/src/test/regress/expected/collate.linux.utf8.out index 580b00eea7..f06ae543e4 100644 --- a/src/test/regress/expected/collate.linux.utf8.out +++ b/src/test/regress/expected/collate.linux.utf8.out @@ -1093,6 +1093,9 @@ SELECT collname FROM pg_collation WHERE collname LIKE 'test%'; DROP SCHEMA test_schema; DROP ROLE regress_test_role; +-- ALTER +ALTER COLLATION "en_US" REFRESH VERSION; +NOTICE: version has not changed -- dependencies CREATE COLLATION test0 FROM "C"; CREATE TABLE collate_dep_test1 (a int, b text COLLATE test0); diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index 7f8f91b92c..49f2a158c1 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -2026,10 +2026,10 @@ REINDEX TABLE concur_reindex_tab; -- notice NOTICE: table "concur_reindex_tab" has no indexes to reindex REINDEX (CONCURRENTLY) TABLE concur_reindex_tab; -- notice NOTICE: table "concur_reindex_tab" has no indexes that can be reindexed concurrently -ALTER TABLE concur_reindex_tab ADD COLUMN c2 text COLLATE "C"; -- add toast index +ALTER TABLE concur_reindex_tab ADD COLUMN c2 text; -- add toast index -- Normal index with integer column CREATE UNIQUE INDEX concur_reindex_ind1 ON concur_reindex_tab(c1); --- Normal index with text column (with unversioned collation) +-- Normal index with text column CREATE INDEX concur_reindex_ind2 ON concur_reindex_tab(c2); -- UNIQUE index with expression CREATE UNIQUE INDEX concur_reindex_ind3 ON concur_reindex_tab(abs(c1)); @@ -2483,7 +2483,7 @@ WARNING: cannot reindex system catalogs concurrently, skipping all Column | Type | Collation | Nullable | Default --------+---------+-----------+----------+--------- c1 | integer | | not null | - c2 | text | C | | + c2 | text | | | Indexes: "concur_reindex_ind1" PRIMARY KEY, btree (c1) "concur_reindex_ind2" btree (c2) diff --git a/src/test/regress/expected/misc_sanity.out b/src/test/regress/expected/misc_sanity.out index 9ebe28a78d..a67f40198a 100644 --- a/src/test/regress/expected/misc_sanity.out +++ b/src/test/regress/expected/misc_sanity.out @@ -18,8 +18,8 @@ WHERE refclassid = 0 OR refobjid = 0 OR deptype NOT IN ('a', 'e', 'i', 'n', 'p') OR (deptype != 'p' AND (classid = 0 OR objid = 0)) OR (deptype = 'p' AND (classid != 0 OR objid != 0 OR objsubid != 0)); - classid | objid | objsubid | refclassid | refobjid | refobjsubid | deptype | refobjversion ----------+-------+----------+------------+----------+-------------+---------+--------------- + classid | objid | objsubid | refclassid | refobjid | refobjsubid | deptype +---------+-------+----------+------------+----------+-------------+--------- (0 rows) -- **************** pg_shdepend **************** diff --git a/src/test/regress/sql/collate.icu.utf8.sql b/src/test/regress/sql/collate.icu.utf8.sql index 4c71f4d249..9cee3d0042 100644 --- a/src/test/regress/sql/collate.icu.utf8.sql +++ b/src/test/regress/sql/collate.icu.utf8.sql @@ -405,6 +405,11 @@ DROP SCHEMA test_schema; DROP ROLE regress_test_role; +-- ALTER + +ALTER COLLATION "en-x-icu" REFRESH VERSION; + + -- dependencies CREATE COLLATION test0 FROM "C"; @@ -742,134 +747,6 @@ INSERT INTO test33 VALUES (2, 'DEF'); -- they end up in the same partition (but it's platform-dependent which one) SELECT (SELECT count(*) FROM test33_0) <> (SELECT count(*) FROM test33_1); --- collation versioning support -CREATE TYPE t_en_fr AS (fr text COLLATE "fr-x-icu", en text COLLATE "en-x-icu"); -CREATE DOMAIN d_en_fr AS t_en_fr; -CREATE DOMAIN d_es AS text COLLATE "es-x-icu"; -CREATE TYPE t_en_fr_ga AS (en_fr t_en_fr, ga text COLLATE "ga-x-icu"); -CREATE DOMAIN d_en_fr_ga AS t_en_fr_ga; -CREATE TYPE t_custom AS (meh text, meh2 text); -CREATE DOMAIN d_custom AS t_custom; - -CREATE COLLATION custom ( - LOCALE = 'fr-x-icu', PROVIDER = 'icu' -); - -CREATE TYPE myrange AS range (subtype = text, collation = "POSIX"); -CREATE TYPE myrange_en_fr_ga AS range(subtype = t_en_fr_ga); - -CREATE TABLE collate_test ( - id integer, - val text COLLATE "fr-x-icu", - t_en_fr t_en_fr, - d_en_fr d_en_fr, - d_es d_es, - t_en_fr_ga t_en_fr_ga, - d_en_fr_ga d_en_fr_ga, - d_en_fr_ga_arr d_en_fr_ga[], - myrange myrange, - myrange_en_fr_ga myrange_en_fr_ga -); - -CREATE INDEX icuidx00_val ON collate_test(val); --- shouldn't get duplicated dependencies -CREATE INDEX icuidx00_val_val ON collate_test(val, val); --- shouldn't track version -CREATE INDEX icuidx00_val_pattern ON collate_test(val text_pattern_ops); --- should have single dependency, no version -CREATE INDEX icuidx00_val_pattern_val_pattern ON collate_test(val text_pattern_ops, val text_pattern_ops); --- should have single dependency, with version -CREATE INDEX icuidx00_val_pattern_val ON collate_test(val text_pattern_ops, val); --- should have single dependency, with version -CREATE INDEX icuidx00_val_val_pattern ON collate_test(val, val text_pattern_ops); --- two rows expected, only one a version, because we don't try to merge these yet -CREATE INDEX icuidx00_val_pattern_where ON collate_test(val text_pattern_ops) WHERE val >= val; --- two rows expected with version, because we don't try to merge these yet -CREATE INDEX icuidx00_val_where ON collate_test(val) WHERE val >= val; --- two rows expected with version (expression walker + attribute) -CREATE INDEX icuidx00_val_pattern_expr ON collate_test(val varchar_pattern_ops, (val || val)); --- two rows expected, one with a version (expression walker + attribute) -CREATE INDEX icuidx00_val_pattern_expr_pattern ON collate_test(val varchar_pattern_ops, (val || val) text_pattern_ops); --- should have single dependency, with version tracked -CREATE INDEX icuidx01_t_en_fr__d_es ON collate_test (t_en_fr, d_es); -CREATE INDEX icuidx02_d_en_fr ON collate_test (d_en_fr); -CREATE INDEX icuidx03_t_en_fr_ga ON collate_test (t_en_fr_ga); -CREATE INDEX icuidx04_d_en_fr_ga ON collate_test (d_en_fr_ga); -CREATE INDEX icuidx05_d_en_fr_ga_arr ON collate_test (d_en_fr_ga_arr); -CREATE INDEX icuidx06_d_en_fr_ga ON collate_test(id) WHERE (d_en_fr_ga).en_fr.fr = 'foo'; -CREATE INDEX icuidx07_d_en_fr_ga ON collate_test(id) WHERE (d_en_fr_ga).ga = 'foo'; -CREATE INDEX icuidx08_d_en_fr_ga ON collate_test(id) WHERE (t_en_fr_ga) = ('foo', 'bar', 'baz'); -CREATE INDEX icuidx09_d_en_fr_ga ON collate_test(id) WHERE (d_en_fr_ga) = ('foo', 'bar', 'baz'); -CREATE INDEX icuidx10_d_en_fr_ga_es ON collate_test(id) WHERE (d_en_fr_ga) = ('foo', 'bar', 'baz' COLLATE "es-x-icu"); -CREATE INDEX icuidx11_d_es ON collate_test(id) WHERE (d_es) = ('foo'); -CREATE INDEX icuidx12_custom ON collate_test(id) WHERE ('foo', 'bar')::d_custom = ('foo', 'bar' COLLATE custom)::d_custom; -CREATE INDEX icuidx13_custom ON collate_test(id) WHERE ('foo' COLLATE custom, 'bar')::d_custom = ('foo', 'bar')::d_custom; -CREATE INDEX icuidx14_myrange ON collate_test(myrange); -CREATE INDEX icuidx15_myrange_en_fr_ga ON collate_test USING gist (myrange_en_fr_ga); - -CREATE TABLE collate_part(id integer, val text COLLATE "en-x-icu") PARTITION BY range(id); -CREATE TABLE collate_part_0 PARTITION OF collate_part FOR VALUES FROM (0) TO (1); -CREATE TABLE collate_part_1 PARTITION OF collate_part FOR VALUES FROM (1) TO (1000000); -CREATE INDEX icuidx17_part ON collate_part_1 (val); - -SELECT objid::regclass::text collate "C", refobjid::regcollation::text collate "C", -CASE -WHEN refobjid = 'default'::regcollation THEN 'XXX' -- depends on libc version support -WHEN refobjversion IS NULL THEN 'version not tracked' -WHEN refobjversion = pg_collation_actual_version(refobjid) THEN 'up to date' -ELSE 'out of date' -END AS version -FROM pg_depend d -LEFT JOIN pg_class c ON c.oid = d.objid -WHERE refclassid = 'pg_collation'::regclass -AND coalesce(relkind, 'i') = 'i' -AND relname LIKE 'icuidx%' -ORDER BY 1, 2, 3; - --- Validate that REINDEX will update the stored version. -UPDATE pg_depend SET refobjversion = 'not a version' -WHERE refclassid = 'pg_collation'::regclass -AND objid::regclass::text LIKE 'icuidx%' -AND refobjversion IS NOT NULL; - -REINDEX TABLE collate_test; -REINDEX TABLE collate_part_0; -REINDEX TABLE collate_part_1; - -SELECT objid::regclass FROM pg_depend WHERE refobjversion = 'not a version'; - --- Validate that REINDEX CONCURRENTLY will update the stored version. -UPDATE pg_depend SET refobjversion = 'not a version' -WHERE refclassid = 'pg_collation'::regclass -AND objid::regclass::text LIKE 'icuidx%' -AND refobjversion IS NOT NULL; -REINDEX TABLE CONCURRENTLY collate_test; -REINDEX TABLE CONCURRENTLY collate_part_0; -REINDEX INDEX CONCURRENTLY icuidx17_part; - -SELECT objid::regclass FROM pg_depend WHERE refobjversion = 'not a version'; - --- Validate that VACUUM FULL will update the stored version. -UPDATE pg_depend SET refobjversion = 'not a version' -WHERE refclassid = 'pg_collation'::regclass -AND objid::regclass::text LIKE 'icuidx%' -AND refobjversion IS NOT NULL; -VACUUM FULL collate_test; -VACUUM FULL collate_part_0; -VACUUM FULL collate_part_1; - -SELECT objid::regclass FROM pg_depend WHERE refobjversion = 'not a version'; - --- Test ALTER INDEX name ALTER COLLATION name REFRESH VERSION -UPDATE pg_depend SET refobjversion = 'not a version' -WHERE refclassid = 'pg_collation'::regclass -AND objid::regclass::text = 'icuidx17_part' -AND refobjversion IS NOT NULL; -SELECT objid::regclass FROM pg_depend WHERE refobjversion = 'not a version'; -ALTER INDEX icuidx17_part ALTER COLLATION "en-x-icu" REFRESH VERSION; -SELECT objid::regclass, refobjversion = 'not a version' AS ver FROM pg_depend -WHERE refclassid = 'pg_collation'::regclass -AND objid::regclass::text = 'icuidx17_part'; -- cleanup RESET search_path; @@ -879,8 +756,3 @@ RESET client_min_messages; -- leave a collation for pg_upgrade test CREATE COLLATION coll_icu_upgrade FROM "und-x-icu"; - --- Test user-visible function for inspecting versions -SELECT pg_collation_actual_version('"en-x-icu"'::regcollation) is not null; --- Invalid OIDs are silently ignored -SELECT pg_collation_actual_version(0) is null; diff --git a/src/test/regress/sql/collate.linux.utf8.sql b/src/test/regress/sql/collate.linux.utf8.sql index c697c99488..cbbd2203e4 100644 --- a/src/test/regress/sql/collate.linux.utf8.sql +++ b/src/test/regress/sql/collate.linux.utf8.sql @@ -406,6 +406,11 @@ DROP SCHEMA test_schema; DROP ROLE regress_test_role; +-- ALTER + +ALTER COLLATION "en_US" REFRESH VERSION; + + -- dependencies CREATE COLLATION test0 FROM "C"; diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql index 51c9a12151..8bc76f7c6f 100644 --- a/src/test/regress/sql/create_index.sql +++ b/src/test/regress/sql/create_index.sql @@ -797,10 +797,10 @@ CREATE TABLE concur_reindex_tab (c1 int); -- REINDEX REINDEX TABLE concur_reindex_tab; -- notice REINDEX (CONCURRENTLY) TABLE concur_reindex_tab; -- notice -ALTER TABLE concur_reindex_tab ADD COLUMN c2 text COLLATE "C"; -- add toast index +ALTER TABLE concur_reindex_tab ADD COLUMN c2 text; -- add toast index -- Normal index with integer column CREATE UNIQUE INDEX concur_reindex_ind1 ON concur_reindex_tab(c1); --- Normal index with text column (with unversioned collation) +-- Normal index with text column CREATE INDEX concur_reindex_ind2 ON concur_reindex_tab(c2); -- UNIQUE index with expression CREATE UNIQUE INDEX concur_reindex_ind3 ON concur_reindex_tab(abs(c1)); diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 878b67a276..0f197a9c8d 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -2948,8 +2948,6 @@ dlist_head dlist_iter dlist_mutable_iter dlist_node -do_collation_version_check_context -do_collation_version_update_context ds_state dsa_area dsa_area_control