diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 8f6e2d04bd..5c1cff3618 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -13698,6 +13698,10 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
pg_typeof
+
+ collation for
+
+
lists functions that
extract information from the system catalogs.
@@ -13859,6 +13863,11 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
regtype
get the data type of any value
+
+ collation for (any)
+ text
+ get the collation of the argument
+
@@ -13983,6 +13992,27 @@ SELECT typlen FROM pg_type WHERE oid = pg_typeof(33);
4
(1 row)
+
+
+
+ The expression collation for returns the collation of the
+ value that is passed to it. Example:
+
+SELECT collation for (description) FROM pg_description LIMIT 1;
+ pg_collation_for
+------------------
+ "default"
+(1 row)
+
+SELECT collation for ('foo' COLLATE "de_DE");
+ pg_collation_for
+------------------
+ "de_DE"
+(1 row)
+
+ The value might be quoted and schema-qualified. If no collation is derived
+ for the argument expression, then a null value is returned. If the argument
+ is not of a collatable data type, then an error is raised.
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index d1ce2ab042..9aea2cd80b 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -10701,6 +10701,19 @@ func_expr: func_name '(' ')' over_clause
n->location = @1;
$$ = (Node *)n;
}
+ | COLLATION FOR '(' a_expr ')'
+ {
+ FuncCall *n = makeNode(FuncCall);
+ n->funcname = SystemFuncName("pg_collation_for");
+ n->args = list_make1($4);
+ n->agg_order = NIL;
+ n->agg_star = FALSE;
+ n->agg_distinct = FALSE;
+ n->func_variadic = FALSE;
+ n->over = NULL;
+ n->location = @1;
+ $$ = (Node *)n;
+ }
| CURRENT_DATE
{
/*
@@ -12152,7 +12165,6 @@ unreserved_keyword:
| CLASS
| CLOSE
| CLUSTER
- | COLLATION
| COMMENT
| COMMENTS
| COMMIT
@@ -12491,6 +12503,7 @@ reserved_keyword:
| CAST
| CHECK
| COLLATE
+ | COLLATION
| COLUMN
| CONSTRAINT
| CREATE
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 3de6a5c992..6a1b477147 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -32,6 +32,7 @@
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/procarray.h"
+#include "utils/lsyscache.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/timestamp.h"
@@ -492,3 +493,29 @@ pg_typeof(PG_FUNCTION_ARGS)
{
PG_RETURN_OID(get_fn_expr_argtype(fcinfo->flinfo, 0));
}
+
+
+/*
+ * Implementation of the COLLATE FOR expression; returns the collation
+ * of the argument.
+ */
+Datum
+pg_collation_for(PG_FUNCTION_ARGS)
+{
+ Oid typeid;
+ Oid collid;
+
+ typeid = get_fn_expr_argtype(fcinfo->flinfo, 0);
+ if (!typeid)
+ PG_RETURN_NULL();
+ if (!type_is_collatable(typeid) && typeid != UNKNOWNOID)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("collations are not supported by type %s",
+ format_type_be(typeid))));
+
+ collid = PG_GET_COLLATION();
+ if (!collid)
+ PG_RETURN_NULL();
+ PG_RETURN_TEXT_P(cstring_to_text(generate_collation_name(collid)));
+}
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index e5fbbfc8fd..0335347155 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201203011
+#define CATALOG_VERSION_NO 201203021
#endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 8700d0d958..b476d47579 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -1953,6 +1953,8 @@ DESCR("convert generic options array to name/value table");
DATA(insert OID = 1619 ( pg_typeof PGNSP PGUID 12 1 0 0 0 f f f f f f s 1 0 2206 "2276" _null_ _null_ _null_ _null_ pg_typeof _null_ _null_ _null_ ));
DESCR("type of the argument");
+DATA(insert OID = 3162 ( pg_collation_for PGNSP PGUID 12 1 0 0 0 f f f f f f s 1 0 25 "2276" _null_ _null_ _null_ _null_ pg_collation_for _null_ _null_ _null_ ));
+DESCR("collation of the argument; implementation of the COLLATION FOR expression");
/* Deferrable unique constraint trigger */
DATA(insert OID = 1250 ( unique_key_recheck PGNSP PGUID 12 1 0 0 0 f f f f t f v 0 0 2279 "" _null_ _null_ _null_ _null_ unique_key_recheck _null_ _null_ _null_ ));
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index bf71ee5414..9f6f6d354f 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -79,7 +79,7 @@ PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD)
PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD)
PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD)
PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD)
-PG_KEYWORD("collation", COLLATION, UNRESERVED_KEYWORD)
+PG_KEYWORD("collation", COLLATION, RESERVED_KEYWORD)
PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD)
PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD)
PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD)
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index fe253bcc7c..9fda7ad28e 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -480,6 +480,7 @@ extern Datum pg_rotate_logfile(PG_FUNCTION_ARGS);
extern Datum pg_sleep(PG_FUNCTION_ARGS);
extern Datum pg_get_keywords(PG_FUNCTION_ARGS);
extern Datum pg_typeof(PG_FUNCTION_ARGS);
+extern Datum pg_collation_for(PG_FUNCTION_ARGS);
/* oid.c */
extern Datum oidin(PG_FUNCTION_ARGS);
diff --git a/src/test/regress/expected/collate.out b/src/test/regress/expected/collate.out
index a15e6911b0..81ac6de7b3 100644
--- a/src/test/regress/expected/collate.out
+++ b/src/test/regress/expected/collate.out
@@ -577,6 +577,26 @@ RESET enable_nestloop;
-- 9.1 bug with useless COLLATE in an expression subject to length coercion
CREATE TEMP TABLE vctable (f1 varchar(25));
INSERT INTO vctable VALUES ('foo' COLLATE "C");
+SELECT collation for ('foo'); -- unknown type - null
+ pg_collation_for
+------------------
+
+(1 row)
+
+SELECT collation for ('foo'::text);
+ pg_collation_for
+------------------
+ "default"
+(1 row)
+
+SELECT collation for ((SELECT a FROM collate_test1 LIMIT 1)); -- non-collatable type - error
+ERROR: collations are not supported by type integer
+SELECT collation for ((SELECT b FROM collate_test1 LIMIT 1));
+ pg_collation_for
+------------------
+ "C"
+(1 row)
+
--
-- Clean up. Many of these table names will be re-used if the user is
-- trying to run any platform-specific collation tests later, so we
diff --git a/src/test/regress/sql/collate.sql b/src/test/regress/sql/collate.sql
index f72f3edb9d..3c960e7ed9 100644
--- a/src/test/regress/sql/collate.sql
+++ b/src/test/regress/sql/collate.sql
@@ -219,6 +219,13 @@ RESET enable_nestloop;
CREATE TEMP TABLE vctable (f1 varchar(25));
INSERT INTO vctable VALUES ('foo' COLLATE "C");
+
+SELECT collation for ('foo'); -- unknown type - null
+SELECT collation for ('foo'::text);
+SELECT collation for ((SELECT a FROM collate_test1 LIMIT 1)); -- non-collatable type - error
+SELECT collation for ((SELECT b FROM collate_test1 LIMIT 1));
+
+
--
-- Clean up. Many of these table names will be re-used if the user is
-- trying to run any platform-specific collation tests later, so we