collate.patch
text/x-patch
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| contrib/btree_gist/btree_utils_var.c | 1 | 1 |
| contrib/citext/citext.c | 11 | 10 |
| src/backend/access/common/tupdesc.c | 4 | 1 |
| src/backend/catalog/genbki.pl | 1 | 0 |
| src/backend/catalog/heap.c | 1 | 0 |
| src/backend/catalog/Makefile | 7 | 2 |
| src/backend/catalog/namespace.c | 47 | 0 |
| src/backend/catalog/pg_type.c | 2 | 0 |
| src/backend/commands/aggregatecmds.c | 3 | 3 |
| src/backend/commands/comment.c | 3 | 3 |
| src/backend/commands/functioncmds.c | 6 | 6 |
| src/backend/commands/opclasscmds.c | 4 | 4 |
| src/backend/commands/operatorcmds.c | 2 | 2 |
| src/backend/commands/prepare.c | 1 | 1 |
| src/backend/commands/tablecmds.c | 23 | 11 |
| src/backend/commands/typecmds.c | 11 | 11 |
| src/backend/nodes/copyfuncs.c | 21 | 0 |
| src/backend/nodes/equalfuncs.c | 19 | 0 |
| src/backend/nodes/nodeFuncs.c | 38 | 0 |
| src/backend/nodes/outfuncs.c | 19 | 0 |
| src/backend/nodes/readfuncs.c | 3 | 0 |
| src/backend/optimizer/util/clauses.c | 3 | 0 |
| src/backend/parser/gram.y | 17 | 1 |
| src/backend/parser/parse_expr.c | 29 | 4 |
| src/backend/parser/parse_func.c | 2 | 2 |
| src/backend/parser/parse_node.c | 3 | 1 |
| src/backend/parser/parse_oper.c | 26 | 2 |
| src/backend/parser/parse_relation.c | 10 | 2 |
| src/backend/parser/parse_type.c | 77 | 7 |
| src/backend/parser/parse_utilcmd.c | 2 | 2 |
| src/backend/utils/adt/selfuncs.c | 3 | 3 |
| src/backend/utils/adt/varchar.c | 14 | 7 |
| src/backend/utils/adt/varlena.c | 38 | 13 |
| src/backend/utils/cache/syscache.c | 23 | 0 |
| src/backend/utils/fmgr/fmgr.c | 10 | 0 |
| src/backend/utils/misc/guc.c | 1 | 1 |
| src/bin/initdb/initdb.c | 45 | 0 |
| src/include/catalog/catversion.h | 1 | 1 |
| src/include/catalog/indexing.h | 5 | 0 |
| src/include/catalog/namespace.h | 1 | 0 |
| src/include/catalog/pg_attribute.h | 9 | 5 |
| src/include/catalog/pg_class.h | 2 | 2 |
| src/include/catalog/pg_collation.h | 58 | 0 |
| src/include/catalog/pg_type.h | 146 | 140 |
| src/include/fmgr.h | 2 | 0 |
| src/include/nodes/nodeFuncs.h | 1 | 0 |
| src/include/nodes/nodes.h | 1 | 0 |
| src/include/nodes/parsenodes.h | 4 | 1 |
| src/include/nodes/primnodes.h | 15 | 0 |
| src/include/parser/parsetree.h | 1 | 1 |
| src/include/parser/parse_type.h | 5 | 3 |
| src/include/utils/builtins.h | 1 | 1 |
| src/include/utils/syscache.h | 2 | 0 |
| src/pl/plpgsql/src/pl_comp.c | 1 | 1 |
| src/test/regress/expected/collate.out | 42 | 0 |
| src/test/regress/expected/sanity_check.out | 2 | 1 |
| src/test/regress/parallel_schedule | 1 | 1 |
| src/test/regress/serial_schedule | 1 | 0 |
| src/test/regress/sql/collate.sql | 30 | 0 |
diff --git a/contrib/btree_gist/btree_utils_var.c b/contrib/btree_gist/btree_utils_var.c
index a703289..2d8801d 100644
--- a/contrib/btree_gist/btree_utils_var.c
+++ b/contrib/btree_gist/btree_utils_var.c
@@ -156,7 +156,7 @@ gbt_bytea_pf_match(const bytea *pf, const bytea *query, const gbtree_vinfo *tinf
if (tinfo->eml > 1)
{
- out = (varstr_cmp(q, nlen, n, nlen) == 0);
+ out = (varstr_cmp(q, nlen, n, nlen, InvalidOid) == 0);
}
else
{
diff --git a/contrib/citext/citext.c b/contrib/citext/citext.c
index 006d0e4..bf7c978 100644
--- a/contrib/citext/citext.c
+++ b/contrib/citext/citext.c
@@ -18,7 +18,7 @@ PG_MODULE_MAGIC;
* ====================
*/
-static int32 citextcmp(text *left, text *right);
+static int32 citextcmp(text *left, text *right, Oid collid);
extern Datum citext_cmp(PG_FUNCTION_ARGS);
extern Datum citext_hash(PG_FUNCTION_ARGS);
extern Datum citext_eq(PG_FUNCTION_ARGS);
@@ -42,7 +42,7 @@ extern Datum citext_larger(PG_FUNCTION_ARGS);
* Returns int32 negative, zero, or positive.
*/
static int32
-citextcmp(text *left, text *right)
+citextcmp(text *left, text *right, Oid collid)
{
char *lcstr,
*rcstr;
@@ -52,7 +52,8 @@ citextcmp(text *left, text *right)
rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right));
result = varstr_cmp(lcstr, strlen(lcstr),
- rcstr, strlen(rcstr));
+ rcstr, strlen(rcstr),
+ collid);
pfree(lcstr);
pfree(rcstr);
@@ -75,7 +76,7 @@ citext_cmp(PG_FUNCTION_ARGS)
text *right = PG_GETARG_TEXT_PP(1);
int32 result;
- result = citextcmp(left, right);
+ result = citextcmp(left, right, PG_GET_COLLATION());
PG_FREE_IF_COPY(left, 0);
PG_FREE_IF_COPY(right, 1);
@@ -177,7 +178,7 @@ citext_lt(PG_FUNCTION_ARGS)
text *right = PG_GETARG_TEXT_PP(1);
bool result;
- result = citextcmp(left, right) < 0;
+ result = citextcmp(left, right, PG_GET_COLLATION()) < 0;
PG_FREE_IF_COPY(left, 0);
PG_FREE_IF_COPY(right, 1);
@@ -194,7 +195,7 @@ citext_le(PG_FUNCTION_ARGS)
text *right = PG_GETARG_TEXT_PP(1);
bool result;
- result = citextcmp(left, right) <= 0;
+ result = citextcmp(left, right, PG_GET_COLLATION()) <= 0;
PG_FREE_IF_COPY(left, 0);
PG_FREE_IF_COPY(right, 1);
@@ -211,7 +212,7 @@ citext_gt(PG_FUNCTION_ARGS)
text *right = PG_GETARG_TEXT_PP(1);
bool result;
- result = citextcmp(left, right) > 0;
+ result = citextcmp(left, right, PG_GET_COLLATION()) > 0;
PG_FREE_IF_COPY(left, 0);
PG_FREE_IF_COPY(right, 1);
@@ -228,7 +229,7 @@ citext_ge(PG_FUNCTION_ARGS)
text *right = PG_GETARG_TEXT_PP(1);
bool result;
- result = citextcmp(left, right) >= 0;
+ result = citextcmp(left, right, PG_GET_COLLATION()) >= 0;
PG_FREE_IF_COPY(left, 0);
PG_FREE_IF_COPY(right, 1);
@@ -251,7 +252,7 @@ citext_smaller(PG_FUNCTION_ARGS)
text *right = PG_GETARG_TEXT_PP(1);
text *result;
- result = citextcmp(left, right) < 0 ? left : right;
+ result = citextcmp(left, right, PG_GET_COLLATION()) < 0 ? left : right;
PG_RETURN_TEXT_P(result);
}
@@ -264,6 +265,6 @@ citext_larger(PG_FUNCTION_ARGS)
text *right = PG_GETARG_TEXT_PP(1);
text *result;
- result = citextcmp(left, right) > 0 ? left : right;
+ result = citextcmp(left, right, PG_GET_COLLATION()) > 0 ? left : right;
PG_RETURN_TEXT_P(result);
}
diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c
index 9a8611f..2b290f8 100644
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -476,6 +476,7 @@ TupleDescInitEntry(TupleDesc desc,
att->attisdropped = false;
att->attislocal = true;
att->attinhcount = 0;
+ att->attcollation = InvalidOid;
/* attacl and attoptions are not present in tupledescs */
tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
@@ -514,6 +515,7 @@ BuildDescForRelation(List *schema)
Oid atttypid;
int32 atttypmod;
int attdim;
+ Oid colloid;
/*
* allocate a new tuple descriptor
@@ -536,7 +538,7 @@ BuildDescForRelation(List *schema)
attnum++;
attname = entry->colname;
- atttypid = typenameTypeId(NULL, entry->typeName, &atttypmod);
+ atttypid = typenameTypeId(NULL, entry->typeName, &atttypmod, &colloid);
attdim = list_length(entry->typeName->arrayBounds);
if (entry->typeName->setof)
@@ -557,6 +559,7 @@ BuildDescForRelation(List *schema)
has_not_null |= entry->is_not_null;
desc->attrs[attnum - 1]->attislocal = entry->is_local;
desc->attrs[attnum - 1]->attinhcount = entry->inhcount;
+ desc->attrs[attnum - 1]->attcollation = colloid;
}
if (has_not_null)
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index 82f761d..32ed66d 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -15,7 +15,7 @@ OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
pg_inherits.o pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o \
pg_db_role_setting.o pg_shdepend.o pg_type.o storage.o toasting.o
-BKIFILES = postgres.bki postgres.description postgres.shdescription
+BKIFILES = postgres.bki postgres.description postgres.shdescription locales.txt
include $(top_srcdir)/src/backend/common.mk
@@ -37,7 +37,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
pg_ts_parser.h pg_ts_template.h \
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
- pg_default_acl.h \
+ pg_default_acl.h pg_collation.h \
toasting.h indexing.h \
)
@@ -57,11 +57,15 @@ schemapg.h: postgres.bki ;
postgres.bki: genbki.pl Catalog.pm $(POSTGRES_BKI_SRCS)
$(PERL) -I $(catalogdir) $< $(pg_includes) --set-version=$(MAJORVERSION) $(POSTGRES_BKI_SRCS)
+locales.txt:
+ for loc in $$(locale -a); do cm=$$(LC_CTYPE="$$loc" locale charmap); echo "$$loc $$cm"; done >$@
+
.PHONY: install-data
install-data: $(BKIFILES) installdirs
$(INSTALL_DATA) $(call vpathsearch,postgres.bki) '$(DESTDIR)$(datadir)/postgres.bki'
$(INSTALL_DATA) $(call vpathsearch,postgres.description) '$(DESTDIR)$(datadir)/postgres.description'
$(INSTALL_DATA) $(call vpathsearch,postgres.shdescription) '$(DESTDIR)$(datadir)/postgres.shdescription'
+ $(INSTALL_DATA) $(call vpathsearch,locales.txt) '$(DESTDIR)$(datadir)/locales.txt'
$(INSTALL_DATA) $(srcdir)/system_views.sql '$(DESTDIR)$(datadir)/system_views.sql'
$(INSTALL_DATA) $(srcdir)/information_schema.sql '$(DESTDIR)$(datadir)/information_schema.sql'
$(INSTALL_DATA) $(srcdir)/sql_features.txt '$(DESTDIR)$(datadir)/sql_features.txt'
@@ -76,6 +80,7 @@ uninstall-data:
# postgres.bki, postgres.description, postgres.shdescription, and schemapg.h
# are in the distribution tarball, so they are not cleaned here.
clean:
+ rm -f locales.txt
maintainer-clean: clean
rm -f $(BKIFILES)
diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl
index 31aabda..5e57946 100644
--- a/src/backend/catalog/genbki.pl
+++ b/src/backend/catalog/genbki.pl
@@ -367,6 +367,7 @@ sub emit_pgattr_row
attisdropped => 'f',
attislocal => 't',
attinhcount => '0',
+ attcollation => '0',
attacl => '_null_',
attoptions => '_null_'
);
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index d848ef0..b0350ed 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -536,6 +536,7 @@ InsertPgAttributeTuple(Relation pg_attribute_rel,
values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(new_attribute->attisdropped);
values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(new_attribute->attislocal);
values[Anum_pg_attribute_attinhcount - 1] = Int32GetDatum(new_attribute->attinhcount);
+ values[Anum_pg_attribute_attcollation - 1] = ObjectIdGetDatum(new_attribute->attcollation);
/* start out with empty permissions and empty options */
nulls[Anum_pg_attribute_attacl - 1] = true;
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 5581346..ba1a720 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -2765,6 +2765,53 @@ PopOverrideSearchPath(void)
/*
+ * FindCollationByName - find a collation by possibly qualified name
+ */
+Oid
+FindCollationByName(List *name)
+{
+ char *schemaname;
+ char *collation_name;
+ Oid namespaceId;
+ Oid colloid;
+ ListCell *l;
+
+ /* deconstruct the name list */
+ DeconstructQualifiedName(name, &schemaname, &collation_name);
+
+ if (schemaname)
+ {
+ /* use exact schema given */
+ namespaceId = LookupExplicitNamespace(schemaname);
+ return GetSysCacheOid2(COLLNAMENSP,
+ PointerGetDatum(collation_name),
+ ObjectIdGetDatum(namespaceId));
+ }
+ else
+ {
+ /* search for it in search path */
+ recomputeNamespacePath();
+
+ foreach(l, activeSearchPath)
+ {
+ namespaceId = lfirst_oid(l);
+
+ if (namespaceId == myTempNamespace)
+ continue; /* do not look in temp namespace */
+
+ colloid = GetSysCacheOid2(COLLNAMENSP,
+ PointerGetDatum(collation_name),
+ ObjectIdGetDatum(namespaceId));
+ if (OidIsValid(colloid))
+ return colloid;
+ }
+ }
+
+ /* Not found in path */
+ return InvalidOid;
+}
+
+/*
* FindConversionByName - find a conversion by possibly qualified name
*/
Oid
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 76f9e06..5532b3c 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -109,6 +109,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
values[i++] = CharGetDatum('i'); /* typalign */
values[i++] = CharGetDatum('p'); /* typstorage */
values[i++] = BoolGetDatum(false); /* typnotnull */
+ values[i++] = BoolGetDatum(false); /* typcollatable */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typbasetype */
values[i++] = Int32GetDatum(-1); /* typtypmod */
values[i++] = Int32GetDatum(0); /* typndims */
@@ -339,6 +340,7 @@ TypeCreate(Oid newTypeOid,
values[i++] = CharGetDatum(alignment); /* typalign */
values[i++] = CharGetDatum(storage); /* typstorage */
values[i++] = BoolGetDatum(typeNotNull); /* typnotnull */
+ values[i++] = BoolGetDatum(false); /* typcollatable */ // TODO: add to CREATE TYPE
values[i++] = ObjectIdGetDatum(baseType); /* typbasetype */
values[i++] = Int32GetDatum(typeMod); /* typtypmod */
values[i++] = Int32GetDatum(typNDims); /* typndims */
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 4964fb3..d7ba02e 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -142,7 +142,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
{
numArgs = 1;
aggArgTypes = (Oid *) palloc(sizeof(Oid));
- aggArgTypes[0] = typenameTypeId(NULL, baseType, NULL);
+ aggArgTypes[0] = typenameTypeId(NULL, baseType, NULL, NULL);
}
}
else
@@ -164,7 +164,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
{
TypeName *curTypeName = (TypeName *) lfirst(lc);
- aggArgTypes[i++] = typenameTypeId(NULL, curTypeName, NULL);
+ aggArgTypes[i++] = typenameTypeId(NULL, curTypeName, NULL, NULL);
}
}
@@ -179,7 +179,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
* worse) by connecting up incompatible internal-using functions in an
* aggregate.
*/
- transTypeId = typenameTypeId(NULL, transType, NULL);
+ transTypeId = typenameTypeId(NULL, transType, NULL, NULL);
if (get_typtype(transTypeId) == TYPTYPE_PSEUDO &&
!IsPolymorphicType(transTypeId))
{
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index b613cbf..e0e2c91 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -945,7 +945,7 @@ CommentType(List *typename, char *comment)
/* Find the type's oid */
- oid = typenameTypeId(NULL, tname, NULL);
+ oid = typenameTypeId(NULL, tname, NULL, NULL);
/* Check object security */
@@ -1457,8 +1457,8 @@ CommentCast(List *qualname, List *arguments, char *comment)
targettype = (TypeName *) linitial(arguments);
Assert(IsA(targettype, TypeName));
- sourcetypeid = typenameTypeId(NULL, sourcetype, NULL);
- targettypeid = typenameTypeId(NULL, targettype, NULL);
+ sourcetypeid = typenameTypeId(NULL, sourcetype, NULL, NULL);
+ targettypeid = typenameTypeId(NULL, targettype, NULL, NULL);
tuple = SearchSysCache2(CASTSOURCETARGET,
ObjectIdGetDatum(sourcetypeid),
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 9a584ed..8de06ee 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -86,7 +86,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)
{
@@ -206,7 +206,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)
@@ -1496,8 +1496,8 @@ CreateCast(CreateCastStmt *stmt)
ObjectAddress myself,
referenced;
- sourcetypeid = typenameTypeId(NULL, stmt->sourcetype, NULL);
- targettypeid = typenameTypeId(NULL, stmt->targettype, NULL);
+ sourcetypeid = typenameTypeId(NULL, stmt->sourcetype, NULL, NULL);
+ targettypeid = typenameTypeId(NULL, stmt->targettype, NULL, NULL);
sourcetyptype = get_typtype(sourcetypeid);
targettyptype = get_typtype(targettypeid);
@@ -1763,8 +1763,8 @@ DropCast(DropCastStmt *stmt)
ObjectAddress object;
/* when dropping a cast, the types must exist even if you use IF EXISTS */
- sourcetypeid = typenameTypeId(NULL, stmt->sourcetype, NULL);
- targettypeid = typenameTypeId(NULL, stmt->targettype, NULL);
+ sourcetypeid = typenameTypeId(NULL, stmt->sourcetype, NULL, NULL);
+ targettypeid = typenameTypeId(NULL, stmt->targettype, NULL, NULL);
tuple = SearchSysCache2(CASTSOURCETARGET,
ObjectIdGetDatum(sourcetypeid),
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index 55d447e..47bf116 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -320,7 +320,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
errmsg("must be superuser to create an operator class")));
/* Look up the datatype */
- typeoid = typenameTypeId(NULL, stmt->datatype, NULL);
+ typeoid = typenameTypeId(NULL, stmt->datatype, NULL, NULL);
#ifdef NOT_USED
/* XXX this is unnecessary given the superuser check above */
@@ -474,7 +474,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("storage type specified more than once")));
- storageoid = typenameTypeId(NULL, item->storedtype, NULL);
+ storageoid = typenameTypeId(NULL, item->storedtype, NULL, NULL);
#ifdef NOT_USED
/* XXX this is unnecessary given the superuser check above */
@@ -1021,12 +1021,12 @@ processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
Assert(args != NIL);
typeName = (TypeName *) linitial(args);
- *lefttype = typenameTypeId(NULL, typeName, NULL);
+ *lefttype = typenameTypeId(NULL, typeName, NULL, NULL);
if (list_length(args) > 1)
{
typeName = (TypeName *) lsecond(args);
- *righttype = typenameTypeId(NULL, typeName, NULL);
+ *righttype = typenameTypeId(NULL, typeName, NULL, NULL);
}
else
*righttype = *lefttype;
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 5db1d0d..a0e0360 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -167,9 +167,9 @@ DefineOperator(List *names, List *parameters)
/* Transform type names to type OIDs */
if (typeName1)
- typeId1 = typenameTypeId(NULL, typeName1, NULL);
+ typeId1 = typenameTypeId(NULL, typeName1, NULL, NULL);
if (typeName2)
- typeId2 = typenameTypeId(NULL, typeName2, NULL);
+ typeId2 = typenameTypeId(NULL, typeName2, NULL, NULL);
if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
ereport(ERROR,
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index e765382..33ec289 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -90,7 +90,7 @@ PrepareQuery(PrepareStmt *stmt, const char *queryString)
foreach(l, stmt->argtypes)
{
TypeName *tn = lfirst(l);
- Oid toid = typenameTypeId(pstate, tn, NULL);
+ Oid toid = typenameTypeId(pstate, tn, NULL, NULL);
argtypes[i++] = toid;
}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 5f6fe41..0cbb92f 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -451,7 +451,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
(void) heap_reloptions(relkind, reloptions, true);
if (stmt->ofTypename)
- ofTypeId = typenameTypeId(NULL, stmt->ofTypename, NULL);
+ ofTypeId = typenameTypeId(NULL, stmt->ofTypename, NULL, NULL);
else
ofTypeId = InvalidOid;
@@ -1367,6 +1367,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
{
Oid defTypeId;
int32 deftypmod;
+ Oid defCollId;
/*
* Yes, try to merge the two column definitions. They must
@@ -1376,9 +1377,10 @@ MergeAttributes(List *schema, List *supers, bool istemp,
(errmsg("merging multiple inherited definitions of column \"%s\"",
attributeName)));
def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
- defTypeId = typenameTypeId(NULL, def->typeName, &deftypmod);
+ defTypeId = typenameTypeId(NULL, def->typeName, &deftypmod, &defCollId);
if (defTypeId != attribute->atttypid ||
- deftypmod != attribute->atttypmod)
+ deftypmod != attribute->atttypmod ||
+ defCollId != attribute->attcollation /*TODO: separate msg for collation*/)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("inherited column \"%s\" has a type conflict",
@@ -1539,6 +1541,8 @@ MergeAttributes(List *schema, List *supers, bool istemp,
newTypeId;
int32 deftypmod,
newtypmod;
+ Oid defcollid,
+ newcollid;
/*
* Yes, try to merge the two column definitions. They must
@@ -1548,9 +1552,9 @@ MergeAttributes(List *schema, List *supers, bool istemp,
(errmsg("merging column \"%s\" with inherited definition",
attributeName)));
def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
- defTypeId = typenameTypeId(NULL, def->typeName, &deftypmod);
- newTypeId = typenameTypeId(NULL, newdef->typeName, &newtypmod);
- if (defTypeId != newTypeId || deftypmod != newtypmod)
+ defTypeId = typenameTypeId(NULL, def->typeName, &deftypmod, &defcollid);
+ newTypeId = typenameTypeId(NULL, newdef->typeName, &newtypmod, &newcollid);
+ if (defTypeId != newTypeId || deftypmod != newtypmod || defcollid != newcollid /*TODO*/)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("column \"%s\" has a type conflict",
@@ -3613,6 +3617,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
HeapTuple typeTuple;
Oid typeOid;
int32 typmod;
+ Oid collOid;
Form_pg_type tform;
Expr *defval;
@@ -3638,11 +3643,13 @@ 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 */
- ctypeId = typenameTypeId(NULL, colDef->typeName, &ctypmod);
+ ctypeId = typenameTypeId(NULL, colDef->typeName, &ctypmod, &ccollid);
if (ctypeId != childatt->atttypid ||
- ctypmod != childatt->atttypmod)
+ ctypmod != childatt->atttypmod ||
+ ccollid != childatt->attcollation /*TODO*/)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("child table \"%s\" has different type for column \"%s\"",
@@ -3704,7 +3711,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);
@@ -3729,6 +3736,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);
@@ -5784,6 +5792,7 @@ ATPrepAlterColumnType(List **wqueue,
AttrNumber attnum;
Oid targettype;
int32 targettypmod;
+ Oid targetcollid;
Node *transform;
NewColumnValue *newval;
ParseState *pstate = make_parsestate(NULL);
@@ -5813,7 +5822,8 @@ ATPrepAlterColumnType(List **wqueue,
colName)));
/* Look up the target type */
- targettype = typenameTypeId(NULL, typeName, &targettypmod);
+ targettype = typenameTypeId(NULL, typeName, &targettypmod, &targetcollid);
+ // TODO: check that type accepts collations if targetcollid is set
/* make sure datatype is legal for a column */
CheckAttributeType(colName, targettype, false);
@@ -5917,6 +5927,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
Form_pg_type tform;
Oid targettype;
int32 targettypmod;
+ Oid targetcollid;
Node *defaultexpr;
Relation attrelation;
Relation depRel;
@@ -5945,7 +5956,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);
@@ -6202,6 +6213,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;
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 1e14dca..a245985 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -285,7 +285,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;
@@ -332,7 +332,7 @@ DefineType(List *names, List *parameters)
}
if (elemTypeEl)
{
- elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl), NULL);
+ elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl), NULL, NULL);
/* disallow arrays of pseudotypes */
if (get_typtype(elemType) == TYPTYPE_PSEUDO)
ereport(ERROR,
@@ -640,7 +640,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)
@@ -798,7 +798,7 @@ DefineDomain(CreateDomainStmt *stmt)
/*
* Look up the base type.
*/
- typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
+ typeTup = typenameType(NULL, stmt->typeName, &basetypeMod, NULL); /* TODO: collation support for domains */
baseType = (Form_pg_type) GETSTRUCT(typeTup);
basetypeoid = HeapTupleGetOid(typeTup);
@@ -1572,7 +1572,7 @@ AlterDomainDefault(List *names, Node *defaultRaw)
/* Make a TypeName so we can use standard type lookup machinery */
typename = makeTypeNameFromNameList(names);
- domainoid = typenameTypeId(NULL, typename, NULL);
+ domainoid = typenameTypeId(NULL, typename, NULL, NULL);
/* Look up the domain in the type table */
rel = heap_open(TypeRelationId, RowExclusiveLock);
@@ -1698,7 +1698,7 @@ AlterDomainNotNull(List *names, bool notNull)
/* Make a TypeName so we can use standard type lookup machinery */
typename = makeTypeNameFromNameList(names);
- domainoid = typenameTypeId(NULL, typename, NULL);
+ domainoid = typenameTypeId(NULL, typename, NULL, NULL);
/* Look up the domain in the type table */
typrel = heap_open(TypeRelationId, RowExclusiveLock);
@@ -1798,7 +1798,7 @@ AlterDomainDropConstraint(List *names, const char *constrName,
/* Make a TypeName so we can use standard type lookup machinery */
typename = makeTypeNameFromNameList(names);
- domainoid = typenameTypeId(NULL, typename, NULL);
+ domainoid = typenameTypeId(NULL, typename, NULL, NULL);
/* Look up the domain in the type table */
rel = heap_open(TypeRelationId, RowExclusiveLock);
@@ -1871,7 +1871,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
/* Make a TypeName so we can use standard type lookup machinery */
typename = makeTypeNameFromNameList(names);
- domainoid = typenameTypeId(NULL, typename, NULL);
+ domainoid = typenameTypeId(NULL, typename, NULL, NULL);
/* Look up the domain in the type table */
typrel = heap_open(TypeRelationId, RowExclusiveLock);
@@ -2492,7 +2492,7 @@ RenameType(List *names, const char *newTypeName)
/* Make a TypeName so we can use standard type lookup machinery */
typename = makeTypeNameFromNameList(names);
- typeOid = typenameTypeId(NULL, typename, NULL);
+ typeOid = typenameTypeId(NULL, typename, NULL, NULL);
/* Look up the type in the type table */
rel = heap_open(TypeRelationId, RowExclusiveLock);
@@ -2565,7 +2565,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),
@@ -2721,7 +2721,7 @@ AlterTypeNamespace(List *names, const char *newschema)
/* Make a TypeName so we can use standard type lookup machinery */
typename = makeTypeNameFromNameList(names);
- typeOid = typenameTypeId(NULL, typename, NULL);
+ typeOid = typenameTypeId(NULL, typename, NULL, NULL);
/* check permissions on type */
if (!pg_type_ownercheck(typeOid, GetUserId()))
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 93dcef5..0213cdd 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -975,6 +975,7 @@ _copyVar(Var *from)
COPY_SCALAR_FIELD(varlevelsup);
COPY_SCALAR_FIELD(varnoold);
COPY_SCALAR_FIELD(varoattno);
+ COPY_SCALAR_FIELD(varcollid);
COPY_LOCATION_FIELD(location);
return newnode;
@@ -1105,6 +1106,7 @@ _copyFuncExpr(FuncExpr *from)
COPY_SCALAR_FIELD(funcretset);
COPY_SCALAR_FIELD(funcformat);
COPY_NODE_FIELD(args);
+ COPY_SCALAR_FIELD(collid);
COPY_LOCATION_FIELD(location);
return newnode;
@@ -1139,6 +1141,7 @@ _copyOpExpr(OpExpr *from)
COPY_SCALAR_FIELD(opresulttype);
COPY_SCALAR_FIELD(opretset);
COPY_NODE_FIELD(args);
+ COPY_SCALAR_FIELD(collid);
COPY_LOCATION_FIELD(location);
return newnode;
@@ -2070,6 +2073,8 @@ _copyTypeName(TypeName *from)
COPY_NODE_FIELD(typmods);
COPY_SCALAR_FIELD(typemod);
COPY_NODE_FIELD(arrayBounds);
+ COPY_NODE_FIELD(collnames);
+ COPY_SCALAR_FIELD(collOid);
COPY_LOCATION_FIELD(location);
return newnode;
@@ -2141,6 +2146,19 @@ _copyTypeCast(TypeCast *from)
return newnode;
}
+static CollateClause *
+_copyCollateClause(CollateClause *from)
+{
+ CollateClause *newnode = makeNode(CollateClause);
+
+ COPY_NODE_FIELD(arg);
+ COPY_NODE_FIELD(collnames);
+ COPY_SCALAR_FIELD(collOid);
+ COPY_LOCATION_FIELD(location);
+
+ return newnode;
+}
+
static IndexElem *
_copyIndexElem(IndexElem *from)
{
@@ -4204,6 +4222,9 @@ copyObject(void *from)
case T_TypeCast:
retval = _copyTypeCast(from);
break;
+ case T_CollateClause:
+ retval = _copyCollateClause(from);
+ break;
case T_SortBy:
retval = _copySortBy(from);
break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 5d83727..1b986fc 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -140,6 +140,7 @@ _equalVar(Var *a, Var *b)
COMPARE_SCALAR_FIELD(varlevelsup);
COMPARE_SCALAR_FIELD(varnoold);
COMPARE_SCALAR_FIELD(varoattno);
+ COMPARE_SCALAR_FIELD(varcollid);
COMPARE_LOCATION_FIELD(location);
return true;
@@ -237,6 +238,7 @@ _equalFuncExpr(FuncExpr *a, FuncExpr *b)
return false;
COMPARE_NODE_FIELD(args);
+ COMPARE_SCALAR_FIELD(collid);
COMPARE_LOCATION_FIELD(location);
return true;
@@ -272,6 +274,7 @@ _equalOpExpr(OpExpr *a, OpExpr *b)
COMPARE_SCALAR_FIELD(opresulttype);
COMPARE_SCALAR_FIELD(opretset);
COMPARE_NODE_FIELD(args);
+ COMPARE_SCALAR_FIELD(collid);
COMPARE_LOCATION_FIELD(location);
return true;
@@ -2023,6 +2026,8 @@ _equalTypeName(TypeName *a, TypeName *b)
COMPARE_NODE_FIELD(typmods);
COMPARE_SCALAR_FIELD(typemod);
COMPARE_NODE_FIELD(arrayBounds);
+ COMPARE_NODE_FIELD(collnames);
+ COMPARE_SCALAR_FIELD(collOid);
COMPARE_LOCATION_FIELD(location);
return true;
@@ -2039,6 +2044,17 @@ _equalTypeCast(TypeCast *a, TypeCast *b)
}
static bool
+_equalCollateClause(CollateClause *a, CollateClause *b)
+{
+ COMPARE_NODE_FIELD(arg);
+ COMPARE_NODE_FIELD(collnames);
+ COMPARE_SCALAR_FIELD(collOid);
+ COMPARE_LOCATION_FIELD(location);
+
+ return true;
+}
+
+static bool
_equalSortBy(SortBy *a, SortBy *b)
{
COMPARE_NODE_FIELD(node);
@@ -2871,6 +2887,9 @@ equal(void *a, void *b)
case T_TypeCast:
retval = _equalTypeCast(a, b);
break;
+ case T_CollateClause:
+ retval = _equalCollateClause(a, b);
+ break;
case T_SortBy:
retval = _equalSortBy(a, b);
break;
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 9cf0cae..a41fc41 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -460,6 +460,39 @@ exprTypmod(Node *expr)
}
/*
+ * exprColl -
+ * returns the Oid of the collation of the expression's result.
+ */
+Oid
+exprColl(Node *expr)
+{
+ Oid coll;
+
+ if (!expr)
+ return InvalidOid;
+
+ switch (nodeTag(expr))
+ {
+ case T_Var:
+ coll = ((Var *) expr)->varcollid;
+ break;
+ case T_FuncExpr:
+ coll = ((FuncExpr *) expr)->collid;
+ break;
+ case T_OpExpr:
+ coll = ((OpExpr *) expr)->collid;
+ break;
+ case T_DistinctExpr:
+ coll = ((DistinctExpr *) expr)->collid;
+ break;
+ default:
+ coll = InvalidOid; // TODO
+ break;
+ }
+ return coll;
+}
+
+/*
* exprIsLengthCoercion
* Detect whether an expression tree is an application of a datatype's
* typmod-coercion function. Optionally extract the result's typmod.
@@ -908,6 +941,9 @@ exprLocation(Node *expr)
loc = leftmostLoc(loc, tc->location);
}
break;
+ case T_CollateClause:
+ loc = ((CollateClause *) expr)->location;
+ break;
case T_SortBy:
/* just use argument's location (ignore operator, if any) */
loc = exprLocation(((SortBy *) expr)->node);
@@ -2471,6 +2507,8 @@ bool
return true;
}
break;
+ case T_CollateClause:
+ return walker(((CollateClause *) node)->arg, context);
case T_SortBy:
return walker(((SortBy *) node)->node, context);
case T_WindowDef:
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 79baf4f..74ff920 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -841,6 +841,7 @@ _outVar(StringInfo str, Var *node)
WRITE_UINT_FIELD(varlevelsup);
WRITE_UINT_FIELD(varnoold);
WRITE_INT_FIELD(varoattno);
+ WRITE_OID_FIELD(varcollid);
WRITE_LOCATION_FIELD(location);
}
@@ -928,6 +929,7 @@ _outFuncExpr(StringInfo str, FuncExpr *node)
WRITE_BOOL_FIELD(funcretset);
WRITE_ENUM_FIELD(funcformat, CoercionForm);
WRITE_NODE_FIELD(args);
+ WRITE_OID_FIELD(collid);
WRITE_LOCATION_FIELD(location);
}
@@ -952,6 +954,7 @@ _outOpExpr(StringInfo str, OpExpr *node)
WRITE_OID_FIELD(opresulttype);
WRITE_BOOL_FIELD(opretset);
WRITE_NODE_FIELD(args);
+ WRITE_OID_FIELD(collid);
WRITE_LOCATION_FIELD(location);
}
@@ -1937,6 +1940,8 @@ _outTypeName(StringInfo str, TypeName *node)
WRITE_NODE_FIELD(typmods);
WRITE_INT_FIELD(typemod);
WRITE_NODE_FIELD(arrayBounds);
+ WRITE_NODE_FIELD(collnames);
+ WRITE_OID_FIELD(collOid);
WRITE_LOCATION_FIELD(location);
}
@@ -1951,6 +1956,17 @@ _outTypeCast(StringInfo str, TypeCast *node)
}
static void
+_outCollateClause(StringInfo str, CollateClause *node)
+{
+ WRITE_NODE_TYPE("COLLATE");
+
+ WRITE_NODE_FIELD(arg);
+ WRITE_NODE_FIELD(collnames);
+ WRITE_OID_FIELD(collOid);
+ WRITE_LOCATION_FIELD(location);
+}
+
+static void
_outIndexElem(StringInfo str, IndexElem *node)
{
WRITE_NODE_TYPE("INDEXELEM");
@@ -2823,6 +2839,9 @@ _outNode(StringInfo str, void *obj)
case T_TypeCast:
_outTypeCast(str, obj);
break;
+ case T_CollateClause:
+ _outCollateClause(str, obj);
+ break;
case T_IndexElem:
_outIndexElem(str, obj);
break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index bc6e2a6..d520392 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -407,6 +407,7 @@ _readVar(void)
READ_UINT_FIELD(varlevelsup);
READ_UINT_FIELD(varnoold);
READ_INT_FIELD(varoattno);
+ READ_OID_FIELD(varcollid);
READ_LOCATION_FIELD(location);
READ_DONE();
@@ -524,6 +525,7 @@ _readFuncExpr(void)
READ_BOOL_FIELD(funcretset);
READ_ENUM_FIELD(funcformat, CoercionForm);
READ_NODE_FIELD(args);
+ READ_OID_FIELD(collid);
READ_LOCATION_FIELD(location);
READ_DONE();
@@ -569,6 +571,7 @@ _readOpExpr(void)
READ_OID_FIELD(opresulttype);
READ_BOOL_FIELD(opretset);
READ_NODE_FIELD(args);
+ READ_OID_FIELD(collid);
READ_LOCATION_FIELD(location);
READ_DONE();
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index e525ba6..5e3d50d 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -2173,6 +2173,7 @@ eval_const_expressions_mutator(Node *node,
newexpr->funcretset = expr->funcretset;
newexpr->funcformat = expr->funcformat;
newexpr->args = args;
+ newexpr->collid = expr->collid;
newexpr->location = expr->location;
return (Node *) newexpr;
}
@@ -2233,6 +2234,7 @@ eval_const_expressions_mutator(Node *node,
newexpr->opresulttype = expr->opresulttype;
newexpr->opretset = expr->opretset;
newexpr->args = args;
+ newexpr->collid = expr->collid;
newexpr->location = expr->location;
return (Node *) newexpr;
}
@@ -2325,6 +2327,7 @@ eval_const_expressions_mutator(Node *node,
newexpr->opresulttype = expr->opresulttype;
newexpr->opretset = expr->opretset;
newexpr->args = args;
+ newexpr->collid = expr->collid;
newexpr->location = expr->location;
return (Node *) newexpr;
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 3f6eeeb..ee1d786 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -388,7 +388,8 @@ static TypeName *TableFuncTypeName(List *columns);
%type <list> copy_generic_opt_list copy_generic_opt_arg_list
%type <list> copy_options
-%type <typnam> Typename SimpleTypename ConstTypename
+%type <typnam> Typename SimpleTypename SimpleTypenameWithoutCollation
+ ConstTypename
GenericType Numeric opt_float
Character ConstCharacter
CharacterWithLength CharacterWithoutLength
@@ -8258,6 +8259,14 @@ opt_array_bounds:
;
SimpleTypename:
+ SimpleTypenameWithoutCollation { $$ = $1; }
+ | SimpleTypenameWithoutCollation COLLATE any_name
+ {
+ $$ = $1;
+ $$->collnames = $3;
+ }
+
+SimpleTypenameWithoutCollation:
GenericType { $$ = $1; }
| Numeric { $$ = $1; }
| Bit { $$ = $1; }
@@ -9293,6 +9302,13 @@ c_expr: columnref { $$ = $1; }
r->location = @1;
$$ = (Node *)r;
}
+ | '(' a_expr ')' COLLATE any_name // TODO: this is not the right expression syntax
+ {
+ CollateClause *n = makeNode(CollateClause);
+ n->arg = $2;
+ n->collnames = $5;
+ $$ = (Node *)n;
+ }
;
/*
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 888b526..714c71f 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -69,6 +69,7 @@ static Node *transformWholeRowRef(ParseState *pstate, RangeTblEntry *rte,
static Node *transformIndirection(ParseState *pstate, Node *basenode,
List *indirection);
static Node *transformTypeCast(ParseState *pstate, TypeCast *tc);
+static Node *transformCollateClause(ParseState *pstate, CollateClause *c);
static Node *make_row_comparison_op(ParseState *pstate, List *opname,
List *largs, List *rargs, int location);
static Node *make_row_distinct_op(ParseState *pstate, List *opname,
@@ -164,7 +165,8 @@ transformExpr(ParseState *pstate, Node *expr)
int32 targetTypmod;
targetType = typenameTypeId(pstate, tc->typeName,
- &targetTypmod);
+ &targetTypmod,
+ NULL); /* TODO: support or prohibit collations in type casts */
elementType = get_element_type(targetType);
if (OidIsValid(elementType))
{
@@ -191,6 +193,10 @@ transformExpr(ParseState *pstate, Node *expr)
break;
}
+ case T_CollateClause:
+ result = transformCollateClause(pstate, (CollateClause *) expr);
+ break;
+
case T_A_Expr:
{
A_Expr *a = (A_Expr *) expr;
@@ -1037,7 +1043,7 @@ transformAExprOf(ParseState *pstate, A_Expr *a)
ltype = exprType(lexpr);
foreach(telem, (List *) a->rexpr)
{
- rtype = typenameTypeId(pstate, lfirst(telem), NULL);
+ rtype = typenameTypeId(pstate, lfirst(telem), NULL, NULL);
matched = (rtype == ltype);
if (matched)
break;
@@ -1977,7 +1983,7 @@ transformXmlSerialize(ParseState *pstate, XmlSerialize *xs)
XMLOID,
"XMLSERIALIZE"));
- targetType = typenameTypeId(pstate, xs->typeName, &targetTypmod);
+ targetType = typenameTypeId(pstate, xs->typeName, &targetTypmod, NULL);
xexpr->xmloption = xs->xmloption;
xexpr->location = xs->location;
@@ -2212,7 +2218,7 @@ transformTypeCast(ParseState *pstate, TypeCast *tc)
int32 targetTypmod;
int location;
- targetType = typenameTypeId(pstate, tc->typeName, &targetTypmod);
+ targetType = typenameTypeId(pstate, tc->typeName, &targetTypmod, NULL); /* TODO: support or prohibit collations in type casts */
if (inputType == InvalidOid)
return expr; /* do nothing if NULL input */
@@ -2243,6 +2249,25 @@ transformTypeCast(ParseState *pstate, TypeCast *tc)
}
/*
+ * Handle an explicit COLLATE clause.
+ *
+ * Transform the argument, and look up the collation name.
+ */
+static Node *
+transformCollateClause(ParseState *pstate, CollateClause *c)
+{
+ CollateClause *newc;
+
+ newc = makeNode(CollateClause);
+ newc->arg = transformExpr(pstate, c->arg);
+ // TODO: check that input type accepts collations
+ newc->collOid = LookupCollation(pstate, c->collnames, c->location);
+ newc->collnames = c->collnames;
+
+ return (Node *) newc;
+}
+
+/*
* Transform a "row compare-op row" construct
*
* The inputs are lists of already-transformed expressions.
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 9580be9..25fdf95 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -1270,7 +1270,7 @@ FuncNameAsType(List *funcname)
Oid result;
Type typtup;
- typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL);
+ typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL, NULL);
if (typtup == NULL)
return InvalidOid;
@@ -1456,7 +1456,7 @@ LookupTypeNameOid(const TypeName *typename)
Oid result;
Type typtup;
- typtup = LookupTypeName(NULL, typename, NULL);
+ typtup = LookupTypeName(NULL, typename, NULL, NULL);
if (typtup == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index a838b1e..cbc8f80 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -188,10 +188,12 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno, int location)
sublevels_up;
Oid vartypeid;
int32 type_mod;
+ Oid varcollid;
vnum = RTERangeTablePosn(pstate, rte, &sublevels_up);
- get_rte_attribute_type(rte, attrno, &vartypeid, &type_mod);
+ get_rte_attribute_type(rte, attrno, &vartypeid, &type_mod, &varcollid);
result = makeVar(vnum, attrno, vartypeid, type_mod, sublevels_up);
+ result->varcollid = varcollid;
result->location = location;
return result;
}
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 5798136..cb287cf 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -148,12 +148,12 @@ LookupOperNameTypeNames(ParseState *pstate, List *opername,
if (oprleft == NULL)
leftoid = InvalidOid;
else
- leftoid = typenameTypeId(pstate, oprleft, NULL);
+ leftoid = typenameTypeId(pstate, oprleft, NULL, NULL);
if (oprright == NULL)
rightoid = InvalidOid;
else
- rightoid = typenameTypeId(pstate, oprright, NULL);
+ rightoid = typenameTypeId(pstate, oprright, NULL, NULL);
return LookupOperName(pstate, opername, leftoid, rightoid,
noError, location);
@@ -779,6 +779,9 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
List *args;
Oid rettype;
OpExpr *result;
+ Oid lcollid,
+ rcollid;
+ Oid opcollid;
/* Select the operator */
if (rtree == NULL)
@@ -786,6 +789,8 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
/* right operator */
ltypeId = exprType(ltree);
rtypeId = InvalidOid;
+ lcollid = exprColl(ltree);
+ rcollid = InvalidOid;
tup = right_oper(pstate, opname, ltypeId, false, location);
}
else if (ltree == NULL)
@@ -793,6 +798,8 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
/* left operator */
rtypeId = exprType(rtree);
ltypeId = InvalidOid;
+ lcollid = InvalidOid;
+ rcollid = exprColl(rtree);
tup = left_oper(pstate, opname, rtypeId, false, location);
}
else
@@ -800,6 +807,8 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
/* otherwise, binary operator */
ltypeId = exprType(ltree);
rtypeId = exprType(rtree);
+ lcollid = exprColl(ltree);
+ rcollid = exprColl(rtree);
tup = oper(pstate, opname, ltypeId, rtypeId, false, location);
}
@@ -824,6 +833,7 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
actual_arg_types[0] = ltypeId;
declared_arg_types[0] = opform->oprleft;
nargs = 1;
+ opcollid = lcollid;
}
else if (ltree == NULL)
{
@@ -832,6 +842,7 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
actual_arg_types[0] = rtypeId;
declared_arg_types[0] = opform->oprright;
nargs = 1;
+ opcollid = rcollid;
}
else
{
@@ -842,6 +853,18 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
declared_arg_types[0] = opform->oprleft;
declared_arg_types[1] = opform->oprright;
nargs = 2;
+ // TODO: collation derivation logic per SQL standard goes somewhere here
+ if (lcollid == rcollid)
+ opcollid = lcollid;
+ else if (lcollid == InvalidOid)
+ opcollid = rcollid;
+ else if (rcollid == InvalidOid)
+ opcollid = lcollid;
+ else
+ {
+ elog(ERROR, "collation mismatch: left %u != right %u", lcollid, rcollid);
+ opcollid = InvalidOid;
+ }
}
/*
@@ -865,6 +888,7 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
result->opresulttype = rettype;
result->opretset = get_func_retset(opform->oprcode);
result->args = args;
+ result->collid = opcollid;
result->location = location;
ReleaseSysCache(tup);
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 38c7e91..a189b5b 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -1165,7 +1165,7 @@ addRangeTableEntryForFunction(ParseState *pstate,
errmsg("column \"%s\" cannot be declared SETOF",
attrname),
parser_errposition(pstate, n->typeName->location)));
- attrtype = typenameTypeId(pstate, n->typeName, &attrtypmod);
+ attrtype = typenameTypeId(pstate, n->typeName, &attrtypmod, NULL /*TODO*/);
eref->colnames = lappend(eref->colnames, makeString(attrname));
rte->funccoltypes = lappend_oid(rte->funccoltypes, attrtype);
rte->funccoltypmods = lappend_int(rte->funccoltypmods, attrtypmod);
@@ -1968,7 +1968,7 @@ get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
*/
void
get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
- Oid *vartype, int32 *vartypmod)
+ Oid *vartype, int32 *vartypmod, Oid *varcollid)
{
switch (rte->rtekind)
{
@@ -1998,6 +1998,7 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
get_rel_name(rte->relid))));
*vartype = att_tup->atttypid;
*vartypmod = att_tup->atttypmod;
+ *varcollid = att_tup->attcollation;
ReleaseSysCache(tp);
}
break;
@@ -2012,6 +2013,7 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
rte->eref->aliasname, attnum);
*vartype = exprType((Node *) te->expr);
*vartypmod = exprTypmod((Node *) te->expr);
+ *varcollid = exprColl((Node *) te->expr);
}
break;
case RTE_FUNCTION:
@@ -2053,17 +2055,20 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
rte->eref->aliasname)));
*vartype = att_tup->atttypid;
*vartypmod = att_tup->atttypmod;
+ *varcollid = att_tup->attcollation;
}
else if (functypclass == TYPEFUNC_SCALAR)
{
/* Base data type, i.e. scalar */
*vartype = funcrettype;
*vartypmod = -1;
+ *varcollid = InvalidOid; // XXX?
}
else if (functypclass == TYPEFUNC_RECORD)
{
*vartype = list_nth_oid(rte->funccoltypes, attnum - 1);
*vartypmod = list_nth_int(rte->funccoltypmods, attnum - 1);
+ *varcollid = InvalidOid; // TODO
}
else
{
@@ -2084,6 +2089,7 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
col = (Node *) list_nth(collist, attnum - 1);
*vartype = exprType(col);
*vartypmod = exprTypmod(col);
+ *varcollid = exprColl(col);
}
break;
case RTE_JOIN:
@@ -2097,6 +2103,7 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
aliasvar = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
*vartype = exprType(aliasvar);
*vartypmod = exprTypmod(aliasvar);
+ *varcollid = exprColl(aliasvar);
}
break;
case RTE_CTE:
@@ -2105,6 +2112,7 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
Assert(attnum > 0 && attnum <= list_length(rte->ctecoltypes));
*vartype = list_nth_oid(rte->ctecoltypes, attnum - 1);
*vartypmod = list_nth_int(rte->ctecoltypmods, attnum - 1);
+ *varcollid = InvalidOid; // TODO
}
break;
default:
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index 8d0932b..7205738 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -15,8 +15,10 @@
#include "postgres.h"
#include "catalog/namespace.h"
+#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "lib/stringinfo.h"
+#include "mb/pg_wchar.h"
#include "nodes/makefuncs.h"
#include "parser/parser.h"
#include "parser/parse_type.h"
@@ -29,6 +31,8 @@
static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
Type typ);
+static Oid typenameCollation(ParseState *pstate, const TypeName *typeName,
+ Type typ);
/*
@@ -36,7 +40,8 @@ static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
* Given a TypeName object, lookup the pg_type syscache entry of the type.
* Returns NULL if no such type can be found. If the type is found,
* the typmod value represented in the TypeName struct is computed and
- * stored into *typmod_p.
+ * stored into *typmod_p, and the collation is looked up and stored into
+ * *colloid_p.
*
* NB: on success, the caller must ReleaseSysCache the type tuple when done
* with it.
@@ -51,15 +56,18 @@ static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
* found but is a shell, and there is typmod decoration, an error will be
* thrown --- this is intentional.
*
+ * colloid_p can also be null.
+ *
* pstate is only used for error location info, and may be NULL.
*/
Type
LookupTypeName(ParseState *pstate, const TypeName *typeName,
- int32 *typmod_p)
+ int32 *typmod_p, Oid *colloid_p)
{
Oid typoid;
HeapTuple tup;
int32 typmod;
+ Oid colloid;
if (typeName->names == NIL)
{
@@ -174,6 +182,11 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
if (typmod_p)
*typmod_p = typmod;
+ colloid = typenameCollation(pstate, typeName, (Type) tup);
+
+ if (colloid_p)
+ *colloid_p = colloid;
+
return (Type) tup;
}
@@ -185,11 +198,11 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
* Callers of this can therefore assume the result is a fully valid type.
*/
Type
-typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
+typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p, Oid *colloid_p)
{
Type tup;
- tup = LookupTypeName(pstate, typeName, typmod_p);
+ tup = LookupTypeName(pstate, typeName, typmod_p, colloid_p);
if (tup == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -212,12 +225,12 @@ typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
* not the syscache entry.
*/
Oid
-typenameTypeId(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
+typenameTypeId(ParseState *pstate, const TypeName *typeName, int32 *typmod_p, Oid *colloid_p)
{
Oid typoid;
Type tup;
- tup = typenameType(pstate, typeName, typmod_p);
+ tup = typenameType(pstate, typeName, typmod_p, colloid_p);
typoid = HeapTupleGetOid(tup);
ReleaseSysCache(tup);
@@ -334,6 +347,63 @@ typenameTypeMod(ParseState *pstate, const TypeName *typeName, Type typ)
}
/*
+ * typenameCollation - given a TypeName, return the collation OID
+ *
+ * This will throw an error if the TypeName includes a collation but
+ * the data type does not support collations.
+ *
+ * The actual type OID represented by the TypeName must already have been
+ * looked up, and is passed as "typ".
+ *
+ * pstate is only used for error location info, and may be NULL.
+ */
+static Oid
+typenameCollation(ParseState *pstate, const TypeName *typeName, Type typ)
+{
+ /* return prespecified collation OID if no collation name specified */
+ if (typeName->collnames == NIL)
+ return typeName->collOid;
+
+ if (!((Form_pg_type) GETSTRUCT(typ))->typcollatable)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("collations are not supported by type \"%s\"",
+ TypeNameToString(typeName)),
+ parser_errposition(pstate, typeName->location)));
+
+ return LookupCollation(pstate, typeName->collnames, typeName->location);
+}
+
+Oid
+LookupCollation(ParseState *pstate, List *collnames, int location)
+{
+ Oid colloid;
+ HeapTuple tup;
+
+ colloid = FindCollationByName(collnames);
+ if (!OidIsValid(colloid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("collation \"%s\" does not exist",
+ NameListToString(collnames))));
+
+ tup = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for collation %u", colloid);
+
+ if (((Form_pg_collation) GETSTRUCT(tup))->collencoding != GetDatabaseEncoding())
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("collation \"%s\" is not applicable to current database encoding \"%s\"",
+ NameListToString(collnames), GetDatabaseEncodingName()),
+ parser_errposition(pstate, location)));
+
+ ReleaseSysCache(tup);
+
+ return colloid;
+}
+
+/*
* appendTypeNameToBuffer
* Append a string representing the name of a TypeName to a StringInfo.
* This is the shared guts of TypeNameToString and TypeNameListToString.
@@ -635,7 +705,7 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod_p)
if (typeName->setof)
goto fail;
- *type_id = typenameTypeId(NULL, typeName, typmod_p);
+ *type_id = typenameTypeId(NULL, typeName, typmod_p, NULL);
pfree(buf.data);
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 90d5c76..7a1d616 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -809,7 +809,7 @@ transformOfType(ParseState *pstate, CreateStmtContext *cxt, TypeName *ofTypename
AssertArg(ofTypename);
- tuple = typenameType(NULL, ofTypename, NULL);
+ tuple = typenameType(NULL, ofTypename, NULL, NULL);
typ = (Form_pg_type) GETSTRUCT(tuple);
ofTypeId = HeapTupleGetOid(tuple);
ofTypename->typeOid = ofTypeId; /* cached for later */
@@ -2216,7 +2216,7 @@ transformColumnType(ParseState *pstate, ColumnDef *column)
/*
* All we really need to do here is verify that the type is valid.
*/
- Type ctype = typenameType(pstate, column->typeName, NULL);
+ Type ctype = typenameType(pstate, column->typeName, NULL, NULL);
ReleaseSysCache(ctype);
}
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index fc3c5b0..bfb062e 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -5480,11 +5480,11 @@ make_greater_string(const Const *str_const, FmgrInfo *ltproc)
char *best;
best = "Z";
- if (varstr_cmp(best, 1, "z", 1) < 0)
+ if (varstr_cmp(best, 1, "z", 1, InvalidOid) < 0)
best = "z";
- if (varstr_cmp(best, 1, "y", 1) < 0)
+ if (varstr_cmp(best, 1, "y", 1, InvalidOid) < 0)
best = "y";
- if (varstr_cmp(best, 1, "9", 1) < 0)
+ if (varstr_cmp(best, 1, "9", 1, InvalidOid) < 0)
best = "9";
suffixchar = *best;
}
diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c
index cbc08f7..4bec7af 100644
--- a/src/backend/utils/adt/varchar.c
+++ b/src/backend/utils/adt/varchar.c
@@ -737,7 +737,8 @@ bpcharlt(PG_FUNCTION_ARGS)
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
- cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2);
+ cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
+ PG_GET_COLLATION());
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
@@ -757,7 +758,8 @@ bpcharle(PG_FUNCTION_ARGS)
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
- cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2);
+ cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
+ PG_GET_COLLATION());
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
@@ -777,7 +779,8 @@ bpchargt(PG_FUNCTION_ARGS)
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
- cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2);
+ cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
+ PG_GET_COLLATION());
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
@@ -797,7 +800,8 @@ bpcharge(PG_FUNCTION_ARGS)
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
- cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2);
+ cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
+ PG_GET_COLLATION());
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
@@ -817,7 +821,8 @@ bpcharcmp(PG_FUNCTION_ARGS)
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
- cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2);
+ cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
+ PG_GET_COLLATION());
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
@@ -837,7 +842,8 @@ bpchar_larger(PG_FUNCTION_ARGS)
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
- cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2);
+ cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
+ PG_GET_COLLATION());
PG_RETURN_BPCHAR_P((cmp >= 0) ? arg1 : arg2);
}
@@ -854,7 +860,8 @@ bpchar_smaller(PG_FUNCTION_ARGS)
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
- cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2);
+ cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
+ PG_GET_COLLATION());
PG_RETURN_BPCHAR_P((cmp <= 0) ? arg1 : arg2);
}
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index af28c15..05fadb0 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -15,8 +15,10 @@
#include "postgres.h"
#include <ctype.h>
+#include <xlocale.h>
#include "access/tuptoaster.h"
+#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "libpq/md5.h"
#include "libpq/pqformat.h"
@@ -26,6 +28,7 @@
#include "utils/builtins.h"
#include "utils/bytea.h"
#include "utils/lsyscache.h"
+#include "utils/syscache.h"
#include "utils/pg_locale.h"
@@ -54,7 +57,7 @@ typedef struct
#define PG_GETARG_UNKNOWN_P_COPY(n) DatumGetUnknownPCopy(PG_GETARG_DATUM(n))
#define PG_RETURN_UNKNOWN_P(x) PG_RETURN_POINTER(x)
-static int text_cmp(text *arg1, text *arg2);
+static int text_cmp(text *arg1, text *arg2, Oid collid);
static int32 text_length(Datum str);
static int text_position(text *t1, text *t2);
static void text_position_setup(text *t1, text *t2, TextPositionState *state);
@@ -1267,7 +1270,7 @@ text_position_cleanup(TextPositionState *state)
* whether arg1 is less than, equal to, or greater than arg2.
*/
int
-varstr_cmp(char *arg1, int len1, char *arg2, int len2)
+varstr_cmp(char *arg1, int len1, char *arg2, int len2, Oid collid)
{
int result;
@@ -1277,7 +1280,7 @@ varstr_cmp(char *arg1, int len1, char *arg2, int len2)
* slower, so we optimize the case where LC_COLLATE is C. We also try to
* optimize relatively-short strings by avoiding palloc/pfree overhead.
*/
- if (lc_collate_is_c())
+ if (lc_collate_is_c() && !collid)
{
result = strncmp(arg1, arg2, Min(len1, len2));
if ((result == 0) && (len1 != len2))
@@ -1391,7 +1394,29 @@ varstr_cmp(char *arg1, int len1, char *arg2, int len2)
memcpy(a2p, arg2, len2);
a2p[len2] = '\0';
- result = strcoll(a1p, a2p);
+ if (!collid)
+ result = strcoll(a1p, a2p);
+ else
+ {
+ locale_t mylocale;
+ HeapTuple htup;
+ const char *lc_collate;
+
+ htup = SearchSysCache1(COLLOID, collid);
+ if (!HeapTupleIsValid(htup))
+ elog(ERROR, "cache lookup failed for collation %u", collid);
+
+ lc_collate = NameStr(((Form_pg_collation) GETSTRUCT(htup))->collcollate);
+
+ /* TODO: cache locale lookups */
+ mylocale = newlocale(LC_COLLATE_MASK, lc_collate, NULL);
+ if (!mylocale)
+ elog(ERROR, "could not create locale \"%s\"", lc_collate);
+ result = strcoll_l(a1p, a2p, mylocale);
+ freelocale(mylocale);
+
+ ReleaseSysCache(htup);
+ }
/*
* In some locales strcoll() can claim that nonidentical strings are
@@ -1417,7 +1442,7 @@ varstr_cmp(char *arg1, int len1, char *arg2, int len2)
* Returns -1, 0 or 1
*/
static int
-text_cmp(text *arg1, text *arg2)
+text_cmp(text *arg1, text *arg2, Oid collid)
{
char *a1p,
*a2p;
@@ -1430,7 +1455,7 @@ text_cmp(text *arg1, text *arg2)
len1 = VARSIZE_ANY_EXHDR(arg1);
len2 = VARSIZE_ANY_EXHDR(arg2);
- return varstr_cmp(a1p, len1, a2p, len2);
+ return varstr_cmp(a1p, len1, a2p, len2, collid);
}
/*
@@ -1494,7 +1519,7 @@ text_lt(PG_FUNCTION_ARGS)
text *arg2 = PG_GETARG_TEXT_PP(1);
bool result;
- result = (text_cmp(arg1, arg2) < 0);
+ result = (text_cmp(arg1, arg2, PG_GET_COLLATION()) < 0);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
@@ -1509,7 +1534,7 @@ text_le(PG_FUNCTION_ARGS)
text *arg2 = PG_GETARG_TEXT_PP(1);
bool result;
- result = (text_cmp(arg1, arg2) <= 0);
+ result = (text_cmp(arg1, arg2, PG_GET_COLLATION()) <= 0);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
@@ -1524,7 +1549,7 @@ text_gt(PG_FUNCTION_ARGS)
text *arg2 = PG_GETARG_TEXT_PP(1);
bool result;
- result = (text_cmp(arg1, arg2) > 0);
+ result = (text_cmp(arg1, arg2, PG_GET_COLLATION()) > 0);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
@@ -1539,7 +1564,7 @@ text_ge(PG_FUNCTION_ARGS)
text *arg2 = PG_GETARG_TEXT_PP(1);
bool result;
- result = (text_cmp(arg1, arg2) >= 0);
+ result = (text_cmp(arg1, arg2, PG_GET_COLLATION()) >= 0);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
@@ -1554,7 +1579,7 @@ bttextcmp(PG_FUNCTION_ARGS)
text *arg2 = PG_GETARG_TEXT_PP(1);
int32 result;
- result = text_cmp(arg1, arg2);
+ result = text_cmp(arg1, arg2, PG_GET_COLLATION());
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
@@ -1570,7 +1595,7 @@ text_larger(PG_FUNCTION_ARGS)
text *arg2 = PG_GETARG_TEXT_PP(1);
text *result;
- result = ((text_cmp(arg1, arg2) > 0) ? arg1 : arg2);
+ result = ((text_cmp(arg1, arg2, PG_GET_COLLATION()) > 0) ? arg1 : arg2);
PG_RETURN_TEXT_P(result);
}
@@ -1582,7 +1607,7 @@ text_smaller(PG_FUNCTION_ARGS)
text *arg2 = PG_GETARG_TEXT_PP(1);
text *result;
- result = ((text_cmp(arg1, arg2) < 0) ? arg1 : arg2);
+ result = ((text_cmp(arg1, arg2, PG_GET_COLLATION()) < 0) ? arg1 : arg2);
PG_RETURN_TEXT_P(result);
}
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index 61b06ac..8307beb 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -28,6 +28,7 @@
#include "catalog/pg_auth_members.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_cast.h"
+#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
@@ -266,6 +267,28 @@ static const struct cachedesc cacheinfo[] = {
},
64
},
+ {CollationRelationId, /* COLLNAMENSP */
+ CollationNameNspIndexId,
+ 2,
+ {
+ Anum_pg_collation_collname,
+ Anum_pg_collation_collnamespace,
+ 0,
+ 0
+ },
+ 128
+ },
+ {CollationRelationId, /* COLLOID */
+ CollationOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 128
+ },
{ConversionRelationId, /* CONDEFAULT */
ConversionDefaultIndexId,
4,
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index c3c0440..07479b6 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -2403,3 +2403,13 @@ get_call_expr_arg_stable(Node *expr, int argnum)
return false;
}
+
+/*
+ * Wrapper around exprColl() so that fmgr.h doesn't have to include
+ * the world.
+ */
+Oid
+get_call_collation(Node *expr)
+{
+ return exprColl(expr);
+}
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index e839639..62f2480 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -5573,7 +5573,7 @@ flatten_set_variable_args(const char *name, List *args)
Datum interval;
char *intervalout;
- typoid = typenameTypeId(NULL, typeName, &typmod);
+ typoid = typenameTypeId(NULL, typeName, &typmod, NULL);
Assert(typoid == INTERVALOID);
interval =
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index f40ad87..f4566bf 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -98,6 +98,7 @@ static char *shdesc_file;
static char *hba_file;
static char *ident_file;
static char *conf_file;
+static char *collation_file;
static char *conversion_file;
static char *dictionary_file;
static char *info_schema_file;
@@ -170,6 +171,7 @@ static void get_set_pwd(void);
static void setup_depend(void);
static void setup_sysviews(void);
static void setup_description(void);
+static void setup_collation(void);
static void setup_conversion(void);
static void setup_dictionary(void);
static void setup_privileges(void);
@@ -1653,6 +1655,45 @@ setup_description(void)
}
/*
+ * populate pg_collation
+ */
+static void
+setup_collation(void)
+{
+ PG_CMD_DECL;
+
+ fputs(_("creating collations ..."), stdout);
+ fflush(stdout);
+
+ snprintf(cmd, sizeof(cmd),
+ "\"%s\" %s template1 >%s",
+ backend_exec, backend_options,
+ DEVNULL);
+
+ PG_CMD_OPEN;
+
+ PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_collation ( "
+ " locale name, "
+ " encoding text) WITHOUT OIDS;\n");
+
+ PG_CMD_PRINTF1("COPY tmp_pg_collation FROM E'%s';\n",
+ escape_quotes(collation_file));
+
+ PG_CMD_PUTS("INSERT INTO pg_collation (collname, collnamespace, collencoding, collcollate, collctype) "
+ " SELECT locale, "
+ " (SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog'), "
+ " pg_char_to_encoding(encoding), "
+ " locale, locale "
+ " FROM tmp_pg_collation "
+ " WHERE pg_char_to_encoding(encoding) <> -1;\n");
+
+ PG_CMD_CLOSE;
+
+ check_ok();
+
+}
+
+/*
* load conversion functions
*/
static void
@@ -2761,6 +2802,7 @@ main(int argc, char *argv[])
set_input(&hba_file, "pg_hba.conf.sample");
set_input(&ident_file, "pg_ident.conf.sample");
set_input(&conf_file, "postgresql.conf.sample");
+ set_input(&collation_file, "locales.txt");
set_input(&conversion_file, "conversion_create.sql");
set_input(&dictionary_file, "snowball_create.sql");
set_input(&info_schema_file, "information_schema.sql");
@@ -2794,6 +2836,7 @@ main(int argc, char *argv[])
check_input(hba_file);
check_input(ident_file);
check_input(conf_file);
+ check_input(collation_file);
check_input(conversion_file);
check_input(dictionary_file);
check_input(info_schema_file);
@@ -3109,6 +3152,8 @@ main(int argc, char *argv[])
setup_description();
+ setup_collation();
+
setup_conversion();
setup_dictionary();
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 4f7d920..6242812 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201004261
+#define CATALOG_VERSION_NO 201007071
#endif
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index 4f437fd..8060652 100644
--- a/src/include/catalog/indexing.h
+++ b/src/include/catalog/indexing.h
@@ -107,6 +107,11 @@ DECLARE_UNIQUE_INDEX(pg_class_oid_index, 2662, on pg_class using btree(oid oid_o
DECLARE_UNIQUE_INDEX(pg_class_relname_nsp_index, 2663, on pg_class using btree(relname name_ops, relnamespace oid_ops));
#define ClassNameNspIndexId 2663
+DECLARE_UNIQUE_INDEX(pg_collation_name_nsp_index, 3037, on pg_collation using btree(collname name_ops, collnamespace oid_ops));
+#define CollationNameNspIndexId 3037
+DECLARE_UNIQUE_INDEX(pg_collation_oid_index, 3038, on pg_collation using btree(oid oid_ops));
+#define CollationOidIndexId 3038
+
/* This following index is not used for a cache and is not unique */
DECLARE_INDEX(pg_constraint_conname_nsp_index, 2664, on pg_constraint using btree(conname name_ops, connamespace oid_ops));
#define ConstraintNameNspIndexId 2664
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index fe3b783..541728f 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -111,6 +111,7 @@ extern OverrideSearchPath *GetOverrideSearchPath(MemoryContext context);
extern void PushOverrideSearchPath(OverrideSearchPath *newpath);
extern void PopOverrideSearchPath(void);
+extern Oid FindCollationByName(List *collname);
extern Oid FindConversionByName(List *conname);
extern Oid FindDefaultConversionProc(int4 for_encoding, int4 to_encoding);
diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h
index 078cae4..6d14bfb 100644
--- a/src/include/catalog/pg_attribute.h
+++ b/src/include/catalog/pg_attribute.h
@@ -142,6 +142,9 @@ CATALOG(pg_attribute,1249) BKI_BOOTSTRAP BKI_WITHOUT_OIDS BKI_ROWTYPE_OID(75) BK
/* Number of times inherited from direct parent relation(s) */
int4 attinhcount;
+ /* attribute's collation */
+ Oid attcollation;
+
/*
* VARIABLE LENGTH FIELDS start here. These fields may be NULL, too.
*
@@ -159,10 +162,10 @@ CATALOG(pg_attribute,1249) BKI_BOOTSTRAP BKI_WITHOUT_OIDS BKI_ROWTYPE_OID(75) BK
* ATTRIBUTE_FIXED_PART_SIZE is the size of the fixed-layout,
* guaranteed-not-null part of a pg_attribute row. This is in fact as much
* of the row as gets copied into tuple descriptors, so don't expect you
- * can access fields beyond attinhcount except in a real tuple!
+ * can access fields beyond attcollation except in a real tuple!
*/
#define ATTRIBUTE_FIXED_PART_SIZE \
- (offsetof(FormData_pg_attribute,attinhcount) + sizeof(int4))
+ (offsetof(FormData_pg_attribute,attcollation) + sizeof(Oid))
/* ----------------
* Form_pg_attribute corresponds to a pointer to a tuple with
@@ -176,7 +179,7 @@ typedef FormData_pg_attribute *Form_pg_attribute;
* ----------------
*/
-#define Natts_pg_attribute 19
+#define Natts_pg_attribute 20
#define Anum_pg_attribute_attrelid 1
#define Anum_pg_attribute_attname 2
#define Anum_pg_attribute_atttypid 3
@@ -194,8 +197,9 @@ typedef FormData_pg_attribute *Form_pg_attribute;
#define Anum_pg_attribute_attisdropped 15
#define Anum_pg_attribute_attislocal 16
#define Anum_pg_attribute_attinhcount 17
-#define Anum_pg_attribute_attacl 18
-#define Anum_pg_attribute_attoptions 19
+#define Anum_pg_attribute_attcollation 18
+#define Anum_pg_attribute_attacl 19
+#define Anum_pg_attribute_attoptions 20
/* ----------------
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index 5ea514d..1b64c14 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -132,9 +132,9 @@ typedef FormData_pg_class *Form_pg_class;
*/
/* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
-DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f f r 28 0 t f f f f f 3 _null_ _null_ ));
+DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f f r 29 0 t f f f f f 3 _null_ _null_ ));
DESCR("");
-DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f f r 19 0 f f f f f f 3 _null_ _null_ ));
+DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f f r 20 0 f f f f f f 3 _null_ _null_ ));
DESCR("");
DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f f r 25 0 t f f f f f 3 _null_ _null_ ));
DESCR("");
diff --git a/src/include/catalog/pg_collation.h b/src/include/catalog/pg_collation.h
new file mode 100644
index 0000000..cf7c9a5
--- /dev/null
+++ b/src/include/catalog/pg_collation.h
@@ -0,0 +1,58 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_collation.h
+ * definition of the system "collation" relation (pg_collation)
+ * along with the relation's initial contents.
+ *
+ *
+ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL$
+ *
+ * NOTES
+ * the genbki.pl script reads this file and generates .bki
+ * information from the DATA() statements.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_COLLATION_H
+#define PG_COLLATION_H
+
+#include "catalog/genbki.h"
+
+/* ----------------
+ * pg_collation definition. cpp turns this into
+ * typedef struct FormData_pg_collation
+ * ----------------
+ */
+#define CollationRelationId 2614
+
+CATALOG(pg_collation,2614)
+{
+ NameData collname; /* collation name */
+ Oid collnamespace; /* OID of namespace containing this collation */
+ int4 collencoding; /* encoding that this collation applies to */
+ NameData collcollate; /* LC_COLLATE setting */
+ NameData collctype; /* LC_CTYPE setting */
+} FormData_pg_collation;
+
+/* ----------------
+ * Form_pg_collation corresponds to a pointer to a row with
+ * the format of pg_collation relation.
+ * ----------------
+ */
+typedef FormData_pg_collation *Form_pg_collation;
+
+/* ----------------
+ * compiler constants for pg_collation
+ * ----------------
+ */
+#define Natts_pg_collation 5
+#define Anum_pg_collation_collname 1
+#define Anum_pg_collation_collnamespace 2
+#define Anum_pg_collation_collencoding 3
+#define Anum_pg_collation_collcollate 4
+#define Anum_pg_collation_collctype 5
+
+#endif /* PG_COLLATION_H */
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index c22aacc..9828a50 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -175,6 +175,11 @@ CATALOG(pg_type,1247) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71) BKI_SCHEMA_MACRO
bool typnotnull;
/*
+ * Type can use collations.
+ */
+ bool typcollatable;
+
+ /*
* Domains use typbasetype to show the base (or domain) type that the
* domain is based on. Zero if the type is not a domain.
*/
@@ -224,7 +229,7 @@ typedef FormData_pg_type *Form_pg_type;
* compiler constants for pg_type
* ----------------
*/
-#define Natts_pg_type 28
+#define Natts_pg_type 29
#define Anum_pg_type_typname 1
#define Anum_pg_type_typnamespace 2
#define Anum_pg_type_typowner 3
@@ -248,11 +253,12 @@ typedef FormData_pg_type *Form_pg_type;
#define Anum_pg_type_typalign 21
#define Anum_pg_type_typstorage 22
#define Anum_pg_type_typnotnull 23
-#define Anum_pg_type_typbasetype 24
-#define Anum_pg_type_typtypmod 25
-#define Anum_pg_type_typndims 26
-#define Anum_pg_type_typdefaultbin 27
-#define Anum_pg_type_typdefault 28
+#define Anum_pg_type_typcollatable 24
+#define Anum_pg_type_typbasetype 25
+#define Anum_pg_type_typtypmod 26
+#define Anum_pg_type_typndims 27
+#define Anum_pg_type_typdefaultbin 28
+#define Anum_pg_type_typdefault 29
/* ----------------
@@ -269,83 +275,83 @@ typedef FormData_pg_type *Form_pg_type;
*/
/* OIDS 1 - 99 */
-DATA(insert OID = 16 ( bool PGNSP PGUID 1 t b B t t \054 0 0 1000 boolin boolout boolrecv boolsend - - - c p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 16 ( bool PGNSP PGUID 1 t b B t t \054 0 0 1000 boolin boolout boolrecv boolsend - - - c p f f 0 -1 0 _null_ _null_ ));
DESCR("boolean, 'true'/'false'");
#define BOOLOID 16
-DATA(insert OID = 17 ( bytea PGNSP PGUID -1 f b U f t \054 0 0 1001 byteain byteaout bytearecv byteasend - - - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 17 ( bytea PGNSP PGUID -1 f b U f t \054 0 0 1001 byteain byteaout bytearecv byteasend - - - i x f f 0 -1 0 _null_ _null_ ));
DESCR("variable-length string, binary values escaped");
#define BYTEAOID 17
-DATA(insert OID = 18 ( char PGNSP PGUID 1 t b S f t \054 0 0 1002 charin charout charrecv charsend - - - c p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 18 ( char PGNSP PGUID 1 t b S f t \054 0 0 1002 charin charout charrecv charsend - - - c p f f 0 -1 0 _null_ _null_ ));
DESCR("single character");
#define CHAROID 18
-DATA(insert OID = 19 ( name PGNSP PGUID NAMEDATALEN f b S f t \054 0 18 1003 namein nameout namerecv namesend - - - c p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 19 ( name PGNSP PGUID NAMEDATALEN f b S f t \054 0 18 1003 namein nameout namerecv namesend - - - c p f f 0 -1 0 _null_ _null_ ));
DESCR("63-character type for storing system identifiers");
#define NAMEOID 19
-DATA(insert OID = 20 ( int8 PGNSP PGUID 8 FLOAT8PASSBYVAL b N f t \054 0 0 1016 int8in int8out int8recv int8send - - - d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 20 ( int8 PGNSP PGUID 8 FLOAT8PASSBYVAL b N f t \054 0 0 1016 int8in int8out int8recv int8send - - - d p f f 0 -1 0 _null_ _null_ ));
DESCR("~18 digit integer, 8-byte storage");
#define INT8OID 20
-DATA(insert OID = 21 ( int2 PGNSP PGUID 2 t b N f t \054 0 0 1005 int2in int2out int2recv int2send - - - s p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 21 ( int2 PGNSP PGUID 2 t b N f t \054 0 0 1005 int2in int2out int2recv int2send - - - s p f f 0 -1 0 _null_ _null_ ));
DESCR("-32 thousand to 32 thousand, 2-byte storage");
#define INT2OID 21
-DATA(insert OID = 22 ( int2vector PGNSP PGUID -1 f b A f t \054 0 21 1006 int2vectorin int2vectorout int2vectorrecv int2vectorsend - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 22 ( int2vector PGNSP PGUID -1 f b A f t \054 0 21 1006 int2vectorin int2vectorout int2vectorrecv int2vectorsend - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("array of int2, used in system tables");
#define INT2VECTOROID 22
-DATA(insert OID = 23 ( int4 PGNSP PGUID 4 t b N f t \054 0 0 1007 int4in int4out int4recv int4send - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 23 ( int4 PGNSP PGUID 4 t b N f t \054 0 0 1007 int4in int4out int4recv int4send - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("-2 billion to 2 billion integer, 4-byte storage");
#define INT4OID 23
-DATA(insert OID = 24 ( regproc PGNSP PGUID 4 t b N f t \054 0 0 1008 regprocin regprocout regprocrecv regprocsend - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 24 ( regproc PGNSP PGUID 4 t b N f t \054 0 0 1008 regprocin regprocout regprocrecv regprocsend - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("registered procedure");
#define REGPROCOID 24
-DATA(insert OID = 25 ( text PGNSP PGUID -1 f b S t t \054 0 0 1009 textin textout textrecv textsend - - - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 25 ( text PGNSP PGUID -1 f b S t t \054 0 0 1009 textin textout textrecv textsend - - - i x f t 0 -1 0 _null_ _null_ ));
DESCR("variable-length string, no limit specified");
#define TEXTOID 25
-DATA(insert OID = 26 ( oid PGNSP PGUID 4 t b N t t \054 0 0 1028 oidin oidout oidrecv oidsend - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 26 ( oid PGNSP PGUID 4 t b N t t \054 0 0 1028 oidin oidout oidrecv oidsend - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("object identifier(oid), maximum 4 billion");
#define OIDOID 26
-DATA(insert OID = 27 ( tid PGNSP PGUID 6 f b U f t \054 0 0 1010 tidin tidout tidrecv tidsend - - - s p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 27 ( tid PGNSP PGUID 6 f b U f t \054 0 0 1010 tidin tidout tidrecv tidsend - - - s p f f 0 -1 0 _null_ _null_ ));
DESCR("(block, offset), physical location of tuple");
#define TIDOID 27
-DATA(insert OID = 28 ( xid PGNSP PGUID 4 t b U f t \054 0 0 1011 xidin xidout xidrecv xidsend - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 28 ( xid PGNSP PGUID 4 t b U f t \054 0 0 1011 xidin xidout xidrecv xidsend - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("transaction id");
#define XIDOID 28
-DATA(insert OID = 29 ( cid PGNSP PGUID 4 t b U f t \054 0 0 1012 cidin cidout cidrecv cidsend - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 29 ( cid PGNSP PGUID 4 t b U f t \054 0 0 1012 cidin cidout cidrecv cidsend - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("command identifier type, sequence in transaction id");
#define CIDOID 29
-DATA(insert OID = 30 ( oidvector PGNSP PGUID -1 f b A f t \054 0 26 1013 oidvectorin oidvectorout oidvectorrecv oidvectorsend - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 30 ( oidvector PGNSP PGUID -1 f b A f t \054 0 26 1013 oidvectorin oidvectorout oidvectorrecv oidvectorsend - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("array of oids, used in system tables");
#define OIDVECTOROID 30
/* hand-built rowtype entries for bootstrapped catalogs */
/* NB: OIDs assigned here must match the BKI_ROWTYPE_OID declarations */
-DATA(insert OID = 71 ( pg_type PGNSP PGUID -1 f c C f t \054 1247 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 75 ( pg_attribute PGNSP PGUID -1 f c C f t \054 1249 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 81 ( pg_proc PGNSP PGUID -1 f c C f t \054 1255 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 83 ( pg_class PGNSP PGUID -1 f c C f t \054 1259 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 71 ( pg_type PGNSP PGUID -1 f c C f t \054 1247 0 0 record_in record_out record_recv record_send - - - d x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 75 ( pg_attribute PGNSP PGUID -1 f c C f t \054 1249 0 0 record_in record_out record_recv record_send - - - d x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 81 ( pg_proc PGNSP PGUID -1 f c C f t \054 1255 0 0 record_in record_out record_recv record_send - - - d x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 83 ( pg_class PGNSP PGUID -1 f c C f t \054 1259 0 0 record_in record_out record_recv record_send - - - d x f f 0 -1 0 _null_ _null_ ));
/* OIDS 100 - 199 */
-DATA(insert OID = 142 ( xml PGNSP PGUID -1 f b U f t \054 0 0 143 xml_in xml_out xml_recv xml_send - - - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 142 ( xml PGNSP PGUID -1 f b U f t \054 0 0 143 xml_in xml_out xml_recv xml_send - - - i x f f 0 -1 0 _null_ _null_ ));
DESCR("XML content");
#define XMLOID 142
-DATA(insert OID = 143 ( _xml PGNSP PGUID -1 f b A f t \054 0 142 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 143 ( _xml PGNSP PGUID -1 f b A f t \054 0 142 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
/* OIDS 200 - 299 */
-DATA(insert OID = 210 ( smgr PGNSP PGUID 2 t b U f t \054 0 0 0 smgrin smgrout - - - - - s p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 210 ( smgr PGNSP PGUID 2 t b U f t \054 0 0 0 smgrin smgrout - - - - - s p f f 0 -1 0 _null_ _null_ ));
DESCR("storage manager");
/* OIDS 300 - 399 */
@@ -355,231 +361,231 @@ DESCR("storage manager");
/* OIDS 500 - 599 */
/* OIDS 600 - 699 */
-DATA(insert OID = 600 ( point PGNSP PGUID 16 f b G f t \054 0 701 1017 point_in point_out point_recv point_send - - - d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 600 ( point PGNSP PGUID 16 f b G f t \054 0 701 1017 point_in point_out point_recv point_send - - - d p f f 0 -1 0 _null_ _null_ ));
DESCR("geometric point '(x, y)'");
#define POINTOID 600
-DATA(insert OID = 601 ( lseg PGNSP PGUID 32 f b G f t \054 0 600 1018 lseg_in lseg_out lseg_recv lseg_send - - - d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 601 ( lseg PGNSP PGUID 32 f b G f t \054 0 600 1018 lseg_in lseg_out lseg_recv lseg_send - - - d p f f 0 -1 0 _null_ _null_ ));
DESCR("geometric line segment '(pt1,pt2)'");
#define LSEGOID 601
-DATA(insert OID = 602 ( path PGNSP PGUID -1 f b G f t \054 0 0 1019 path_in path_out path_recv path_send - - - d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 602 ( path PGNSP PGUID -1 f b G f t \054 0 0 1019 path_in path_out path_recv path_send - - - d x f f 0 -1 0 _null_ _null_ ));
DESCR("geometric path '(pt1,...)'");
#define PATHOID 602
-DATA(insert OID = 603 ( box PGNSP PGUID 32 f b G f t \073 0 600 1020 box_in box_out box_recv box_send - - - d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 603 ( box PGNSP PGUID 32 f b G f t \073 0 600 1020 box_in box_out box_recv box_send - - - d p f f 0 -1 0 _null_ _null_ ));
DESCR("geometric box '(lower left,upper right)'");
#define BOXOID 603
-DATA(insert OID = 604 ( polygon PGNSP PGUID -1 f b G f t \054 0 0 1027 poly_in poly_out poly_recv poly_send - - - d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 604 ( polygon PGNSP PGUID -1 f b G f t \054 0 0 1027 poly_in poly_out poly_recv poly_send - - - d x f f 0 -1 0 _null_ _null_ ));
DESCR("geometric polygon '(pt1,...)'");
#define POLYGONOID 604
-DATA(insert OID = 628 ( line PGNSP PGUID 32 f b G f t \054 0 701 629 line_in line_out line_recv line_send - - - d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 628 ( line PGNSP PGUID 32 f b G f t \054 0 701 629 line_in line_out line_recv line_send - - - d p f f 0 -1 0 _null_ _null_ ));
DESCR("geometric line (not implemented)");
#define LINEOID 628
-DATA(insert OID = 629 ( _line PGNSP PGUID -1 f b A f t \054 0 628 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 629 ( _line PGNSP PGUID -1 f b A f t \054 0 628 0 array_in array_out array_recv array_send - - - d x f f 0 -1 0 _null_ _null_ ));
DESCR("");
/* OIDS 700 - 799 */
-DATA(insert OID = 700 ( float4 PGNSP PGUID 4 FLOAT4PASSBYVAL b N f t \054 0 0 1021 float4in float4out float4recv float4send - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 700 ( float4 PGNSP PGUID 4 FLOAT4PASSBYVAL b N f t \054 0 0 1021 float4in float4out float4recv float4send - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("single-precision floating point number, 4-byte storage");
#define FLOAT4OID 700
-DATA(insert OID = 701 ( float8 PGNSP PGUID 8 FLOAT8PASSBYVAL b N t t \054 0 0 1022 float8in float8out float8recv float8send - - - d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 701 ( float8 PGNSP PGUID 8 FLOAT8PASSBYVAL b N t t \054 0 0 1022 float8in float8out float8recv float8send - - - d p f f 0 -1 0 _null_ _null_ ));
DESCR("double-precision floating point number, 8-byte storage");
#define FLOAT8OID 701
-DATA(insert OID = 702 ( abstime PGNSP PGUID 4 t b D f t \054 0 0 1023 abstimein abstimeout abstimerecv abstimesend - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 702 ( abstime PGNSP PGUID 4 t b D f t \054 0 0 1023 abstimein abstimeout abstimerecv abstimesend - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("absolute, limited-range date and time (Unix system time)");
#define ABSTIMEOID 702
-DATA(insert OID = 703 ( reltime PGNSP PGUID 4 t b T f t \054 0 0 1024 reltimein reltimeout reltimerecv reltimesend - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 703 ( reltime PGNSP PGUID 4 t b T f t \054 0 0 1024 reltimein reltimeout reltimerecv reltimesend - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("relative, limited-range time interval (Unix delta time)");
#define RELTIMEOID 703
-DATA(insert OID = 704 ( tinterval PGNSP PGUID 12 f b T f t \054 0 0 1025 tintervalin tintervalout tintervalrecv tintervalsend - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 704 ( tinterval PGNSP PGUID 12 f b T f t \054 0 0 1025 tintervalin tintervalout tintervalrecv tintervalsend - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("(abstime,abstime), time interval");
#define TINTERVALOID 704
-DATA(insert OID = 705 ( unknown PGNSP PGUID -2 f b X f t \054 0 0 0 unknownin unknownout unknownrecv unknownsend - - - c p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 705 ( unknown PGNSP PGUID -2 f b X f t \054 0 0 0 unknownin unknownout unknownrecv unknownsend - - - c p f f 0 -1 0 _null_ _null_ ));
DESCR("");
#define UNKNOWNOID 705
-DATA(insert OID = 718 ( circle PGNSP PGUID 24 f b G f t \054 0 0 719 circle_in circle_out circle_recv circle_send - - - d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 718 ( circle PGNSP PGUID 24 f b G f t \054 0 0 719 circle_in circle_out circle_recv circle_send - - - d p f f 0 -1 0 _null_ _null_ ));
DESCR("geometric circle '(center,radius)'");
#define CIRCLEOID 718
-DATA(insert OID = 719 ( _circle PGNSP PGUID -1 f b A f t \054 0 718 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 790 ( money PGNSP PGUID 8 FLOAT8PASSBYVAL b N f t \054 0 0 791 cash_in cash_out cash_recv cash_send - - - d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 719 ( _circle PGNSP PGUID -1 f b A f t \054 0 718 0 array_in array_out array_recv array_send - - - d x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 790 ( money PGNSP PGUID 8 FLOAT8PASSBYVAL b N f t \054 0 0 791 cash_in cash_out cash_recv cash_send - - - d p f f 0 -1 0 _null_ _null_ ));
DESCR("monetary amounts, $d,ddd.cc");
#define CASHOID 790
-DATA(insert OID = 791 ( _money PGNSP PGUID -1 f b A f t \054 0 790 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 791 ( _money PGNSP PGUID -1 f b A f t \054 0 790 0 array_in array_out array_recv array_send - - - d x f f 0 -1 0 _null_ _null_ ));
/* OIDS 800 - 899 */
-DATA(insert OID = 829 ( macaddr PGNSP PGUID 6 f b U f t \054 0 0 1040 macaddr_in macaddr_out macaddr_recv macaddr_send - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 829 ( macaddr PGNSP PGUID 6 f b U f t \054 0 0 1040 macaddr_in macaddr_out macaddr_recv macaddr_send - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("XX:XX:XX:XX:XX:XX, MAC address");
#define MACADDROID 829
-DATA(insert OID = 869 ( inet PGNSP PGUID -1 f b I t t \054 0 0 1041 inet_in inet_out inet_recv inet_send - - - i m f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 869 ( inet PGNSP PGUID -1 f b I t t \054 0 0 1041 inet_in inet_out inet_recv inet_send - - - i m f f 0 -1 0 _null_ _null_ ));
DESCR("IP address/netmask, host address, netmask optional");
#define INETOID 869
-DATA(insert OID = 650 ( cidr PGNSP PGUID -1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 650 ( cidr PGNSP PGUID -1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f f 0 -1 0 _null_ _null_ ));
DESCR("network IP address/netmask, network address");
#define CIDROID 650
/* OIDS 900 - 999 */
/* OIDS 1000 - 1099 */
-DATA(insert OID = 1000 ( _bool PGNSP PGUID -1 f b A f t \054 0 16 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1001 ( _bytea PGNSP PGUID -1 f b A f t \054 0 17 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1002 ( _char PGNSP PGUID -1 f b A f t \054 0 18 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1003 ( _name PGNSP PGUID -1 f b A f t \054 0 19 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1005 ( _int2 PGNSP PGUID -1 f b A f t \054 0 21 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1006 ( _int2vector PGNSP PGUID -1 f b A f t \054 0 22 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1007 ( _int4 PGNSP PGUID -1 f b A f t \054 0 23 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1000 ( _bool PGNSP PGUID -1 f b A f t \054 0 16 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1001 ( _bytea PGNSP PGUID -1 f b A f t \054 0 17 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1002 ( _char PGNSP PGUID -1 f b A f t \054 0 18 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1003 ( _name PGNSP PGUID -1 f b A f t \054 0 19 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1005 ( _int2 PGNSP PGUID -1 f b A f t \054 0 21 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1006 ( _int2vector PGNSP PGUID -1 f b A f t \054 0 22 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1007 ( _int4 PGNSP PGUID -1 f b A f t \054 0 23 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
#define INT4ARRAYOID 1007
-DATA(insert OID = 1008 ( _regproc PGNSP PGUID -1 f b A f t \054 0 24 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1009 ( _text PGNSP PGUID -1 f b A f t \054 0 25 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1008 ( _regproc PGNSP PGUID -1 f b A f t \054 0 24 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1009 ( _text PGNSP PGUID -1 f b A f t \054 0 25 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
#define TEXTARRAYOID 1009
-DATA(insert OID = 1028 ( _oid PGNSP PGUID -1 f b A f t \054 0 26 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1010 ( _tid PGNSP PGUID -1 f b A f t \054 0 27 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1011 ( _xid PGNSP PGUID -1 f b A f t \054 0 28 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1012 ( _cid PGNSP PGUID -1 f b A f t \054 0 29 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1013 ( _oidvector PGNSP PGUID -1 f b A f t \054 0 30 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1014 ( _bpchar PGNSP PGUID -1 f b A f t \054 0 1042 0 array_in array_out array_recv array_send bpchartypmodin bpchartypmodout - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1015 ( _varchar PGNSP PGUID -1 f b A f t \054 0 1043 0 array_in array_out array_recv array_send varchartypmodin varchartypmodout - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1016 ( _int8 PGNSP PGUID -1 f b A f t \054 0 20 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1017 ( _point PGNSP PGUID -1 f b A f t \054 0 600 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1018 ( _lseg PGNSP PGUID -1 f b A f t \054 0 601 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1019 ( _path PGNSP PGUID -1 f b A f t \054 0 602 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1020 ( _box PGNSP PGUID -1 f b A f t \073 0 603 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1021 ( _float4 PGNSP PGUID -1 f b A f t \054 0 700 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1028 ( _oid PGNSP PGUID -1 f b A f t \054 0 26 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1010 ( _tid PGNSP PGUID -1 f b A f t \054 0 27 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1011 ( _xid PGNSP PGUID -1 f b A f t \054 0 28 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1012 ( _cid PGNSP PGUID -1 f b A f t \054 0 29 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1013 ( _oidvector PGNSP PGUID -1 f b A f t \054 0 30 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1014 ( _bpchar PGNSP PGUID -1 f b A f t \054 0 1042 0 array_in array_out array_recv array_send bpchartypmodin bpchartypmodout - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1015 ( _varchar PGNSP PGUID -1 f b A f t \054 0 1043 0 array_in array_out array_recv array_send varchartypmodin varchartypmodout - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1016 ( _int8 PGNSP PGUID -1 f b A f t \054 0 20 0 array_in array_out array_recv array_send - - - d x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1017 ( _point PGNSP PGUID -1 f b A f t \054 0 600 0 array_in array_out array_recv array_send - - - d x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1018 ( _lseg PGNSP PGUID -1 f b A f t \054 0 601 0 array_in array_out array_recv array_send - - - d x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1019 ( _path PGNSP PGUID -1 f b A f t \054 0 602 0 array_in array_out array_recv array_send - - - d x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1020 ( _box PGNSP PGUID -1 f b A f t \073 0 603 0 array_in array_out array_recv array_send - - - d x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1021 ( _float4 PGNSP PGUID -1 f b A f t \054 0 700 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
#define FLOAT4ARRAYOID 1021
-DATA(insert OID = 1022 ( _float8 PGNSP PGUID -1 f b A f t \054 0 701 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1023 ( _abstime PGNSP PGUID -1 f b A f t \054 0 702 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1024 ( _reltime PGNSP PGUID -1 f b A f t \054 0 703 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1025 ( _tinterval PGNSP PGUID -1 f b A f t \054 0 704 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1027 ( _polygon PGNSP PGUID -1 f b A f t \054 0 604 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1033 ( aclitem PGNSP PGUID 12 f b U f t \054 0 0 1034 aclitemin aclitemout - - - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1022 ( _float8 PGNSP PGUID -1 f b A f t \054 0 701 0 array_in array_out array_recv array_send - - - d x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1023 ( _abstime PGNSP PGUID -1 f b A f t \054 0 702 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1024 ( _reltime PGNSP PGUID -1 f b A f t \054 0 703 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1025 ( _tinterval PGNSP PGUID -1 f b A f t \054 0 704 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1027 ( _polygon PGNSP PGUID -1 f b A f t \054 0 604 0 array_in array_out array_recv array_send - - - d x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1033 ( aclitem PGNSP PGUID 12 f b U f t \054 0 0 1034 aclitemin aclitemout - - - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("access control list");
#define ACLITEMOID 1033
-DATA(insert OID = 1034 ( _aclitem PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1040 ( _macaddr PGNSP PGUID -1 f b A f t \054 0 829 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1041 ( _inet PGNSP PGUID -1 f b A f t \054 0 869 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 651 ( _cidr PGNSP PGUID -1 f b A f t \054 0 650 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1263 ( _cstring PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1034 ( _aclitem PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1040 ( _macaddr PGNSP PGUID -1 f b A f t \054 0 829 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1041 ( _inet PGNSP PGUID -1 f b A f t \054 0 869 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 651 ( _cidr PGNSP PGUID -1 f b A f t \054 0 650 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1263 ( _cstring PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
#define CSTRINGARRAYOID 1263
-DATA(insert OID = 1042 ( bpchar PGNSP PGUID -1 f b S f t \054 0 0 1014 bpcharin bpcharout bpcharrecv bpcharsend bpchartypmodin bpchartypmodout - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1042 ( bpchar PGNSP PGUID -1 f b S f t \054 0 0 1014 bpcharin bpcharout bpcharrecv bpcharsend bpchartypmodin bpchartypmodout - i x f t 0 -1 0 _null_ _null_ ));
DESCR("char(length), blank-padded string, fixed storage length");
#define BPCHAROID 1042
-DATA(insert OID = 1043 ( varchar PGNSP PGUID -1 f b S f t \054 0 0 1015 varcharin varcharout varcharrecv varcharsend varchartypmodin varchartypmodout - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1043 ( varchar PGNSP PGUID -1 f b S f t \054 0 0 1015 varcharin varcharout varcharrecv varcharsend varchartypmodin varchartypmodout - i x f t 0 -1 0 _null_ _null_ ));
DESCR("varchar(length), non-blank-padded string, variable storage length");
#define VARCHAROID 1043
-DATA(insert OID = 1082 ( date PGNSP PGUID 4 t b D f t \054 0 0 1182 date_in date_out date_recv date_send - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1082 ( date PGNSP PGUID 4 t b D f t \054 0 0 1182 date_in date_out date_recv date_send - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("date");
#define DATEOID 1082
-DATA(insert OID = 1083 ( time PGNSP PGUID 8 FLOAT8PASSBYVAL b D f t \054 0 0 1183 time_in time_out time_recv time_send timetypmodin timetypmodout - d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1083 ( time PGNSP PGUID 8 FLOAT8PASSBYVAL b D f t \054 0 0 1183 time_in time_out time_recv time_send timetypmodin timetypmodout - d p f f 0 -1 0 _null_ _null_ ));
DESCR("time of day");
#define TIMEOID 1083
/* OIDS 1100 - 1199 */
-DATA(insert OID = 1114 ( timestamp PGNSP PGUID 8 FLOAT8PASSBYVAL b D f t \054 0 0 1115 timestamp_in timestamp_out timestamp_recv timestamp_send timestamptypmodin timestamptypmodout - d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1114 ( timestamp PGNSP PGUID 8 FLOAT8PASSBYVAL b D f t \054 0 0 1115 timestamp_in timestamp_out timestamp_recv timestamp_send timestamptypmodin timestamptypmodout - d p f f 0 -1 0 _null_ _null_ ));
DESCR("date and time");
#define TIMESTAMPOID 1114
-DATA(insert OID = 1115 ( _timestamp PGNSP PGUID -1 f b A f t \054 0 1114 0 array_in array_out array_recv array_send timestamptypmodin timestamptypmodout - d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1182 ( _date PGNSP PGUID -1 f b A f t \054 0 1082 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1183 ( _time PGNSP PGUID -1 f b A f t \054 0 1083 0 array_in array_out array_recv array_send timetypmodin timetypmodout - d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1184 ( timestamptz PGNSP PGUID 8 FLOAT8PASSBYVAL b D t t \054 0 0 1185 timestamptz_in timestamptz_out timestamptz_recv timestamptz_send timestamptztypmodin timestamptztypmodout - d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1115 ( _timestamp PGNSP PGUID -1 f b A f t \054 0 1114 0 array_in array_out array_recv array_send timestamptypmodin timestamptypmodout - d x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1182 ( _date PGNSP PGUID -1 f b A f t \054 0 1082 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1183 ( _time PGNSP PGUID -1 f b A f t \054 0 1083 0 array_in array_out array_recv array_send timetypmodin timetypmodout - d x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1184 ( timestamptz PGNSP PGUID 8 FLOAT8PASSBYVAL b D t t \054 0 0 1185 timestamptz_in timestamptz_out timestamptz_recv timestamptz_send timestamptztypmodin timestamptztypmodout - d p f f 0 -1 0 _null_ _null_ ));
DESCR("date and time with time zone");
#define TIMESTAMPTZOID 1184
-DATA(insert OID = 1185 ( _timestamptz PGNSP PGUID -1 f b A f t \054 0 1184 0 array_in array_out array_recv array_send timestamptztypmodin timestamptztypmodout - d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1186 ( interval PGNSP PGUID 16 f b T t t \054 0 0 1187 interval_in interval_out interval_recv interval_send intervaltypmodin intervaltypmodout - d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1185 ( _timestamptz PGNSP PGUID -1 f b A f t \054 0 1184 0 array_in array_out array_recv array_send timestamptztypmodin timestamptztypmodout - d x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1186 ( interval PGNSP PGUID 16 f b T t t \054 0 0 1187 interval_in interval_out interval_recv interval_send intervaltypmodin intervaltypmodout - d p f f 0 -1 0 _null_ _null_ ));
DESCR("@ <number> <units>, time interval");
#define INTERVALOID 1186
-DATA(insert OID = 1187 ( _interval PGNSP PGUID -1 f b A f t \054 0 1186 0 array_in array_out array_recv array_send intervaltypmodin intervaltypmodout - d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1187 ( _interval PGNSP PGUID -1 f b A f t \054 0 1186 0 array_in array_out array_recv array_send intervaltypmodin intervaltypmodout - d x f f 0 -1 0 _null_ _null_ ));
/* OIDS 1200 - 1299 */
-DATA(insert OID = 1231 ( _numeric PGNSP PGUID -1 f b A f t \054 0 1700 0 array_in array_out array_recv array_send numerictypmodin numerictypmodout - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1266 ( timetz PGNSP PGUID 12 f b D f t \054 0 0 1270 timetz_in timetz_out timetz_recv timetz_send timetztypmodin timetztypmodout - d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1231 ( _numeric PGNSP PGUID -1 f b A f t \054 0 1700 0 array_in array_out array_recv array_send numerictypmodin numerictypmodout - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1266 ( timetz PGNSP PGUID 12 f b D f t \054 0 0 1270 timetz_in timetz_out timetz_recv timetz_send timetztypmodin timetztypmodout - d p f f 0 -1 0 _null_ _null_ ));
DESCR("time of day with time zone");
#define TIMETZOID 1266
-DATA(insert OID = 1270 ( _timetz PGNSP PGUID -1 f b A f t \054 0 1266 0 array_in array_out array_recv array_send timetztypmodin timetztypmodout - d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1270 ( _timetz PGNSP PGUID -1 f b A f t \054 0 1266 0 array_in array_out array_recv array_send timetztypmodin timetztypmodout - d x f f 0 -1 0 _null_ _null_ ));
/* OIDS 1500 - 1599 */
-DATA(insert OID = 1560 ( bit PGNSP PGUID -1 f b V f t \054 0 0 1561 bit_in bit_out bit_recv bit_send bittypmodin bittypmodout - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1560 ( bit PGNSP PGUID -1 f b V f t \054 0 0 1561 bit_in bit_out bit_recv bit_send bittypmodin bittypmodout - i x f f 0 -1 0 _null_ _null_ ));
DESCR("fixed-length bit string");
#define BITOID 1560
-DATA(insert OID = 1561 ( _bit PGNSP PGUID -1 f b A f t \054 0 1560 0 array_in array_out array_recv array_send bittypmodin bittypmodout - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1562 ( varbit PGNSP PGUID -1 f b V t t \054 0 0 1563 varbit_in varbit_out varbit_recv varbit_send varbittypmodin varbittypmodout - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1561 ( _bit PGNSP PGUID -1 f b A f t \054 0 1560 0 array_in array_out array_recv array_send bittypmodin bittypmodout - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1562 ( varbit PGNSP PGUID -1 f b V t t \054 0 0 1563 varbit_in varbit_out varbit_recv varbit_send varbittypmodin varbittypmodout - i x f f 0 -1 0 _null_ _null_ ));
DESCR("variable-length bit string");
#define VARBITOID 1562
-DATA(insert OID = 1563 ( _varbit PGNSP PGUID -1 f b A f t \054 0 1562 0 array_in array_out array_recv array_send varbittypmodin varbittypmodout - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1563 ( _varbit PGNSP PGUID -1 f b A f t \054 0 1562 0 array_in array_out array_recv array_send varbittypmodin varbittypmodout - i x f f 0 -1 0 _null_ _null_ ));
/* OIDS 1600 - 1699 */
/* OIDS 1700 - 1799 */
-DATA(insert OID = 1700 ( numeric PGNSP PGUID -1 f b N f t \054 0 0 1231 numeric_in numeric_out numeric_recv numeric_send numerictypmodin numerictypmodout - i m f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1700 ( numeric PGNSP PGUID -1 f b N f t \054 0 0 1231 numeric_in numeric_out numeric_recv numeric_send numerictypmodin numerictypmodout - i m f f 0 -1 0 _null_ _null_ ));
DESCR("numeric(precision, decimal), arbitrary precision number");
#define NUMERICOID 1700
-DATA(insert OID = 1790 ( refcursor PGNSP PGUID -1 f b U f t \054 0 0 2201 textin textout textrecv textsend - - - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1790 ( refcursor PGNSP PGUID -1 f b U f t \054 0 0 2201 textin textout textrecv textsend - - - i x f f 0 -1 0 _null_ _null_ ));
DESCR("reference to cursor (portal name)");
#define REFCURSOROID 1790
/* OIDS 2200 - 2299 */
-DATA(insert OID = 2201 ( _refcursor PGNSP PGUID -1 f b A f t \054 0 1790 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2201 ( _refcursor PGNSP PGUID -1 f b A f t \054 0 1790 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 2202 ( regprocedure PGNSP PGUID 4 t b N f t \054 0 0 2207 regprocedurein regprocedureout regprocedurerecv regproceduresend - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2202 ( regprocedure PGNSP PGUID 4 t b N f t \054 0 0 2207 regprocedurein regprocedureout regprocedurerecv regproceduresend - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("registered procedure (with args)");
#define REGPROCEDUREOID 2202
-DATA(insert OID = 2203 ( regoper PGNSP PGUID 4 t b N f t \054 0 0 2208 regoperin regoperout regoperrecv regopersend - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2203 ( regoper PGNSP PGUID 4 t b N f t \054 0 0 2208 regoperin regoperout regoperrecv regopersend - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("registered operator");
#define REGOPEROID 2203
-DATA(insert OID = 2204 ( regoperator PGNSP PGUID 4 t b N f t \054 0 0 2209 regoperatorin regoperatorout regoperatorrecv regoperatorsend - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2204 ( regoperator PGNSP PGUID 4 t b N f t \054 0 0 2209 regoperatorin regoperatorout regoperatorrecv regoperatorsend - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("registered operator (with args)");
#define REGOPERATOROID 2204
-DATA(insert OID = 2205 ( regclass PGNSP PGUID 4 t b N f t \054 0 0 2210 regclassin regclassout regclassrecv regclasssend - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2205 ( regclass PGNSP PGUID 4 t b N f t \054 0 0 2210 regclassin regclassout regclassrecv regclasssend - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("registered class");
#define REGCLASSOID 2205
-DATA(insert OID = 2206 ( regtype PGNSP PGUID 4 t b N f t \054 0 0 2211 regtypein regtypeout regtyperecv regtypesend - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2206 ( regtype PGNSP PGUID 4 t b N f t \054 0 0 2211 regtypein regtypeout regtyperecv regtypesend - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("registered type");
#define REGTYPEOID 2206
-DATA(insert OID = 2207 ( _regprocedure PGNSP PGUID -1 f b A f t \054 0 2202 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 2208 ( _regoper PGNSP PGUID -1 f b A f t \054 0 2203 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 2209 ( _regoperator PGNSP PGUID -1 f b A f t \054 0 2204 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 2210 ( _regclass PGNSP PGUID -1 f b A f t \054 0 2205 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b A f t \054 0 2206 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2207 ( _regprocedure PGNSP PGUID -1 f b A f t \054 0 2202 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2208 ( _regoper PGNSP PGUID -1 f b A f t \054 0 2203 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2209 ( _regoperator PGNSP PGUID -1 f b A f t \054 0 2204 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2210 ( _regclass PGNSP PGUID -1 f b A f t \054 0 2205 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b A f t \054 0 2206 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
#define REGTYPEARRAYOID 2211
/* uuid */
-DATA(insert OID = 2950 ( uuid PGNSP PGUID 16 f b U f t \054 0 0 2951 uuid_in uuid_out uuid_recv uuid_send - - - c p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2950 ( uuid PGNSP PGUID 16 f b U f t \054 0 0 2951 uuid_in uuid_out uuid_recv uuid_send - - - c p f f 0 -1 0 _null_ _null_ ));
DESCR("UUID datatype");
-DATA(insert OID = 2951 ( _uuid PGNSP PGUID -1 f b A f t \054 0 2950 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2951 ( _uuid PGNSP PGUID -1 f b A f t \054 0 2950 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
/* text search */
-DATA(insert OID = 3614 ( tsvector PGNSP PGUID -1 f b U f t \054 0 0 3643 tsvectorin tsvectorout tsvectorrecv tsvectorsend - - ts_typanalyze i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 3614 ( tsvector PGNSP PGUID -1 f b U f t \054 0 0 3643 tsvectorin tsvectorout tsvectorrecv tsvectorsend - - ts_typanalyze i x f f 0 -1 0 _null_ _null_ ));
DESCR("text representation for text search");
#define TSVECTOROID 3614
-DATA(insert OID = 3642 ( gtsvector PGNSP PGUID -1 f b U f t \054 0 0 3644 gtsvectorin gtsvectorout - - - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 3642 ( gtsvector PGNSP PGUID -1 f b U f t \054 0 0 3644 gtsvectorin gtsvectorout - - - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("GiST index internal text representation for text search");
#define GTSVECTOROID 3642
-DATA(insert OID = 3615 ( tsquery PGNSP PGUID -1 f b U f t \054 0 0 3645 tsqueryin tsqueryout tsqueryrecv tsquerysend - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 3615 ( tsquery PGNSP PGUID -1 f b U f t \054 0 0 3645 tsqueryin tsqueryout tsqueryrecv tsquerysend - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("query representation for text search");
#define TSQUERYOID 3615
-DATA(insert OID = 3734 ( regconfig PGNSP PGUID 4 t b N f t \054 0 0 3735 regconfigin regconfigout regconfigrecv regconfigsend - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 3734 ( regconfig PGNSP PGUID 4 t b N f t \054 0 0 3735 regconfigin regconfigout regconfigrecv regconfigsend - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("registered text search configuration");
#define REGCONFIGOID 3734
-DATA(insert OID = 3769 ( regdictionary PGNSP PGUID 4 t b N f t \054 0 0 3770 regdictionaryin regdictionaryout regdictionaryrecv regdictionarysend - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 3769 ( regdictionary PGNSP PGUID 4 t b N f t \054 0 0 3770 regdictionaryin regdictionaryout regdictionaryrecv regdictionarysend - - - i p f f 0 -1 0 _null_ _null_ ));
DESCR("registered text search dictionary");
#define REGDICTIONARYOID 3769
-DATA(insert OID = 3643 ( _tsvector PGNSP PGUID -1 f b A f t \054 0 3614 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 3644 ( _gtsvector PGNSP PGUID -1 f b A f t \054 0 3642 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 3645 ( _tsquery PGNSP PGUID -1 f b A f t \054 0 3615 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 3735 ( _regconfig PGNSP PGUID -1 f b A f t \054 0 3734 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 3770 ( _regdictionary PGNSP PGUID -1 f b A f t \054 0 3769 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 3643 ( _tsvector PGNSP PGUID -1 f b A f t \054 0 3614 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 3644 ( _gtsvector PGNSP PGUID -1 f b A f t \054 0 3642 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 3645 ( _tsquery PGNSP PGUID -1 f b A f t \054 0 3615 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 3735 ( _regconfig PGNSP PGUID -1 f b A f t \054 0 3734 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 3770 ( _regdictionary PGNSP PGUID -1 f b A f t \054 0 3769 0 array_in array_out array_recv array_send - - - i x f f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 2970 ( txid_snapshot PGNSP PGUID -1 f b U f t \054 0 0 2949 txid_snapshot_in txid_snapshot_out txid_snapshot_recv txid_snapshot_send - - - d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2970 ( txid_snapshot PGNSP PGUID -1 f b U f t \054 0 0 2949 txid_snapshot_in txid_snapshot_out txid_snapshot_recv txid_snapshot_send - - - d x f f 0 -1 0 _null_ _null_ ));
DESCR("txid snapshot");
-DATA(insert OID = 2949 ( _txid_snapshot PGNSP PGUID -1 f b A f t \054 0 2970 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2949 ( _txid_snapshot PGNSP PGUID -1 f b A f t \054 0 2970 0 array_in array_out array_recv array_send - - - d x f f 0 -1 0 _null_ _null_ ));
/*
* pseudo-types
@@ -594,31 +600,31 @@ DATA(insert OID = 2949 ( _txid_snapshot PGNSP PGUID -1 f b A f t \054 0 2970 0 a
* but there is now support for it in records and arrays. Perhaps we should
* just treat it as a regular base type?
*/
-DATA(insert OID = 2249 ( record PGNSP PGUID -1 f p P f t \054 0 0 2287 record_in record_out record_recv record_send - - - d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2249 ( record PGNSP PGUID -1 f p P f t \054 0 0 2287 record_in record_out record_recv record_send - - - d x f f 0 -1 0 _null_ _null_ ));
#define RECORDOID 2249
-DATA(insert OID = 2287 ( _record PGNSP PGUID -1 f p P f t \054 0 2249 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2287 ( _record PGNSP PGUID -1 f p P f t \054 0 2249 0 array_in array_out array_recv array_send - - - d x f f 0 -1 0 _null_ _null_ ));
#define RECORDARRAYOID 2287
-DATA(insert OID = 2275 ( cstring PGNSP PGUID -2 f p P f t \054 0 0 1263 cstring_in cstring_out cstring_recv cstring_send - - - c p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2275 ( cstring PGNSP PGUID -2 f p P f t \054 0 0 1263 cstring_in cstring_out cstring_recv cstring_send - - - c p f f 0 -1 0 _null_ _null_ ));
#define CSTRINGOID 2275
-DATA(insert OID = 2276 ( any PGNSP PGUID 4 t p P f t \054 0 0 0 any_in any_out - - - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2276 ( any PGNSP PGUID 4 t p P f t \054 0 0 0 any_in any_out - - - - - i p f f 0 -1 0 _null_ _null_ ));
#define ANYOID 2276
-DATA(insert OID = 2277 ( anyarray PGNSP PGUID -1 f p P f t \054 0 0 0 anyarray_in anyarray_out anyarray_recv anyarray_send - - - d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2277 ( anyarray PGNSP PGUID -1 f p P f t \054 0 0 0 anyarray_in anyarray_out anyarray_recv anyarray_send - - - d x f f 0 -1 0 _null_ _null_ ));
#define ANYARRAYOID 2277
-DATA(insert OID = 2278 ( void PGNSP PGUID 4 t p P f t \054 0 0 0 void_in void_out - - - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2278 ( void PGNSP PGUID 4 t p P f t \054 0 0 0 void_in void_out - - - - - i p f f 0 -1 0 _null_ _null_ ));
#define VOIDOID 2278
-DATA(insert OID = 2279 ( trigger PGNSP PGUID 4 t p P f t \054 0 0 0 trigger_in trigger_out - - - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2279 ( trigger PGNSP PGUID 4 t p P f t \054 0 0 0 trigger_in trigger_out - - - - - i p f f 0 -1 0 _null_ _null_ ));
#define TRIGGEROID 2279
-DATA(insert OID = 2280 ( language_handler PGNSP PGUID 4 t p P f t \054 0 0 0 language_handler_in language_handler_out - - - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2280 ( language_handler PGNSP PGUID 4 t p P f t \054 0 0 0 language_handler_in language_handler_out - - - - - i p f f 0 -1 0 _null_ _null_ ));
#define LANGUAGE_HANDLEROID 2280
-DATA(insert OID = 2281 ( internal PGNSP PGUID SIZEOF_POINTER t p P f t \054 0 0 0 internal_in internal_out - - - - - ALIGNOF_POINTER p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2281 ( internal PGNSP PGUID SIZEOF_POINTER t p P f t \054 0 0 0 internal_in internal_out - - - - - ALIGNOF_POINTER p f f 0 -1 0 _null_ _null_ ));
#define INTERNALOID 2281
-DATA(insert OID = 2282 ( opaque PGNSP PGUID 4 t p P f t \054 0 0 0 opaque_in opaque_out - - - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2282 ( opaque PGNSP PGUID 4 t p P f t \054 0 0 0 opaque_in opaque_out - - - - - i p f f 0 -1 0 _null_ _null_ ));
#define OPAQUEOID 2282
-DATA(insert OID = 2283 ( anyelement PGNSP PGUID 4 t p P f t \054 0 0 0 anyelement_in anyelement_out - - - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2283 ( anyelement PGNSP PGUID 4 t p P f t \054 0 0 0 anyelement_in anyelement_out - - - - - i p f f 0 -1 0 _null_ _null_ ));
#define ANYELEMENTOID 2283
-DATA(insert OID = 2776 ( anynonarray PGNSP PGUID 4 t p P f t \054 0 0 0 anynonarray_in anynonarray_out - - - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2776 ( anynonarray PGNSP PGUID 4 t p P f t \054 0 0 0 anynonarray_in anynonarray_out - - - - - i p f f 0 -1 0 _null_ _null_ ));
#define ANYNONARRAYOID 2776
-DATA(insert OID = 3500 ( anyenum PGNSP PGUID 4 t p P f t \054 0 0 0 anyenum_in anyenum_out - - - - - i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 3500 ( anyenum PGNSP PGUID 4 t p P f t \054 0 0 0 anyenum_in anyenum_out - - - - - i p f f 0 -1 0 _null_ _null_ ));
#define ANYENUMOID 3500
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index c502b96..cd6d802 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -296,6 +296,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena * datum);
#define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
#define PG_RETURN_HEAPTUPLEHEADER(x) PG_RETURN_POINTER(x)
+#define PG_GET_COLLATION() get_call_collation(fcinfo->flinfo->fn_expr)
/*-------------------------------------------------------------------------
* Support for detecting call convention of dynamically-loaded functions
@@ -518,6 +519,7 @@ extern Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum);
extern Oid get_call_expr_argtype(fmNodePtr expr, int argnum);
extern bool get_fn_expr_arg_stable(FmgrInfo *flinfo, int argnum);
extern bool get_call_expr_arg_stable(fmNodePtr expr, int argnum);
+extern Oid get_call_collation(fmNodePtr expr);
/*
* Routines in dfmgr.c
diff --git a/src/include/nodes/nodeFuncs.h b/src/include/nodes/nodeFuncs.h
index aad6dc1..e3ff5d6 100644
--- a/src/include/nodes/nodeFuncs.h
+++ b/src/include/nodes/nodeFuncs.h
@@ -27,6 +27,7 @@
extern Oid exprType(Node *expr);
extern int32 exprTypmod(Node *expr);
+extern Oid exprColl(Node *expr);
extern bool exprIsLengthCoercion(Node *expr, int32 *coercedTypmod);
extern bool expression_returns_set(Node *clause);
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index a5f5df5..42a6c70 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -164,6 +164,7 @@ typedef enum NodeTag
T_JoinExpr,
T_FromExpr,
T_IntoClause,
+ T_CollateClause,
/*
* TAGS FOR EXPRESSION STATE NODES (execnodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index b591073..01a3a39 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -164,7 +164,8 @@ typedef struct Query
* specify the type by OID than by name. If "names" is NIL then the
* actual type OID is given by typeOid, otherwise typeOid is unused.
* Similarly, if "typmods" is NIL then the actual typmod is expected to
- * be prespecified in typemod, otherwise typemod is unused.
+ * be prespecified in typemod, otherwise typemod is unused. Similarly
+ * for collnames/collOid.
*
* If pct_type is TRUE, then names is actually a field name and we look up
* the type of that field. Otherwise (the normal case), names is a type
@@ -180,6 +181,8 @@ typedef struct TypeName
List *typmods; /* type modifier expression(s) */
int32 typemod; /* prespecified type modifier */
List *arrayBounds; /* array bounds */
+ List *collnames; /* collation name */
+ Oid collOid; /* collation by OID */
int location; /* token location, or -1 if unknown */
} TypeName;
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index c523d72..013bc0d 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -144,6 +144,7 @@ typedef struct Var
* levels up */
Index varnoold; /* original value of varno, for debugging */
AttrNumber varoattno; /* original value of varattno */
+ Oid varcollid; /* collation */
int location; /* token location, or -1 if unknown */
} Var;
@@ -324,6 +325,7 @@ typedef struct FuncExpr
bool funcretset; /* true if function returns set */
CoercionForm funcformat; /* how to display this function call */
List *args; /* arguments to the function */
+ Oid collid; /* collation OID to use by function */
int location; /* token location, or -1 if unknown */
} FuncExpr;
@@ -367,6 +369,7 @@ typedef struct OpExpr
Oid opresulttype; /* PG_TYPE OID of result value */
bool opretset; /* true if operator returns set */
List *args; /* arguments to the operator (1 or 2) */
+ Oid collid; /* collation OID to use by operator */
int location; /* token location, or -1 if unknown */
} OpExpr;
@@ -642,6 +645,18 @@ typedef struct RelabelType
int location; /* token location, or -1 if unknown */
} RelabelType;
+/*
+ * CollateClause - COLLATE
+ */
+typedef struct CollateClause
+{
+ NodeTag type;
+ Node *arg; /* original expression */
+ List *collnames; /* assigned collation */
+ Oid collOid; /* resolved collation OID */
+ int location; /* token location, or -1 if unknown */
+} CollateClause;
+
/* ----------------
* CoerceViaIO
*
diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h
index fa99ef7..0e17f7f 100644
--- a/src/include/parser/parse_type.h
+++ b/src/include/parser/parse_type.h
@@ -20,11 +20,13 @@
typedef HeapTuple Type;
extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
- int32 *typmod_p);
+ int32 *typmod_p, Oid *colloid_p);
extern Type typenameType(ParseState *pstate, const TypeName *typeName,
- int32 *typmod_p);
+ int32 *typmod_p, Oid *colloid_p);
extern Oid typenameTypeId(ParseState *pstate, const TypeName *typeName,
- int32 *typmod_p);
+ int32 *typmod_p, Oid *colloid_p);
+
+extern Oid LookupCollation(ParseState *pstate, List *collnames, int location);
extern char *TypeNameToString(const TypeName *typeName);
extern char *TypeNameListToString(List *typenames);
diff --git a/src/include/parser/parsetree.h b/src/include/parser/parsetree.h
index 377589a..db36c18 100644
--- a/src/include/parser/parsetree.h
+++ b/src/include/parser/parsetree.h
@@ -52,7 +52,7 @@ extern char *get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum);
* type and typemod info for that attribute of that RTE.
*/
extern void get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
- Oid *vartype, int32 *vartypmod);
+ Oid *vartype, int32 *vartypmod, Oid *varcollid);
/*
* Check whether an attribute of an RTE has been dropped (note that
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 0b60e09..ab2b925 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -705,7 +705,7 @@ extern Datum textoverlay(PG_FUNCTION_ARGS);
extern Datum textoverlay_no_len(PG_FUNCTION_ARGS);
extern Datum name_text(PG_FUNCTION_ARGS);
extern Datum text_name(PG_FUNCTION_ARGS);
-extern int varstr_cmp(char *arg1, int len1, char *arg2, int len2);
+extern int varstr_cmp(char *arg1, int len1, char *arg2, int len2, Oid collid);
extern List *textToQualifiedNameList(text *textval);
extern bool SplitIdentifierString(char *rawstring, char separator,
List **namelist);
diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h
index 2f19e5c..92ce4e2 100644
--- a/src/include/utils/syscache.h
+++ b/src/include/utils/syscache.h
@@ -44,6 +44,8 @@ enum SysCacheIdentifier
CASTSOURCETARGET,
CLAAMNAMENSP,
CLAOID,
+ COLLNAMENSP,
+ COLLOID,
CONDEFAULT,
CONNAMENSP,
CONSTROID,
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 656ea73..31842a9 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -1536,7 +1536,7 @@ plpgsql_parse_wordtype(char *ident)
* Word wasn't found in the namespace stack. Try to find a data type with
* that name, but ignore shell types and complex types.
*/
- typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL);
+ typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL, NULL);
if (typeTup)
{
Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
diff --git a/src/test/regress/expected/collate.out b/src/test/regress/expected/collate.out
new file mode 100644
index 0000000..19ab9a5
--- /dev/null
+++ b/src/test/regress/expected/collate.out
@@ -0,0 +1,42 @@
+CREATE TABLE collate_test1 (
+ a int,
+ b text COLLATE "en_US.utf8"
+);
+CREATE TABLE collate_test_fail (
+ a int,
+ b text COLLATE "en_US"
+);
+ERROR: collation "en_US" is not applicable to current database encoding "UTF8"
+LINE 3: b text COLLATE "en_US"
+ ^
+CREATE TABLE collate_test_fail (
+ a int,
+ b text COLLATE "foo"
+);
+ERROR: collation "foo" does not exist
+CREATE TABLE collate_test_fail (
+ a int COLLATE "en_US.utf8",
+ b text
+);
+ERROR: collations are not supported by type "pg_catalog.int4"
+LINE 2: a int COLLATE "en_US.utf8",
+ ^
+CREATE TABLE collate_test2 (
+ a int,
+ b text COLLATE "sv_SE.utf8"
+);
+INSERT INTO collate_test1 VALUES (1, 'abc'), (2, 'äbc'), (3, 'bbc');
+INSERT INTO collate_test2 SELECT * FROM collate_test1;
+SELECT * FROM collate_test1 WHERE b >= 'bbc';
+ a | b
+---+-----
+ 3 | bbc
+(1 row)
+
+SELECT * FROM collate_test2 WHERE b >= 'bbc';
+ a | b
+---+-----
+ 2 | äbc
+ 3 | bbc
+(2 rows)
+
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index 1d9e110..8608171 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -92,6 +92,7 @@ SELECT relname, relhasindex
pg_authid | t
pg_cast | t
pg_class | t
+ pg_collation | t
pg_constraint | t
pg_conversion | t
pg_database | t
@@ -153,7 +154,7 @@ SELECT relname, relhasindex
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
-(142 rows)
+(143 rows)
--
-- another sanity check: every system catalog that has OIDs should have
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 7529777..e8cdb79 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -84,7 +84,7 @@ test: rules
# ----------
# Another group of parallel tests
# ----------
-test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap
+test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap collate
# ----------
# Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 5f185f9..761bff6 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -103,6 +103,7 @@ test: tsdicts
test: foreign_data
test: window
test: xmlmap
+test: collate
test: plancache
test: limit
test: plpgsql
diff --git a/src/test/regress/sql/collate.sql b/src/test/regress/sql/collate.sql
new file mode 100644
index 0000000..60ffbe1
--- /dev/null
+++ b/src/test/regress/sql/collate.sql
@@ -0,0 +1,30 @@
+CREATE TABLE collate_test1 (
+ a int,
+ b text COLLATE "en_US.utf8"
+);
+
+CREATE TABLE collate_test_fail (
+ a int,
+ b text COLLATE "en_US"
+);
+
+CREATE TABLE collate_test_fail (
+ a int,
+ b text COLLATE "foo"
+);
+
+CREATE TABLE collate_test_fail (
+ a int COLLATE "en_US.utf8",
+ b text
+);
+
+CREATE TABLE collate_test2 (
+ a int,
+ b text COLLATE "sv_SE.utf8"
+);
+
+INSERT INTO collate_test1 VALUES (1, 'abc'), (2, 'äbc'), (3, 'bbc');
+INSERT INTO collate_test2 SELECT * FROM collate_test1;
+
+SELECT * FROM collate_test1 WHERE b >= 'bbc';
+SELECT * FROM collate_test2 WHERE b >= 'bbc';