Revert per-index collation version tracking feature.

Design problems were discovered in the handling of composite types and
record types that would cause some relevant versions not to be recorded.
Misgivings were also expressed about the use of the pg_depend catalog
for this purpose.  We're out of time for this release so we'll revert
and try again.

Commits reverted:

1bf946bd: Doc: Document known problem with Windows collation versions.
cf002008: Remove no-longer-relevant test case.
ef387bed: Fix bogus collation-version-recording logic.
0fb0a050: Hide internal error for pg_collation_actual_version(<bad OID>).
ff942057: Suppress "warning: variable 'collcollate' set but not used".
d50e3b1f: Fix assertion in collation version lookup.
f24b1569: Rethink extraction of collation dependencies.
257836a7: Track collation versions for indexes.
cd6f479e: Add pg_depend.refobjversion.
7d1297df: Remove pg_collation.collversion.

Discussion: https://postgr.es/m/CA%2BhUKGLhj5t1fcjqAu8iD9B3ixJtsTNqyCCD4V0aTO9kAKAjjA%40mail.gmail.com
This commit is contained in:
Thomas Munro 2021-05-07 20:17:42 +12:00
parent a288d94c91
commit ec48314708
55 changed files with 463 additions and 1354 deletions

View File

@ -2374,6 +2374,17 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
<symbol>LC_CTYPE</symbol> for this collation object
</para></entry>
</row>
<row>
<entry role="catalog_table_entry"><para role="column_definition">
<structfield>collversion</structfield> <type>text</type>
</para>
<para>
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.
</para></entry>
</row>
</tbody>
</tgroup>
</table>
@ -3317,18 +3328,6 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
A code defining the specific semantics of this dependency relationship; see text
</para></entry>
</row>
<row>
<entry role="catalog_table_entry"><para role="column_definition">
<structfield>refobjversion</structfield> <type>text</type>
</para>
<para>
An optional version for the referenced object. Currently used for
indexes' collations (see <xref linkend="collation-versions"/>).
</para>
</entry>
</row>
</tbody>
</tgroup>
</table>

View File

@ -948,54 +948,6 @@ CREATE COLLATION ignore_accents (provider = icu, locale = 'und-u-ks-level1-kc-tr
</tip>
</sect3>
</sect2>
<sect2 id="collation-versions">
<title>Collation Versions</title>
<para>
The sort order defined by a collation is not necessarily fixed over time.
<productname>PostgreSQL</productname> 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.
<productname>PostgreSQL</productname> defends against this by recording the
current version of each referenced collation for any index that depends on
it in the
<link linkend="catalog-pg-depend"><structname>pg_depend</structname></link>
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
<xref linkend="sql-reindex"/> command or the
<xref linkend="sql-alterindex"/> command is used to update the version.
</para>
<para>
Version information is available from the
<literal>icu</literal> provider on all operating systems. For the
<literal>libc</literal> provider, versions are currently only available
on systems using the GNU C library (most Linux systems), FreeBSD and
Windows.
</para>
<note>
<para>
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.
</para>
<para>
When using Windows collations, version information is only available for
collations defined with BCP 47 language tags such as
<literal>en-US</literal>. Currently, <command>initdb</command> selects
a default locale using a traditional Windows language and country
string such as <literal>English_United States.1252</literal>. The
<literal>--lc-collate</literal> option can be used to provide an explicit
locale name in BCP 47 format.
</para>
</note>
</sect2>
</sect1>
<sect1 id="multibyte">

View File

@ -26547,9 +26547,11 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
</para>
<para>
Returns the actual version of the collation object as it is currently
installed in the operating system. <literal>null</literal> is returned
on operating systems where <productname>PostgreSQL</productname>
doesn't have support for versions.
installed in the operating system. If this is different from the
value in
<structname>pg_collation</structname>.<structfield>collversion</structfield>,
then objects depending on the collation might need to be rebuilt. See
also <xref linkend="sql-altercollation"/>.
</para></entry>
</row>

View File

@ -21,6 +21,8 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
ALTER COLLATION <replaceable>name</replaceable> REFRESH VERSION
ALTER COLLATION <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable>
ALTER COLLATION <replaceable>name</replaceable> OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_ROLE | CURRENT_USER | SESSION_USER }
ALTER COLLATION <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
@ -86,9 +88,70 @@ ALTER COLLATION <replaceable>name</replaceable> SET SCHEMA <replaceable>new_sche
</listitem>
</varlistentry>
<varlistentry>
<term><literal>REFRESH VERSION</literal></term>
<listitem>
<para>
Update the collation's version.
See <xref linkend="sql-altercollation-notes"/> below.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id="sql-altercollation-notes" xreflabel="Notes">
<title>Notes</title>
<para>
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:
<screen>
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.
</screen>
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 <command>pg_upgrade</command> 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 <command>REINDEX</command>. When that is done, the collation version
can be refreshed using the command <literal>ALTER COLLATION ... REFRESH
VERSION</literal>. 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.
</para>
<para>
When using collations provided by <literal>libc</literal> and
<productname>PostgreSQL</productname> 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.
</para>
<para>
Currently, there is no version tracking for the database default collation.
</para>
<para>
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:
<programlisting><![CDATA[
SELECT pg_describe_object(refclassid, refobjid, refobjsubid) AS "Collation",
pg_describe_object(classid, objid, objsubid) AS "Object"
FROM pg_depend d JOIN pg_collation c
ON refclassid = 'pg_collation'::regclass AND refobjid = c.oid
WHERE c.collversion <> pg_collation_actual_version(c.oid)
ORDER BY 1, 2;
]]></programlisting></para>
</refsect1>
<refsect1>
<title>Examples</title>

