mirror of
https://github.com/postgres/postgres.git
synced 2025-10-25 13:17:41 +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:
@@ -862,11 +862,13 @@ examine_attribute(Relation onerel, int attnum, Node *index_expr)
|
||||
{
|
||||
stats->attrtypid = exprType(index_expr);
|
||||
stats->attrtypmod = exprTypmod(index_expr);
|
||||
stats->attrcollation = exprCollation(index_expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
stats->attrtypid = attr->atttypid;
|
||||
stats->attrtypmod = attr->atttypmod;
|
||||
stats->attrcollation = attr->attcollation;
|
||||
}
|
||||
|
||||
typtuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(stats->attrtypid));
|
||||
@@ -1929,6 +1931,7 @@ compute_minimal_stats(VacAttrStatsP stats,
|
||||
track_cnt = 0;
|
||||
|
||||
fmgr_info(mystats->eqfunc, &f_cmpeq);
|
||||
fmgr_info_collation(stats->attrcollation, &f_cmpeq);
|
||||
|
||||
for (i = 0; i < samplerows; i++)
|
||||
{
|
||||
@@ -2250,6 +2253,7 @@ compute_scalar_stats(VacAttrStatsP stats,
|
||||
|
||||
SelectSortFunction(mystats->ltopr, false, &cmpFn, &cmpFlags);
|
||||
fmgr_info(cmpFn, &f_cmpfn);
|
||||
fmgr_info_collation(stats->attrcollation, &f_cmpfn);
|
||||
|
||||
/* Initial scan to find sortable values */
|
||||
for (i = 0; i < samplerows; i++)
|
||||
|
||||
@@ -356,8 +356,8 @@ createdb(const CreatedbStmt *stmt)
|
||||
*
|
||||
* Note: if you change this policy, fix initdb to match.
|
||||
*/
|
||||
ctype_encoding = pg_get_encoding_from_locale(dbctype);
|
||||
collate_encoding = pg_get_encoding_from_locale(dbcollate);
|
||||
ctype_encoding = pg_get_encoding_from_locale(dbctype, true);
|
||||
collate_encoding = pg_get_encoding_from_locale(dbcollate, true);
|
||||
|
||||
if (!(ctype_encoding == encoding ||
|
||||
ctype_encoding == PG_SQL_ASCII ||
|
||||
|
||||
@@ -87,7 +87,7 @@ compute_return_type(TypeName *returnType, Oid languageOid,
|
||||
Oid rettype;
|
||||
Type typtup;
|
||||
|
||||
typtup = LookupTypeName(NULL, returnType, NULL);
|
||||
typtup = LookupTypeName(NULL, returnType, NULL, NULL);
|
||||
|
||||
if (typtup)
|
||||
{
|
||||
@@ -207,7 +207,7 @@ examine_parameter_list(List *parameters, Oid languageOid,
|
||||
Oid toid;
|
||||
Type typtup;
|
||||
|
||||
typtup = LookupTypeName(NULL, t, NULL);
|
||||
typtup = LookupTypeName(NULL, t, NULL, NULL);
|
||||
if (typtup)
|
||||
{
|
||||
if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
/* non-export function prototypes */
|
||||
static void CheckPredicate(Expr *predicate);
|
||||
static void ComputeIndexAttrs(IndexInfo *indexInfo,
|
||||
Oid *collationOidP,
|
||||
Oid *classOidP,
|
||||
int16 *colOptionP,
|
||||
List *attList,
|
||||
@@ -124,6 +125,7 @@ DefineIndex(RangeVar *heapRelation,
|
||||
bool quiet,
|
||||
bool concurrent)
|
||||
{
|
||||
Oid *collationObjectId;
|
||||
Oid *classObjectId;
|
||||
Oid accessMethodId;
|
||||
Oid relationId;
|
||||
@@ -345,9 +347,10 @@ DefineIndex(RangeVar *heapRelation,
|
||||
indexInfo->ii_Concurrent = concurrent;
|
||||
indexInfo->ii_BrokenHotChain = false;
|
||||
|
||||
collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
|
||||
classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
|
||||
coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
|
||||
ComputeIndexAttrs(indexInfo, classObjectId, coloptions, attributeList,
|
||||
ComputeIndexAttrs(indexInfo, collationObjectId, classObjectId, coloptions, attributeList,
|
||||
exclusionOpNames, relationId,
|
||||
accessMethodName, accessMethodId,
|
||||
amcanorder, isconstraint);
|
||||
@@ -392,7 +395,7 @@ DefineIndex(RangeVar *heapRelation,
|
||||
indexRelationId =
|
||||
index_create(rel, indexRelationName, indexRelationId,
|
||||
indexInfo, indexColNames,
|
||||
accessMethodId, tablespaceId, classObjectId,
|
||||
accessMethodId, tablespaceId, collationObjectId, classObjectId,
|
||||
coloptions, reloptions, primary,
|
||||
isconstraint, deferrable, initdeferred,
|
||||
allowSystemTableMods,
|
||||
@@ -764,6 +767,7 @@ CheckPredicate(Expr *predicate)
|
||||
*/
|
||||
static void
|
||||
ComputeIndexAttrs(IndexInfo *indexInfo,
|
||||
Oid *collationOidP,
|
||||
Oid *classOidP,
|
||||
int16 *colOptionP,
|
||||
List *attList, /* list of IndexElem's */
|
||||
@@ -800,6 +804,7 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
|
||||
{
|
||||
IndexElem *attribute = (IndexElem *) lfirst(lc);
|
||||
Oid atttype;
|
||||
Oid attcollation;
|
||||
|
||||
/*
|
||||
* Process the column-or-expression to be indexed.
|
||||
@@ -829,6 +834,7 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
|
||||
attform = (Form_pg_attribute) GETSTRUCT(atttuple);
|
||||
indexInfo->ii_KeyAttrNumbers[attn] = attform->attnum;
|
||||
atttype = attform->atttypid;
|
||||
attcollation = attform->attcollation;
|
||||
ReleaseSysCache(atttuple);
|
||||
}
|
||||
else if (attribute->expr && IsA(attribute->expr, Var) &&
|
||||
@@ -839,6 +845,7 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
|
||||
|
||||
indexInfo->ii_KeyAttrNumbers[attn] = var->varattno;
|
||||
atttype = get_atttype(relId, var->varattno);
|
||||
attcollation = var->varcollid;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -848,6 +855,7 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
|
||||
indexInfo->ii_Expressions = lappend(indexInfo->ii_Expressions,
|
||||
attribute->expr);
|
||||
atttype = exprType(attribute->expr);
|
||||
attcollation = exprCollation(attribute->expr);
|
||||
|
||||
/*
|
||||
* We don't currently support generation of an actual query plan
|
||||
@@ -874,6 +882,20 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
|
||||
errmsg("functions in index expression must be marked IMMUTABLE")));
|
||||
}
|
||||
|
||||
/*
|
||||
* Collation override
|
||||
*/
|
||||
if (attribute->collation)
|
||||
{
|
||||
if (!type_is_collatable(atttype))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("collations are not supported by type %s",
|
||||
format_type_be(atttype))));
|
||||
attcollation = get_collation_oid(attribute->collation, false);
|
||||
}
|
||||
collationOidP[attn] = attcollation;
|
||||
|
||||
/*
|
||||
* Identify the opclass to use.
|
||||
*/
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "catalog/catalog.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_collation.h"
|
||||
#include "catalog/pg_seclabel.h"
|
||||
#include "commands/seclabel.h"
|
||||
#include "miscadmin.h"
|
||||
@@ -194,6 +195,7 @@ GetSecurityLabel(const ObjectAddress *object, const char *provider)
|
||||
Anum_pg_seclabel_provider,
|
||||
BTEqualStrategyNumber, F_TEXTEQ,
|
||||
CStringGetTextDatum(provider));
|
||||
ScanKeyEntryInitializeCollation(&keys[3], DEFAULT_COLLATION_OID);
|
||||
|
||||
pg_seclabel = heap_open(SecLabelRelationId, AccessShareLock);
|
||||
|
||||
@@ -263,6 +265,7 @@ SetSecurityLabel(const ObjectAddress *object,
|
||||
Anum_pg_seclabel_provider,
|
||||
BTEqualStrategyNumber, F_TEXTEQ,
|
||||
CStringGetTextDatum(provider));
|
||||
ScanKeyEntryInitializeCollation(&keys[3], DEFAULT_COLLATION_OID);
|
||||
|
||||
pg_seclabel = heap_open(SecLabelRelationId, RowExclusiveLock);
|
||||
|
||||
|
||||
@@ -143,53 +143,53 @@ DefineSequence(CreateSeqStmt *seq)
|
||||
switch (i)
|
||||
{
|
||||
case SEQ_COL_NAME:
|
||||
coldef->typeName = makeTypeNameFromOid(NAMEOID, -1);
|
||||
coldef->typeName = makeTypeNameFromOid(NAMEOID, -1, InvalidOid);
|
||||
coldef->colname = "sequence_name";
|
||||
namestrcpy(&name, seq->sequence->relname);
|
||||
value[i - 1] = NameGetDatum(&name);
|
||||
break;
|
||||
case SEQ_COL_LASTVAL:
|
||||
coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
|
||||
coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid);
|
||||
coldef->colname = "last_value";
|
||||
value[i - 1] = Int64GetDatumFast(new.last_value);
|
||||
break;
|
||||
case SEQ_COL_STARTVAL:
|
||||
coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
|
||||
coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid);
|
||||
coldef->colname = "start_value";
|
||||
value[i - 1] = Int64GetDatumFast(new.start_value);
|
||||
break;
|
||||
case SEQ_COL_INCBY:
|
||||
coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
|
||||
coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid);
|
||||
coldef->colname = "increment_by";
|
||||
value[i - 1] = Int64GetDatumFast(new.increment_by);
|
||||
break;
|
||||
case SEQ_COL_MAXVALUE:
|
||||
coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
|
||||
coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid);
|
||||
coldef->colname = "max_value";
|
||||
value[i - 1] = Int64GetDatumFast(new.max_value);
|
||||
break;
|
||||
case SEQ_COL_MINVALUE:
|
||||
coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
|
||||
coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid);
|
||||
coldef->colname = "min_value";
|
||||
value[i - 1] = Int64GetDatumFast(new.min_value);
|
||||
break;
|
||||
case SEQ_COL_CACHE:
|
||||
coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
|
||||
coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid);
|
||||
coldef->colname = "cache_value";
|
||||
value[i - 1] = Int64GetDatumFast(new.cache_value);
|
||||
break;
|
||||
case SEQ_COL_LOG:
|
||||
coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
|
||||
coldef->typeName = makeTypeNameFromOid(INT8OID, -1, InvalidOid);
|
||||
coldef->colname = "log_cnt";
|
||||
value[i - 1] = Int64GetDatum((int64) 1);
|
||||
break;
|
||||
case SEQ_COL_CYCLE:
|
||||
coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
|
||||
coldef->typeName = makeTypeNameFromOid(BOOLOID, -1, InvalidOid);
|
||||
coldef->colname = "is_cycled";
|
||||
value[i - 1] = BoolGetDatum(new.is_cycled);
|
||||
break;
|
||||
case SEQ_COL_CALLED:
|
||||
coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
|
||||
coldef->typeName = makeTypeNameFromOid(BOOLOID, -1, InvalidOid);
|
||||
coldef->colname = "is_called";
|
||||
value[i - 1] = BoolGetDatum(false);
|
||||
break;
|
||||
|
||||
@@ -1422,6 +1422,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
|
||||
{
|
||||
Oid defTypeId;
|
||||
int32 deftypmod;
|
||||
Oid defCollId;
|
||||
|
||||
/*
|
||||
* Yes, try to merge the two column definitions. They must
|
||||
@@ -1431,7 +1432,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
|
||||
(errmsg("merging multiple inherited definitions of column \"%s\"",
|
||||
attributeName)));
|
||||
def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
|
||||
typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
|
||||
typenameTypeIdModColl(NULL, def->typeName, &defTypeId, &deftypmod, &defCollId);
|
||||
if (defTypeId != attribute->atttypid ||
|
||||
deftypmod != attribute->atttypmod)
|
||||
ereport(ERROR,
|
||||
@@ -1441,6 +1442,14 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
|
||||
errdetail("%s versus %s",
|
||||
TypeNameToString(def->typeName),
|
||||
format_type_be(attribute->atttypid))));
|
||||
if (defCollId != attribute->attcollation)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_COLLATION_MISMATCH),
|
||||
errmsg("inherited column \"%s\" has a collation conflict",
|
||||
attributeName),
|
||||
errdetail("\"%s\" versus \"%s\"",
|
||||
get_collation_name(defCollId),
|
||||
get_collation_name(attribute->attcollation))));
|
||||
|
||||
/* Copy storage parameter */
|
||||
if (def->storage == 0)
|
||||
@@ -1468,7 +1477,8 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
|
||||
def = makeNode(ColumnDef);
|
||||
def->colname = pstrdup(attributeName);
|
||||
def->typeName = makeTypeNameFromOid(attribute->atttypid,
|
||||
attribute->atttypmod);
|
||||
attribute->atttypmod,
|
||||
attribute->attcollation);
|
||||
def->inhcount = 1;
|
||||
def->is_local = false;
|
||||
def->is_not_null = attribute->attnotnull;
|
||||
@@ -1594,6 +1604,8 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
|
||||
newTypeId;
|
||||
int32 deftypmod,
|
||||
newtypmod;
|
||||
Oid defcollid,
|
||||
newcollid;
|
||||
|
||||
/*
|
||||
* Yes, try to merge the two column definitions. They must
|
||||
@@ -1603,8 +1615,8 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
|
||||
(errmsg("merging column \"%s\" with inherited definition",
|
||||
attributeName)));
|
||||
def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
|
||||
typenameTypeIdAndMod(NULL, def->typeName, &defTypeId, &deftypmod);
|
||||
typenameTypeIdAndMod(NULL, newdef->typeName, &newTypeId, &newtypmod);
|
||||
typenameTypeIdModColl(NULL, def->typeName, &defTypeId, &deftypmod, &defcollid);
|
||||
typenameTypeIdModColl(NULL, newdef->typeName, &newTypeId, &newtypmod, &newcollid);
|
||||
if (defTypeId != newTypeId || deftypmod != newtypmod)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
@@ -1613,6 +1625,14 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
|
||||
errdetail("%s versus %s",
|
||||
TypeNameToString(def->typeName),
|
||||
TypeNameToString(newdef->typeName))));
|
||||
if (defcollid != newcollid)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_COLLATION_MISMATCH),
|
||||
errmsg("column \"%s\" has a collation conflict",
|
||||
attributeName),
|
||||
errdetail("\"%s\" versus \"%s\"",
|
||||
get_collation_name(defcollid),
|
||||
get_collation_name(newcollid))));
|
||||
|
||||
/* Copy storage parameter */
|
||||
if (def->storage == 0)
|
||||
@@ -4065,6 +4085,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
|
||||
HeapTuple typeTuple;
|
||||
Oid typeOid;
|
||||
int32 typmod;
|
||||
Oid collOid;
|
||||
Form_pg_type tform;
|
||||
Expr *defval;
|
||||
|
||||
@@ -4085,15 +4106,24 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
|
||||
Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
|
||||
Oid ctypeId;
|
||||
int32 ctypmod;
|
||||
Oid ccollid;
|
||||
|
||||
/* Child column must match by type */
|
||||
typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
|
||||
typenameTypeIdModColl(NULL, colDef->typeName, &ctypeId, &ctypmod, &ccollid);
|
||||
if (ctypeId != childatt->atttypid ||
|
||||
ctypmod != childatt->atttypmod)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
errmsg("child table \"%s\" has different type for column \"%s\"",
|
||||
RelationGetRelationName(rel), colDef->colname)));
|
||||
if (ccollid != childatt->attcollation)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_COLLATION_MISMATCH),
|
||||
errmsg("child table \"%s\" has different collation for column \"%s\"",
|
||||
RelationGetRelationName(rel), colDef->colname),
|
||||
errdetail("\"%s\" versus \"%s\"",
|
||||
get_collation_name(ccollid),
|
||||
get_collation_name(childatt->attcollation))));
|
||||
|
||||
/* If it's OID, child column must actually be OID */
|
||||
if (isOid && childatt->attnum != ObjectIdAttributeNumber)
|
||||
@@ -4151,7 +4181,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
|
||||
MaxHeapAttributeNumber)));
|
||||
}
|
||||
|
||||
typeTuple = typenameType(NULL, colDef->typeName, &typmod);
|
||||
typeTuple = typenameType(NULL, colDef->typeName, &typmod, &collOid);
|
||||
tform = (Form_pg_type) GETSTRUCT(typeTuple);
|
||||
typeOid = HeapTupleGetOid(typeTuple);
|
||||
|
||||
@@ -4176,6 +4206,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
|
||||
attribute.attisdropped = false;
|
||||
attribute.attislocal = colDef->is_local;
|
||||
attribute.attinhcount = colDef->inhcount;
|
||||
attribute.attcollation = collOid;
|
||||
/* attribute.attacl is handled by InsertPgAttributeTuple */
|
||||
|
||||
ReleaseSysCache(typeTuple);
|
||||
@@ -4353,7 +4384,7 @@ ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOC
|
||||
ColumnDef *cdef = makeNode(ColumnDef);
|
||||
|
||||
cdef->colname = pstrdup("oid");
|
||||
cdef->typeName = makeTypeNameFromOid(OIDOID, -1);
|
||||
cdef->typeName = makeTypeNameFromOid(OIDOID, -1, InvalidOid);
|
||||
cdef->inhcount = 0;
|
||||
cdef->is_local = true;
|
||||
cdef->is_not_null = true;
|
||||
@@ -6415,6 +6446,7 @@ ATPrepAlterColumnType(List **wqueue,
|
||||
AttrNumber attnum;
|
||||
Oid targettype;
|
||||
int32 targettypmod;
|
||||
Oid targetcollid;
|
||||
Node *transform;
|
||||
NewColumnValue *newval;
|
||||
ParseState *pstate = make_parsestate(NULL);
|
||||
@@ -6449,7 +6481,7 @@ ATPrepAlterColumnType(List **wqueue,
|
||||
colName)));
|
||||
|
||||
/* Look up the target type */
|
||||
typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod);
|
||||
typenameTypeIdModColl(NULL, typeName, &targettype, &targettypmod, &targetcollid);
|
||||
|
||||
/* make sure datatype is legal for a column */
|
||||
CheckAttributeType(colName, targettype, false);
|
||||
@@ -6501,7 +6533,7 @@ ATPrepAlterColumnType(List **wqueue,
|
||||
else
|
||||
{
|
||||
transform = (Node *) makeVar(1, attnum,
|
||||
attTup->atttypid, attTup->atttypmod,
|
||||
attTup->atttypid, attTup->atttypmod, attTup->attcollation,
|
||||
0);
|
||||
}
|
||||
|
||||
@@ -6578,6 +6610,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
|
||||
Form_pg_type tform;
|
||||
Oid targettype;
|
||||
int32 targettypmod;
|
||||
Oid targetcollid;
|
||||
Node *defaultexpr;
|
||||
Relation attrelation;
|
||||
Relation depRel;
|
||||
@@ -6606,7 +6639,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
|
||||
colName)));
|
||||
|
||||
/* Look up the target type (should not fail, since prep found it) */
|
||||
typeTuple = typenameType(NULL, typeName, &targettypmod);
|
||||
typeTuple = typenameType(NULL, typeName, &targettypmod, &targetcollid);
|
||||
tform = (Form_pg_type) GETSTRUCT(typeTuple);
|
||||
targettype = HeapTupleGetOid(typeTuple);
|
||||
|
||||
@@ -6880,6 +6913,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
|
||||
*/
|
||||
attTup->atttypid = targettype;
|
||||
attTup->atttypmod = targettypmod;
|
||||
attTup->attcollation = targetcollid;
|
||||
attTup->attndims = list_length(typeName->arrayBounds);
|
||||
attTup->attlen = tform->typlen;
|
||||
attTup->attbyval = tform->typbyval;
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "catalog/dependency.h"
|
||||
#include "catalog/heap.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/pg_collation.h"
|
||||
#include "catalog/pg_constraint.h"
|
||||
#include "catalog/pg_depend.h"
|
||||
#include "catalog/pg_enum.h"
|
||||
@@ -118,6 +119,7 @@ DefineType(List *names, List *parameters)
|
||||
bool byValue = false;
|
||||
char alignment = 'i'; /* default alignment */
|
||||
char storage = 'p'; /* default TOAST storage method */
|
||||
Oid collation = InvalidOid;
|
||||
DefElem *likeTypeEl = NULL;
|
||||
DefElem *internalLengthEl = NULL;
|
||||
DefElem *inputNameEl = NULL;
|
||||
@@ -135,6 +137,7 @@ DefineType(List *names, List *parameters)
|
||||
DefElem *byValueEl = NULL;
|
||||
DefElem *alignmentEl = NULL;
|
||||
DefElem *storageEl = NULL;
|
||||
DefElem *collatableEl = NULL;
|
||||
Oid inputOid;
|
||||
Oid outputOid;
|
||||
Oid receiveOid = InvalidOid;
|
||||
@@ -261,6 +264,8 @@ DefineType(List *names, List *parameters)
|
||||
defelp = &alignmentEl;
|
||||
else if (pg_strcasecmp(defel->defname, "storage") == 0)
|
||||
defelp = &storageEl;
|
||||
else if (pg_strcasecmp(defel->defname, "collatable") == 0)
|
||||
defelp = &collatableEl;
|
||||
else
|
||||
{
|
||||
/* WARNING, not ERROR, for historical backwards-compatibility */
|
||||
@@ -287,7 +292,7 @@ DefineType(List *names, List *parameters)
|
||||
Type likeType;
|
||||
Form_pg_type likeForm;
|
||||
|
||||
likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
|
||||
likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL, NULL);
|
||||
likeForm = (Form_pg_type) GETSTRUCT(likeType);
|
||||
internalLength = likeForm->typlen;
|
||||
byValue = likeForm->typbyval;
|
||||
@@ -390,6 +395,8 @@ DefineType(List *names, List *parameters)
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("storage \"%s\" not recognized", a)));
|
||||
}
|
||||
if (collatableEl)
|
||||
collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
|
||||
|
||||
/*
|
||||
* make sure we have our required definitions
|
||||
@@ -562,7 +569,8 @@ DefineType(List *names, List *parameters)
|
||||
storage, /* TOAST strategy */
|
||||
-1, /* typMod (Domains only) */
|
||||
0, /* Array Dimensions of typbasetype */
|
||||
false); /* Type NOT NULL */
|
||||
false, /* Type NOT NULL */
|
||||
collation);
|
||||
|
||||
/*
|
||||
* Create the array type that goes with it.
|
||||
@@ -601,7 +609,8 @@ DefineType(List *names, List *parameters)
|
||||
'x', /* ARRAY is always toastable */
|
||||
-1, /* typMod (Domains only) */
|
||||
0, /* Array dimensions of typbasetype */
|
||||
false); /* Type NOT NULL */
|
||||
false, /* Type NOT NULL */
|
||||
collation);
|
||||
|
||||
pfree(array_type);
|
||||
}
|
||||
@@ -640,7 +649,7 @@ RemoveTypes(DropStmt *drop)
|
||||
typename = makeTypeNameFromNameList(names);
|
||||
|
||||
/* Use LookupTypeName here so that shell types can be removed. */
|
||||
tup = LookupTypeName(NULL, typename, NULL);
|
||||
tup = LookupTypeName(NULL, typename, NULL, NULL);
|
||||
if (tup == NULL)
|
||||
{
|
||||
if (!drop->missing_ok)
|
||||
@@ -767,6 +776,7 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||
Oid old_type_oid;
|
||||
Form_pg_type baseType;
|
||||
int32 basetypeMod;
|
||||
Oid baseColl;
|
||||
|
||||
/* Convert list of names to a name and namespace */
|
||||
domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
|
||||
@@ -797,7 +807,7 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||
/*
|
||||
* Look up the base type.
|
||||
*/
|
||||
typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
|
||||
typeTup = typenameType(NULL, stmt->typeName, &basetypeMod, &baseColl);
|
||||
baseType = (Form_pg_type) GETSTRUCT(typeTup);
|
||||
basetypeoid = HeapTupleGetOid(typeTup);
|
||||
|
||||
@@ -1040,7 +1050,8 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||
storage, /* TOAST strategy */
|
||||
basetypeMod, /* typeMod value */
|
||||
typNDims, /* Array dimensions for base type */
|
||||
typNotNull); /* Type NOT NULL */
|
||||
typNotNull, /* Type NOT NULL */
|
||||
baseColl);
|
||||
|
||||
/*
|
||||
* Process constraints which refer to the domain ID returned by TypeCreate
|
||||
@@ -1149,7 +1160,8 @@ DefineEnum(CreateEnumStmt *stmt)
|
||||
'p', /* TOAST strategy always plain */
|
||||
-1, /* typMod (Domains only) */
|
||||
0, /* Array dimensions of typbasetype */
|
||||
false); /* Type NOT NULL */
|
||||
false, /* Type NOT NULL */
|
||||
InvalidOid); /* typcollation */
|
||||
|
||||
/* Enter the enum's values into pg_enum */
|
||||
EnumValuesCreate(enumTypeOid, stmt->vals);
|
||||
@@ -1188,7 +1200,8 @@ DefineEnum(CreateEnumStmt *stmt)
|
||||
'x', /* ARRAY is always toastable */
|
||||
-1, /* typMod (Domains only) */
|
||||
0, /* Array dimensions of typbasetype */
|
||||
false); /* Type NOT NULL */
|
||||
false, /* Type NOT NULL */
|
||||
InvalidOid); /* typcollation */
|
||||
|
||||
pfree(enumArrayName);
|
||||
}
|
||||
@@ -2615,7 +2628,7 @@ AlterTypeOwner(List *names, Oid newOwnerId)
|
||||
typename = makeTypeNameFromNameList(names);
|
||||
|
||||
/* Use LookupTypeName here so that shell types can be processed */
|
||||
tup = LookupTypeName(NULL, typename, NULL);
|
||||
tup = LookupTypeName(NULL, typename, NULL, NULL);
|
||||
if (tup == NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
|
||||
@@ -120,7 +120,8 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
|
||||
|
||||
def->colname = pstrdup(tle->resname);
|
||||
def->typeName = makeTypeNameFromOid(exprType((Node *) tle->expr),
|
||||
exprTypmod((Node *) tle->expr));
|
||||
exprTypmod((Node *) tle->expr),
|
||||
exprCollation((Node *) tle->expr));
|
||||
def->inhcount = 0;
|
||||
def->is_local = true;
|
||||
def->is_not_null = false;
|
||||
|
||||
Reference in New Issue
Block a user