mirror of
https://github.com/postgres/postgres.git
synced 2025-06-29 10:41:53 +03:00
Per-column collation support
This adds collation support for columns and domains, a COLLATE clause to override it per expression, and B-tree index support. Peter Eisentraut reviewed by Pavel Stehule, Itagaki Takahiro, Robert Haas, Noah Misch
This commit is contained in:
@ -23,6 +23,7 @@
|
||||
#include "catalog/dependency.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/pg_authid.h"
|
||||
#include "catalog/pg_collation.h"
|
||||
#include "catalog/pg_constraint.h"
|
||||
#include "catalog/pg_depend.h"
|
||||
#include "catalog/pg_language.h"
|
||||
@ -233,7 +234,7 @@ static void get_from_clause_item(Node *jtnode, Query *query,
|
||||
deparse_context *context);
|
||||
static void get_from_clause_alias(Alias *alias, RangeTblEntry *rte,
|
||||
deparse_context *context);
|
||||
static void get_from_clause_coldeflist(List *names, List *types, List *typmods,
|
||||
static void get_from_clause_coldeflist(List *names, List *types, List *typmods, List *collations,
|
||||
deparse_context *context);
|
||||
static void get_opclass_name(Oid opclass, Oid actual_datatype,
|
||||
StringInfo buf);
|
||||
@ -788,9 +789,11 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
|
||||
Oid indrelid;
|
||||
int keyno;
|
||||
Oid keycoltype;
|
||||
Datum indcollDatum;
|
||||
Datum indclassDatum;
|
||||
Datum indoptionDatum;
|
||||
bool isnull;
|
||||
oidvector *indcollation;
|
||||
oidvector *indclass;
|
||||
int2vector *indoption;
|
||||
StringInfoData buf;
|
||||
@ -808,11 +811,17 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
|
||||
indrelid = idxrec->indrelid;
|
||||
Assert(indexrelid == idxrec->indexrelid);
|
||||
|
||||
/* Must get indclass and indoption the hard way */
|
||||
/* Must get indcollation, indclass, and indoption the hard way */
|
||||
indcollDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
|
||||
Anum_pg_index_indcollation, &isnull);
|
||||
Assert(!isnull);
|
||||
indcollation = (oidvector *) DatumGetPointer(indcollDatum);
|
||||
|
||||
indclassDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
|
||||
Anum_pg_index_indclass, &isnull);
|
||||
Assert(!isnull);
|
||||
indclass = (oidvector *) DatumGetPointer(indclassDatum);
|
||||
|
||||
indoptionDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
|
||||
Anum_pg_index_indoption, &isnull);
|
||||
Assert(!isnull);
|
||||
@ -928,6 +937,13 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
|
||||
|
||||
if (!attrsOnly && (!colno || colno == keyno + 1))
|
||||
{
|
||||
Oid coll;
|
||||
|
||||
/* Add collation, if not default */
|
||||
coll = indcollation->values[keyno];
|
||||
if (coll && coll != DEFAULT_COLLATION_OID && coll != get_attcollation(indrelid, attnum))
|
||||
appendStringInfo(&buf, " COLLATE %s", generate_collation_name((indcollation->values[keyno])));
|
||||
|
||||
/* Add the operator class name, if not default */
|
||||
get_opclass_name(indclass->values[keyno], keycoltype, &buf);
|
||||
|
||||
@ -5054,6 +5070,20 @@ get_rule_expr(Node *node, deparse_context *context,
|
||||
}
|
||||
break;
|
||||
|
||||
case T_CollateClause:
|
||||
{
|
||||
CollateClause *collate = (CollateClause *) node;
|
||||
Node *arg = (Node *) collate->arg;
|
||||
|
||||
if (!PRETTY_PAREN(context))
|
||||
appendStringInfoChar(buf, '(');
|
||||
get_rule_expr_paren(arg, context, false, node);
|
||||
appendStringInfo(buf, " COLLATE %s", generate_collation_name(collate->collOid));
|
||||
if (!PRETTY_PAREN(context))
|
||||
appendStringInfoChar(buf, ')');
|
||||
}
|
||||
break;
|
||||
|
||||
case T_CoerceViaIO:
|
||||
{
|
||||
CoerceViaIO *iocoerce = (CoerceViaIO *) node;
|
||||
@ -6345,6 +6375,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
|
||||
get_from_clause_coldeflist(rte->eref->colnames,
|
||||
rte->funccoltypes,
|
||||
rte->funccoltypmods,
|
||||
rte->funccolcollations,
|
||||
context);
|
||||
}
|
||||
else
|
||||
@ -6543,35 +6574,42 @@ get_from_clause_alias(Alias *alias, RangeTblEntry *rte,
|
||||
* responsible for ensuring that an alias or AS is present before it.
|
||||
*/
|
||||
static void
|
||||
get_from_clause_coldeflist(List *names, List *types, List *typmods,
|
||||
get_from_clause_coldeflist(List *names, List *types, List *typmods, List *collations,
|
||||
deparse_context *context)
|
||||
{
|
||||
StringInfo buf = context->buf;
|
||||
ListCell *l1;
|
||||
ListCell *l2;
|
||||
ListCell *l3;
|
||||
ListCell *l4;
|
||||
int i = 0;
|
||||
|
||||
appendStringInfoChar(buf, '(');
|
||||
|
||||
l2 = list_head(types);
|
||||
l3 = list_head(typmods);
|
||||
l4 = list_head(collations);
|
||||
foreach(l1, names)
|
||||
{
|
||||
char *attname = strVal(lfirst(l1));
|
||||
Oid atttypid;
|
||||
int32 atttypmod;
|
||||
Oid attcollation;
|
||||
|
||||
atttypid = lfirst_oid(l2);
|
||||
l2 = lnext(l2);
|
||||
atttypmod = lfirst_int(l3);
|
||||
l3 = lnext(l3);
|
||||
attcollation = lfirst_oid(l4);
|
||||
l4 = lnext(l4);
|
||||
|
||||
if (i > 0)
|
||||
appendStringInfo(buf, ", ");
|
||||
appendStringInfo(buf, "%s %s",
|
||||
quote_identifier(attname),
|
||||
format_type_with_typemod(atttypid, atttypmod));
|
||||
if (attcollation && attcollation != DEFAULT_COLLATION_OID)
|
||||
appendStringInfo(buf, " COLLATE %s", generate_collation_name(attcollation));
|
||||
i++;
|
||||
}
|
||||
|
||||
@ -7038,6 +7076,39 @@ generate_operator_name(Oid operid, Oid arg1, Oid arg2)
|
||||
return buf.data;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate_collation_name
|
||||
* Compute the name to display for a collation specified by OID
|
||||
*
|
||||
* The result includes all necessary quoting and schema-prefixing.
|
||||
*/
|
||||
char *
|
||||
generate_collation_name(Oid collid)
|
||||
{
|
||||
HeapTuple tp;
|
||||
Form_pg_collation colltup;
|
||||
char *collname;
|
||||
char *nspname;
|
||||
char *result;
|
||||
|
||||
tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
|
||||
if (!HeapTupleIsValid(tp))
|
||||
elog(ERROR, "cache lookup failed for collation %u", collid);
|
||||
colltup = (Form_pg_collation) GETSTRUCT(tp);
|
||||
collname = NameStr(colltup->collname);
|
||||
|
||||
if (!CollationIsVisible(collid))
|
||||
nspname = get_namespace_name(colltup->collnamespace);
|
||||
else
|
||||
nspname = NULL;
|
||||
|
||||
result = quote_qualified_identifier(nspname, collname);
|
||||
|
||||
ReleaseSysCache(tp);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a C string, produce a TEXT datum.
|
||||
*
|
||||
|
Reference in New Issue
Block a user