View File

@ -25,7 +25,6 @@ ALTER INDEX [ IF EXISTS ] <replaceable class="parameter">name</replaceable> RENA
ALTER INDEX [ IF EXISTS ] <replaceable class="parameter">name</replaceable> SET TABLESPACE <replaceable class="parameter">tablespace_name</replaceable>
ALTER INDEX <replaceable class="parameter">name</replaceable> ATTACH PARTITION <replaceable class="parameter">index_name</replaceable>
ALTER INDEX <replaceable class="parameter">name</replaceable> [ NO ] DEPENDS ON EXTENSION <replaceable class="parameter">extension_name</replaceable>
ALTER INDEX <replaceable class="parameter">name</replaceable> ALTER COLLATION <replaceable class="parameter">collation_name</replaceable> REFRESH VERSION
ALTER INDEX [ IF EXISTS ] <replaceable class="parameter">name</replaceable> SET ( <replaceable class="parameter">storage_parameter</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] )
ALTER INDEX [ IF EXISTS ] <replaceable class="parameter">name</replaceable> RESET ( <replaceable class="parameter">storage_parameter</replaceable> [, ... ] )
ALTER INDEX [ IF EXISTS ] <replaceable class="parameter">name</replaceable> ALTER [ COLUMN ] <replaceable class="parameter">column_number</replaceable>
@ -113,20 +112,6 @@ ALTER INDEX ALL IN TABLESPACE <replaceable class="parameter">name</replaceable>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>ALTER COLLATION <replaceable class="parameter">collation_name</replaceable> REFRESH VERSION</literal></term>
<listitem>
<para>
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, <xref linkend="sql-reindex"/> is a safe alternative.
See <xref linkend="collation-versions"/> for more information.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>SET ( <replaceable class="parameter">storage_parameter</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] )</literal></term>
<listitem>

View File

@ -27,6 +27,7 @@ CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> (
[ LC_CTYPE = <replaceable>lc_ctype</replaceable>, ]
[ PROVIDER = <replaceable>provider</replaceable>, ]
[ DETERMINISTIC = <replaceable>boolean</replaceable>, ]
[ VERSION = <replaceable>version</replaceable> ]
)
CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
</synopsis>
@ -148,6 +149,26 @@ CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> FROM <replace
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable>version</replaceable></term>
<listitem>
<para>
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 <command>pg_upgrade</command> for copying the version from an
existing installation.
</para>
<para>
See also <xref linkend="sql-altercollation"/> for how to handle
collation version mismatches.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable>existing_collation</replaceable></term>

View File

@ -215,21 +215,6 @@ PostgreSQL documentation
</listitem>
</varlistentry>
<varlistentry>
<term><option>--index-collation-versions-unknown</option></term>
<listitem>
<para>
When upgrading indexes from releases before 14 that didn't track
collation versions, <application>pg_upgrade</application>
assumes by default that the upgraded indexes are compatible with the
currently installed versions of relevant collations (see
<xref linkend="collation-versions"/>). Specify
<option>--index-collation-versions-unknown</option> to mark
them as needing to be rebuilt instead.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-?</option></term>
<term><option>--help</option></term>

View File

@ -40,15 +40,6 @@ REINDEX [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] { IN
several scenarios in which to use <command>REINDEX</command>:
<itemizedlist>
<listitem>
<para>
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 <xref linkend="collation-versions"/> for
more information.
</para>
</listitem>
<listitem>
<para>
An index has become corrupted, and no longer contains valid

View File

@ -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);
}
/*

View File

@ -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

View File

@ -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);
}
/*

View File

@ -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);

View File

@ -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 */

View File

@ -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++;

View File

@ -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
*

View File

@ -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))
{

View File

@ -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

View File

@ -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.
*/

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -263,7 +263,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
}
%type <node> stmt toplevel_stmt schema_stmt routine_body_stmt
AlterEventTrigStmt
AlterEventTrigStmt AlterCollationStmt
AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt
AlterFdwStmt AlterForeignServerStmt AlterGroupStmt
AlterObjectDependsStmt AlterObjectSchemaStmt AlterOwnerStmt
@ -902,6 +902,7 @@ toplevel_stmt:
stmt:
AlterEventTrigStmt
| AlterCollationStmt
| AlterDatabaseStmt
| AlterDatabaseSetStmt
| AlterDefaultPrivilegesStmt
@ -2682,14 +2683,6 @@ alter_table_cmd:
n->subtype = AT_NoForceRowSecurity;
$$ = (Node *)n;
}
/* ALTER INDEX <name> ALTER COLLATION ... REFRESH VERSION */
| ALTER COLLATION any_name REFRESH VERSION_P
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_AlterCollationRefreshVersion;
n->object = $3;
$$ = (Node *)n;
}
| alter_generic_options
{
AlterTableCmd *n = makeNode(AlterTableCmd);
@ -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

View File

@ -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:
{

View File

@ -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
/*

View File

@ -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"

View File

@ -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;

View File

@ -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;
/*

View File

@ -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.
*

View File

@ -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 */

View File

@ -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);

View File

@ -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"

View File

@ -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

View File

@ -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 <name> ALTER */
else if (Matches("ALTER", "INDEX", MatchAny, "ALTER"))
COMPLETE_WITH("COLLATION", "COLUMN");
COMPLETE_WITH("COLUMN");
/* ALTER INDEX <name> 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 <name> 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 <name> ALTER COLLATION <name> */
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 <name> */
else if (Matches("ALTER", "LANGUAGE", MatchAny))

View File

@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 202104271
#define CATALOG_VERSION_NO 202105051
#endif

View File

@ -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);

View File

@ -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,

View File

@ -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);

View File

@ -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));

View File

@ -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);

View File

@ -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 */

View File

@ -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
*

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -1,2 +1 @@
/test-ctype
/tmp_check/

View File

@ -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)

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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 ****************

View File

@ -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;

View File

@ -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";

View File

@ -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));

View File

@ -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