Sunday, August 31, 2008

[HACKERS] WIP patch: Collation support

Index: backend/parser/keywords.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/keywords.c,v
retrieving revision 1.199
diff -c -r1.199 keywords.c
*** backend/parser/keywords.c 16 Jul 2008 01:30:22 -0000 1.199
--- backend/parser/keywords.c 31 Aug 2008 19:21:08 -0000
***************
*** 45,50 ****
--- 45,51 ----
/* name, value, category */
{"abort", ABORT_P, UNRESERVED_KEYWORD},
{"absolute", ABSOLUTE_P, UNRESERVED_KEYWORD},
+ {"accent", ACCENT, UNRESERVED_KEYWORD},
{"access", ACCESS, UNRESERVED_KEYWORD},
{"action", ACTION, UNRESERVED_KEYWORD},
{"add", ADD_P, UNRESERVED_KEYWORD},
***************
*** 94,99 ****
--- 95,101 ----
{"cluster", CLUSTER, UNRESERVED_KEYWORD},
{"coalesce", COALESCE, COL_NAME_KEYWORD},
{"collate", COLLATE, RESERVED_KEYWORD},
+ {"collation", COLLATION, UNRESERVED_KEYWORD},
{"column", COLUMN, RESERVED_KEYWORD},
{"comment", COMMENT, UNRESERVED_KEYWORD},
{"commit", COMMIT, UNRESERVED_KEYWORD},
***************
*** 220,225 ****
--- 222,229 ----
{"language", LANGUAGE, UNRESERVED_KEYWORD},
{"large", LARGE_P, UNRESERVED_KEYWORD},
{"last", LAST_P, UNRESERVED_KEYWORD},
+ {"lccollate", LCCOLLATE, UNRESERVED_KEYWORD},
+ {"lcctype", LCCTYPE, UNRESERVED_KEYWORD},
{"leading", LEADING, RESERVED_KEYWORD},
{"least", LEAST, COL_NAME_KEYWORD},
{"left", LEFT, TYPE_FUNC_NAME_KEYWORD},
***************
*** 284,289 ****
--- 288,294 ----
{"overlay", OVERLAY, COL_NAME_KEYWORD},
{"owned", OWNED, UNRESERVED_KEYWORD},
{"owner", OWNER, UNRESERVED_KEYWORD},
+ {"pad", PAD, UNRESERVED_KEYWORD},
{"parser", PARSER, UNRESERVED_KEYWORD},
{"partial", PARTIAL, UNRESERVED_KEYWORD},
{"password", PASSWORD, UNRESERVED_KEYWORD},
***************
*** 331,336 ****
--- 336,342 ----
{"second", SECOND_P, UNRESERVED_KEYWORD},
{"security", SECURITY, UNRESERVED_KEYWORD},
{"select", SELECT, RESERVED_KEYWORD},
+ {"sensitive", SENSITIVE, UNRESERVED_KEYWORD},
{"sequence", SEQUENCE, UNRESERVED_KEYWORD},
{"serializable", SERIALIZABLE, UNRESERVED_KEYWORD},
{"session", SESSION, UNRESERVED_KEYWORD},
***************
*** 343,348 ****
--- 349,355 ----
{"simple", SIMPLE, UNRESERVED_KEYWORD},
{"smallint", SMALLINT, COL_NAME_KEYWORD},
{"some", SOME, RESERVED_KEYWORD},
+ {"space", SPACE, UNRESERVED_KEYWORD},
{"stable", STABLE, UNRESERVED_KEYWORD},
{"standalone", STANDALONE_P, UNRESERVED_KEYWORD},
{"start", START, UNRESERVED_KEYWORD},
***************
*** 351,356 ****
--- 358,364 ----
{"stdin", STDIN, UNRESERVED_KEYWORD},
{"stdout", STDOUT, UNRESERVED_KEYWORD},
{"storage", STORAGE, UNRESERVED_KEYWORD},
+ {"strcolfn", STRCOLFN, UNRESERVED_KEYWORD},
{"strict", STRICT_P, UNRESERVED_KEYWORD},
{"strip", STRIP_P, UNRESERVED_KEYWORD},
{"substring", SUBSTRING, COL_NAME_KEYWORD},
Index: backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.618
diff -c -r2.618 gram.y
*** backend/parser/gram.y 18 Jul 2008 03:32:52 -0000 2.618
--- backend/parser/gram.y 31 Aug 2008 19:21:08 -0000
***************
*** 155,174 ****
}

%type <node> stmt schema_stmt
! AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterGroupStmt
! AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt
! AlterUserStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt
! AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
! ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
! CreateDomainStmt CreateGroupStmt CreateOpClassStmt
! CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt
CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
CreateAssertStmt CreateTrigStmt CreateUserStmt CreateRoleStmt
! CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt
! DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
! DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
! DropUserStmt DropdbStmt DropTableSpaceStmt ExplainStmt FetchStmt
! GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt
LockStmt NotifyStmt ExplainableStmt PreparableStmt
CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt
RemoveFuncStmt RemoveOperStmt RenameStmt RevokeStmt RevokeRoleStmt
--- 155,173 ----
}

%type <node> stmt schema_stmt
! AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterGroupStmt
! AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt
! AlterUserStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt AnalyzeStmt
! ClosePortalStmt ClusterStmt CommentStmt ConstraintsSetStmt CopyStmt
! CreateAsStmt CreateCastStmt CreateCollationStmt CreateDomainStmt
! CreateGroupStmt CreateOpClassStmt CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt
CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
CreateAssertStmt CreateTrigStmt CreateUserStmt CreateRoleStmt
! CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt
! DropCollationStmt DropGroupStmt DropOpClassStmt DropOpFamilyStmt
! DropPLangStmt DropStmt DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt
! DropRoleStmt DropUserStmt DropdbStmt DropTableSpaceStmt ExplainStmt
! FetchStmt GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt
LockStmt NotifyStmt ExplainableStmt PreparableStmt
CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt
RemoveFuncStmt RemoveOperStmt RenameStmt RevokeStmt RevokeRoleStmt
***************
*** 296,301 ****
--- 295,303 ----
%type <list> OptSeqOptList SeqOptList
%type <defelt> SeqOptElem

+ %type <list> OptCollationList
+ %type <defelt> OptCollationElem
+
%type <istmt> insert_rest

%type <vsetstmt> set_rest SetResetClause
***************
*** 372,378 ****
*/

/* ordinary key words in alphabetical order */
! %token <keyword> ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC
ASSERTION ASSIGNMENT ASYMMETRIC AT AUTHORIZATION

--- 374,380 ----
*/

/* ordinary key words in alphabetical order */
! %token <keyword> ABORT_P ABSOLUTE_P ACCENT ACCESS ACTION ADD_P ADMIN AFTER
AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC
ASSERTION ASSIGNMENT ASYMMETRIC AT AUTHORIZATION

***************
*** 381,387 ****

CACHE CALLED CASCADE CASCADED CASE CAST CHAIN CHAR_P
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
! CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS
CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CREATEDB
CREATEROLE CREATEUSER CROSS CSV CURRENT_P CURRENT_DATE CURRENT_ROLE
--- 383,389 ----

CACHE CALLED CASCADE CASCADED CASE CAST CHAIN CHAR_P
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
! CLUSTER COALESCE COLLATE COLLATION COLUMN COMMENT COMMIT
COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS
CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CREATEDB
CREATEROLE CREATEUSER CROSS CSV CURRENT_P CURRENT_DATE CURRENT_ROLE
***************
*** 401,416 ****

HANDLER HAVING HEADER_P HOLD HOUR_P

! IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P
! INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY
! INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER
! INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION

JOIN

KEY

! LANCOMPILER LANGUAGE LARGE_P LAST_P LEADING LEAST LEFT LEVEL
LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
LOCK_P LOGIN_P

--- 403,418 ----

HANDLER HAVING HEADER_P HOLD HOUR_P

! IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDING INCREMENT
! INDEX INDEXES INHERIT INHERITS INITIALLY INNER_P INOUT INPUT_P
! INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT
! INTERVAL INTO INVOKER IS ISNULL ISOLATION

JOIN

KEY

! LANCOMPILER LANGUAGE LARGE_P LAST_P LCCOLLATE LCCTYPE LEADING LEAST LEFT LEVEL
LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
LOCK_P LOGIN_P

***************
*** 423,429 ****
OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR
ORDER OUT_P OUTER_P OVERLAPS OVERLAY OWNED OWNER

! PARSER PARTIAL PASSWORD PLACING PLANS POSITION
PRECISION PRESERVE PREPARE PREPARED PRIMARY
PRIOR PRIVILEGES PROCEDURAL PROCEDURE

--- 425,431 ----
OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR
ORDER OUT_P OUTER_P OVERLAPS OVERLAY OWNED OWNER

! PAD PARSER PARTIAL PASSWORD PLACING PLANS POSITION
PRECISION PRESERVE PREPARE PREPARED PRIMARY
PRIOR PRIVILEGES PROCEDURAL PROCEDURE

***************
*** 433,443 ****
REPEATABLE REPLACE REPLICA RESET RESTART RESTRICT RETURNING RETURNS REVOKE
RIGHT ROLE ROLLBACK ROW ROWS RULE

! SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE
! SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
! SHOW SIMILAR SIMPLE SMALLINT SOME STABLE STANDALONE_P START STATEMENT
! STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING SUPERUSER_P
! SYMMETRIC SYSID SYSTEM_P

TABLE TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN TIME TIMESTAMP
TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
--- 435,445 ----
REPEATABLE REPLACE REPLICA RESET RESTART RESTRICT RETURNING RETURNS REVOKE
RIGHT ROLE ROLLBACK ROW ROWS RULE

! SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SENSITIVE
! SEQUENCE SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
! SHOW SIMILAR SIMPLE SMALLINT SOME SPACE STABLE STANDALONE_P START STATEMENT
! STATISTICS STDIN STDOUT STORAGE STRCOLFN STRICT_P STRIP_P SUBSTRING
! SUPERUSER_P SYMMETRIC SYSID SYSTEM_P

TABLE TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN TIME TIMESTAMP
TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
***************
*** 559,564 ****
--- 561,567 ----
| CreateAsStmt
| CreateAssertStmt
| CreateCastStmt
+ | CreateCollationStmt
| CreateConversionStmt
| CreateDomainStmt
| CreateFunctionStmt
***************
*** 582,587 ****
--- 585,591 ----
| DiscardStmt
| DropAssertStmt
| DropCastStmt
+ | DropCollationStmt
| DropGroupStmt
| DropOpClassStmt
| DropOpFamilyStmt
***************
*** 2421,2426 ****
--- 2425,2508 ----
}
;

+ /*****************************************************************************
+ *
+ * QUERY :
+ *
+ * CREATE COLLATION <collation name> FOR <character set specification>
+ * FROM <existing collation name> [STRCOLFN <fn name>]
+ * [ <pad characteristic> ] [ <case sensitive> ] [ <accent sensitive> ]
+ * [ LCCOLLATE <lc_collate> ] [ LCCTYPE <lc_ctype> ]
+ *
+ * DROP COLLATION <collation name>
+ *
+ *****************************************************************************/
+
+ CreateCollationStmt:
+ CREATE COLLATION name FOR name FROM name OptCollationList
+ {
+ CreateCollationStmt *n = makeNode(CreateCollationStmt);
+ n->name = $3;
+ n->for_charset = $5;
+ n->parent_collation = $7;
+ n->options = $8;
+ $$ = (Node *)n;
+ }
+ ;
+
+ OptCollationList:
+ OptCollationList OptCollationElem { $$ = lappend($1, $2); }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+ OptCollationElem:
+ NO PAD
+ {
+ $$ = makeDefElem("pad_characteristic", (Node *)makeInteger(FALSE));
+ }
+ | PAD SPACE
+ {
+ $$ = makeDefElem("pad_characteristic", (Node *)makeInteger(TRUE));
+ }
+ | CASE SENSITIVE
+ {
+ $$ = makeDefElem("case_sensitive", (Node *)makeInteger(TRUE));
+ }
+ | CASE INSENSITIVE
+ {
+ $$ = makeDefElem("case_sensitive", (Node *)makeInteger(FALSE));
+ }
+ | ACCENT SENSITIVE
+ {
+ $$ = makeDefElem("accent_sensitive", (Node *)makeInteger(TRUE));
+ }
+ | ACCENT INSENSITIVE
+ {
+ $$ = makeDefElem("accent_sensitive", (Node *)makeInteger(FALSE));
+ }
+ | LCCOLLATE name
+ {
+ $$ = makeDefElem("lc_collate_name", (Node *)makeString($2));
+ }
+ | LCCTYPE name
+ {
+ $$ = makeDefElem("lc_ctype_name", (Node *)makeString($2));
+ }
+ | STRCOLFN name
+ {
+ $$ = makeDefElem("str_col_function", (Node *)makeInteger(1));
+ }
+ ;
+
+ DropCollationStmt:
+ DROP COLLATION name
+ {
+ DropCollationStmt *n = makeNode(DropCollationStmt);
+ n->name = $3;
+ $$ = (Node *)n;
+ }
+ ;
+

/*****************************************************************************
*
***************
*** 5432,5437 ****
--- 5514,5527 ----
{
$$ = makeDefElem("encoding", NULL);
}
+ | COLLATE opt_equal name
+ {
+ $$ = makeDefElem("collate", (Node *)makeString($3));
+ }
+ | COLLATE opt_equal DEFAULT
+ {
+ $$ = makeDefElem("collate", NULL);
+ }
| CONNECTION LIMIT opt_equal SignedIconst
{
$$ = makeDefElem("connectionlimit", (Node *)makeInteger($4));
***************
*** 9044,9049 ****
--- 9134,9140 ----
unreserved_keyword:
ABORT_P
| ABSOLUTE_P
+ | ACCENT
| ACCESS
| ACTION
| ADD_P
***************
*** 9070,9075 ****
--- 9161,9167 ----
| CLASS
| CLOSE
| CLUSTER
+ | COLLATION
| COMMENT
| COMMIT
| COMMITTED
***************
*** 9151,9156 ****
--- 9243,9250 ----
| LANGUAGE
| LARGE_P
| LAST_P
+ | LCCOLLATE
+ | LCCTYPE
| LEVEL
| LISTEN
| LOAD
***************
*** 9187,9192 ****
--- 9281,9287 ----
| OPTION
| OWNED
| OWNER
+ | PAD
| PARSER
| PARTIAL
| PASSWORD
***************
*** 9224,9229 ****
--- 9319,9325 ----
| SEARCH
| SECOND_P
| SECURITY
+ | SENSITIVE
| SEQUENCE
| SERIALIZABLE
| SESSION
***************
*** 9231,9236 ****
--- 9327,9333 ----
| SHARE
| SHOW
| SIMPLE
+ | SPACE
| STABLE
| STANDALONE_P
| START
***************
*** 9239,9244 ****
--- 9336,9342 ----
| STDIN
| STDOUT
| STORAGE
+ | STRCOLFN
| STRICT_P
| STRIP_P
| SUPERUSER_P
Index: backend/utils/cache/syscache.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/cache/syscache.c,v
retrieving revision 1.117
diff -c -r1.117 syscache.c
*** backend/utils/cache/syscache.c 19 Jun 2008 00:46:05 -0000 1.117
--- backend/utils/cache/syscache.c 31 Aug 2008 19:21:08 -0000
***************
*** 28,33 ****
--- 28,35 ----
#include "catalog/pg_auth_members.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_cast.h"
+ #include "catalog/pg_charset.h"
+ #include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
***************
*** 257,262 ****
--- 259,288 ----
},
256
},
+ {CharsetRelationId, /* CHARSETNAME */
+ CharsetNameIndexId,
+ 0,
+ 1,
+ {
+ Anum_pg_charset_charsetname,
+ 0,
+ 0,
+ 0
+ },
+ 64
+ },
+ {CharsetRelationId, /* CHARSETOID */
+ CharsetOidIndexId,
+ 0,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 64
+ },
{OperatorClassRelationId, /* CLAAMNAMENSP */
OpclassAmNameNspIndexId,
0,
***************
*** 281,286 ****
--- 307,336 ----
},
64
},
+ {CollationRelationId, /* COLLNAME */
+ CollationNameIndexId,
+ 0,
+ 1,
+ {
+ Anum_pg_collation_colname,
+ 0,
+ 0,
+ 0
+ },
+ 64
+ },
+ {CollationRelationId, /* COLLOID */
+ CollationOidIndexId,
+ 0,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 64
+ },
{ConversionRelationId, /* CONDEFAULT */
ConversionDefaultIndexId,
0,
Index: include/utils/pg_locale.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/pg_locale.h,v
retrieving revision 1.25
diff -c -r1.25 pg_locale.h
*** include/utils/pg_locale.h 19 May 2008 18:08:16 -0000 1.25
--- include/utils/pg_locale.h 31 Aug 2008 19:21:10 -0000
***************
*** 30,35 ****
--- 30,39 ----
extern char *localized_full_months[];


+ extern const char *locale_collate_assign(const char *value,
+ bool doit, GucSource source);
+ extern const char *locale_ctype_assign(const char *value,
+ bool doit, GucSource source);
extern const char *locale_messages_assign(const char *value,
bool doit, GucSource source);
extern const char *locale_monetary_assign(const char *value,
Index: include/utils/syscache.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/syscache.h,v
retrieving revision 1.72
diff -c -r1.72 syscache.h
*** include/utils/syscache.h 7 May 2008 01:04:49 -0000 1.72
--- include/utils/syscache.h 31 Aug 2008 19:21:10 -0000
***************
*** 42,49 ****
--- 42,53 ----
AUTHNAME,
AUTHOID,
CASTSOURCETARGET,
+ CHARSETNAME,
+ CHARSETOID,
CLAAMNAMENSP,
CLAOID,
+ COLLNAME,
+ COLLOID,
CONDEFAULT,
CONNAMENSP,
CONSTROID,
Index: interfaces/ecpg/preproc/preproc.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/ecpg/preproc/preproc.y,v
retrieving revision 1.371
diff -c -r1.371 preproc.y
*** interfaces/ecpg/preproc/preproc.y 20 Aug 2008 14:09:16 -0000 1.371
--- interfaces/ecpg/preproc/preproc.y 31 Aug 2008 19:21:10 -0000
***************
*** 416,422 ****
%token TYPECAST

/* ordinary key words in alphabetical order */
! %token <keyword> ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC
ASSERTION ASSIGNMENT ASYMMETRIC AT AUTHORIZATION

--- 416,422 ----
%token TYPECAST

/* ordinary key words in alphabetical order */
! %token <keyword> ABORT_P ABSOLUTE_P ACCENT ACCESS ACTION ADD_P ADMIN AFTER
AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC
ASSERTION ASSIGNMENT ASYMMETRIC AT AUTHORIZATION

***************
*** 425,431 ****

CACHE CALLED CASCADE CASCADED CASE CAST CHAIN CHAR_P
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
! CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS
CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CREATEDB
CREATEROLE CREATEUSER CROSS CSV CURRENT_P CURRENT_DATE CURRENT_ROLE
--- 425,431 ----

CACHE CALLED CASCADE CASCADED CASE CAST CHAIN CHAR_P
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
! CLUSTER COALESCE COLLATE COLLATION COLUMN COMMENT COMMIT
COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS
CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CREATEDB
CREATEROLE CREATEUSER CROSS CSV CURRENT_P CURRENT_DATE CURRENT_ROLE
***************
*** 454,462 ****

KEY

! LANCOMPILER LANGUAGE LARGE_P LAST_P LEADING LEAST LEFT LEVEL
! LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
! LOCK_P LOGIN_P

MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE

--- 454,462 ----

KEY

! LANCOMPILER LANGUAGE LARGE_P LAST_P LCCOLLATE LCCTYPE LEADING LEAST
! LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP
! LOCATION LOCK_P LOGIN_P

MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE

***************
*** 467,473 ****
OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR ORDER
OUT_P OUTER_P OVERLAPS OVERLAY OWNED OWNER

! PARSER PARTIAL PASSWORD PLACING PLANS POSITION
PRECISION PRESERVE PREPARE PREPARED PRIMARY
PRIOR PRIVILEGES PROCEDURAL PROCEDURE

--- 467,473 ----
OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR ORDER
OUT_P OUTER_P OVERLAPS OVERLAY OWNED OWNER

! PAD PARSER PARTIAL PASSWORD PLACING PLANS POSITION
PRECISION PRESERVE PREPARE PREPARED PRIMARY
PRIOR PRIVILEGES PROCEDURAL PROCEDURE

***************
*** 477,487 ****
REPEATABLE REPLACE REPLICA RESET RESTART RESTRICT RETURNING RETURNS REVOKE
RIGHT ROLE ROLLBACK ROW ROWS RULE

! SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE
SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
! SHOW SIMILAR SIMPLE SMALLINT SOME STABLE STANDALONE_P START STATEMENT
! STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING SUPERUSER_P
! SYMMETRIC SYSID SYSTEM_P

TABLE TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN TIME TIMESTAMP TO
TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P TRUNCATE TRUSTED TYPE_P
--- 477,487 ----
REPEATABLE REPLACE REPLICA RESET RESTART RESTRICT RETURNING RETURNS REVOKE
RIGHT ROLE ROLLBACK ROW ROWS RULE

! SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SENSITIVE SEQUENCE
SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
! SHOW SIMILAR SIMPLE SMALLINT SOME SPACE STABLE STANDALONE_P START STATEMENT
! STATISTICS STDIN STDOUT STORAGE STRCOLFN STRICT_P STRIP_P SUBSTRING
! SUPERUSER_P SYMMETRIC SYSID SYSTEM_P

TABLE TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN TIME TIMESTAMP TO
TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P TRUNCATE TRUSTED TYPE_P
Index: bin/psql/tab-complete.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/tab-complete.c,v
retrieving revision 1.171
diff -c -r1.171 tab-complete.c
*** bin/psql/tab-complete.c 16 Aug 2008 01:36:35 -0000 1.171
--- bin/psql/tab-complete.c 31 Aug 2008 19:21:09 -0000
***************
*** 514,520 ****
{"AGGREGATE", NULL, &Query_for_list_of_aggregates},
{"CAST", NULL, NULL}, /* Casts have complex structures for names, so
* skip it */
!
/*
* CREATE CONSTRAINT TRIGGER is not supported here because it is designed
* to be used only by pg_dump.
--- 514,520 ----
{"AGGREGATE", NULL, &Query_for_list_of_aggregates},
{"CAST", NULL, NULL}, /* Casts have complex structures for names, so
* skip it */
! {"COLLATION", NULL, NULL}, /* TODO eventually change */
/*
* CREATE CONSTRAINT TRIGGER is not supported here because it is designed
* to be used only by pg_dump.
***************
*** 1199,1205 ****
pg_strcasecmp(prev2_wd, "DATABASE") == 0)
{
static const char *const list_DATABASE[] =
! {"OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "CONNECTION LIMIT",
NULL};

COMPLETE_WITH_LIST(list_DATABASE);
--- 1199,1205 ----
pg_strcasecmp(prev2_wd, "DATABASE") == 0)
{
static const char *const list_DATABASE[] =
! {"OWNER", "TEMPLATE", "ENCODING", "LCCOLLATE", "LCCTYPE", "TABLESPACE", "CONNECTION LIMIT",
NULL};

COMPLETE_WITH_LIST(list_DATABASE);
***************
*** 1462,1468 ****

/* DROP object with CASCADE / RESTRICT */
else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
! (pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
--- 1462,1469 ----

/* DROP object with CASCADE / RESTRICT */
else if ((pg_strcasecmp(prev3_wd, "DROP") == 0 &&
! (pg_strcasecmp(prev2_wd, "COLLATION") == 0 ||
! pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
pg_strcasecmp(prev2_wd, "DOMAIN") == 0 ||
pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
pg_strcasecmp(prev2_wd, "INDEX") == 0 ||
Index: bin/psql/describe.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/describe.c,v
retrieving revision 1.184
diff -c -r1.184 describe.c
*** bin/psql/describe.c 18 Jul 2008 04:20:24 -0000 1.184
--- bin/psql/describe.c 31 Aug 2008 19:21:09 -0000
***************
*** 462,467 ****
--- 462,476 ----
gettext_noop("Access Privileges"));
if (verbose && pset.sversion >= 80200)
appendPQExpBuffer(&buf,
+ ",\n d.datcollate as \"%s\"",
+ _("LC_COLLATE"));
+ if (verbose && pset.sversion >= 80200)
+ appendPQExpBuffer(&buf,
+ ",\n d.datctype as \"%s\"",
+ _("LC_CTYPE"));
+
+ if (verbose && pset.sversion >= 80200)
+ appendPQExpBuffer(&buf,
",\n CASE WHEN pg_catalog.has_database_privilege(d.datname, 'CONNECT')\n"
" THEN pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(d.datname))\n"
" ELSE 'No Access'\n"
Index: backend/commands/Makefile
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/Makefile,v
retrieving revision 1.38
diff -c -r1.38 Makefile
*** backend/commands/Makefile 19 Feb 2008 10:30:07 -0000 1.38
--- backend/commands/Makefile 31 Aug 2008 19:21:07 -0000
***************
*** 13,19 ****
include $(top_builddir)/src/Makefile.global

OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \
! conversioncmds.o copy.o \
dbcommands.o define.o discard.o explain.o functioncmds.o \
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
portalcmds.o prepare.o proclang.o \
--- 13,19 ----
include $(top_builddir)/src/Makefile.global

OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \
! collation.o conversioncmds.o copy.o \
dbcommands.o define.o discard.o explain.o functioncmds.o \
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
portalcmds.o prepare.o proclang.o \
Index: backend/commands/dbcommands.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/dbcommands.c,v
retrieving revision 1.210
diff -c -r1.210 dbcommands.c
*** backend/commands/dbcommands.c 4 Aug 2008 18:03:46 -0000 1.210
--- backend/commands/dbcommands.c 31 Aug 2008 19:21:07 -0000
***************
*** 19,24 ****
--- 19,28 ----
*/
#include "postgres.h"

+ #ifdef HAVE_LANGINFO_H
+ #include <langinfo.h>
+ #endif
+
#include <fcntl.h>
#include <locale.h>
#include <unistd.h>
***************
*** 32,37 ****
--- 36,42 ----
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_authid.h"
+ #include "catalog/pg_collation.h"
#include "catalog/pg_database.h"
#include "catalog/pg_tablespace.h"
#include "commands/comment.h"
***************
*** 53,58 ****
--- 58,64 ----
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
+ #include "utils/pg_locale.h"
#include "utils/syscache.h"
#include "utils/tqual.h"

***************
*** 69,75 ****
Oid *dbIdP, Oid *ownerIdP,
int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
Oid *dbLastSysOidP, TransactionId *dbFrozenXidP,
! Oid *dbTablespace);
static bool have_createdb_privilege(void);
static void remove_dbtablespaces(Oid db_id);
static bool check_db_file_conflict(Oid db_id);
--- 75,81 ----
Oid *dbIdP, Oid *ownerIdP,
int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
Oid *dbLastSysOidP, TransactionId *dbFrozenXidP,
! Oid *dbTablespace, Oid *dbCollation);
static bool have_createdb_privilege(void);
static void remove_dbtablespaces(Oid db_id);
static bool check_db_file_conflict(Oid db_id);
***************
*** 86,92 ****
--- 92,101 ----
Relation rel;
Oid src_dboid;
Oid src_owner;
+ Oid src_collationoid;
int src_encoding;
+ char *src_collate;
+ char *src_ctype;
bool src_istemplate;
bool src_allowconn;
Oid src_lastsysoid;
***************
*** 95,113 ****
--- 104,127 ----
volatile Oid dst_deftablespace;
Relation pg_database_rel;
HeapTuple tuple;
+ HeapTuple coltuple;
Datum new_record[Natts_pg_database];
char new_record_nulls[Natts_pg_database];
Oid dboid;
Oid datdba;
+ Oid datcollationoid;
ListCell *option;
DefElem *dtablespacename = NULL;
DefElem *downer = NULL;
DefElem *dtemplate = NULL;
DefElem *dencoding = NULL;
+ DefElem *dcollation = NULL;
DefElem *dconnlimit = NULL;
char *dbname = stmt->dbname;
char *dbowner = NULL;
const char *dbtemplate = NULL;
+ char *lc_collate = NULL;
+ char *lc_ctype = NULL;
int encoding = -1;
int dbconnlimit = -1;
int ctype_encoding;
***************
*** 152,157 ****
--- 166,179 ----
errmsg("conflicting or redundant options")));
dencoding = defel;
}
+ else if (strcmp(defel->defname, "collate") == 0)
+ {
+ if (dcollation)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ dcollation = defel;
+ }
else if (strcmp(defel->defname, "connectionlimit") == 0)
{
if (dconnlimit)
***************
*** 205,210 ****
--- 227,256 ----
elog(ERROR, "unrecognized node type: %d",
nodeTag(dencoding->arg));
}
+ /*
+ if (dlc_collate && dlc_collate->arg) {
+ lc_collate = strVal(dlc_collate->arg);
+ if ((locale_collate_assign(lc_collate, false, (GucSource)NULL)) == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("%s is not a valid LC_COLLATE name",
+ lc_collate)));
+ }
+ */
+
+ if (dcollation && dcollation->arg) {
+ coltuple = SearchSysCache(COLLNAME,
+ CStringGetDatum(strVal(dcollation->arg)),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(coltuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("%s is not a valid COLLATION name",
+ strVal(dcollation->arg))));
+ datcollationoid = HeapTupleGetOid(coltuple);
+ ReleaseSysCache(coltuple);
+ }
+
if (dconnlimit && dconnlimit->arg)
dbconnlimit = intVal(dconnlimit->arg);

***************
*** 243,249 ****
if (!get_db_info(dbtemplate, ShareLock,
&src_dboid, &src_owner, &src_encoding,
&src_istemplate, &src_allowconn, &src_lastsysoid,
! &src_frozenxid, &src_deftablespace))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("template database \"%s\" does not exist",
--- 289,295 ----
if (!get_db_info(dbtemplate, ShareLock,
&src_dboid, &src_owner, &src_encoding,
&src_istemplate, &src_allowconn, &src_lastsysoid,
! &src_frozenxid, &src_deftablespace, &src_collationoid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("template database \"%s\" does not exist",
***************
*** 369,374 ****
--- 415,427 ----
/* Note there is no additional permission check in this path */
}

+ /*
+ * If collation is specified for database, use it, otherwise inherit database
+ * cluster's collation.
+ */
+ datcollationoid = OidIsValid(datcollationoid) ? datcollationoid : src_collationoid;
+
+
/*
* Check for db name conflict. This is just to give a more friendly error
* message than "unique index violation". There's a race condition but
***************
*** 414,419 ****
--- 467,473 ----
*/

/* Form tuple */
+
MemSet(new_record, 0, sizeof(new_record));
MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));

***************
*** 421,426 ****
--- 475,481 ----
DirectFunctionCall1(namein, CStringGetDatum(dbname));
new_record[Anum_pg_database_datdba - 1] = ObjectIdGetDatum(datdba);
new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding);
+ new_record[Anum_pg_database_datcollation - 1] = ObjectIdGetDatum(datcollationoid);
new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(false);
new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(true);
new_record[Anum_pg_database_datconnlimit - 1] = Int32GetDatum(dbconnlimit);
***************
*** 583,588 ****
--- 638,659 ----
* space but is not in pg_database, which is not good.
*/
database_file_update_needed();
+
+ /*
+ * Message about reindexing new database
+ */
+ if (lc_collate != src_collate || lc_ctype != src_ctype)
+ ereport(NOTICE,
+ (errmsg("database \"%s\" need to be reindexed manually (REINDEX DATABASE)",
+ dbname)));
+
+ /* {
+ * ereport(NOTICE,
+ * (errmsg("database \"%s\" is reindexed automaticly",
+ * dbname)));
+ * ReindexDatabase(dbname, true, true);
+ *}
+ */
}
PG_END_ENSURE_ERROR_CLEANUP(createdb_failure_callback,
PointerGetDatum(&fparms));
***************
*** 629,635 ****
pgdbrel = heap_open(DatabaseRelationId, RowExclusiveLock);

if (!get_db_info(dbname, AccessExclusiveLock, &db_id, NULL, NULL,
! &db_istemplate, NULL, NULL, NULL, NULL))
{
if (!missing_ok)
{
--- 700,706 ----
pgdbrel = heap_open(DatabaseRelationId, RowExclusiveLock);

if (!get_db_info(dbname, AccessExclusiveLock, &db_id, NULL, NULL,
! &db_istemplate, NULL, NULL, NULL, NULL, NULL))
{
if (!missing_ok)
{
***************
*** 781,787 ****
rel = heap_open(DatabaseRelationId, RowExclusiveLock);

if (!get_db_info(oldname, AccessExclusiveLock, &db_id, NULL, NULL,
! NULL, NULL, NULL, NULL, NULL))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database \"%s\" does not exist", oldname)));
--- 852,858 ----
rel = heap_open(DatabaseRelationId, RowExclusiveLock);

if (!get_db_info(oldname, AccessExclusiveLock, &db_id, NULL, NULL,
! NULL, NULL, NULL, NULL, NULL, NULL))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database \"%s\" does not exist", oldname)));
***************
*** 1168,1174 ****
Oid *dbIdP, Oid *ownerIdP,
int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
Oid *dbLastSysOidP, TransactionId *dbFrozenXidP,
! Oid *dbTablespace)
{
bool result = false;
Relation relation;
--- 1239,1245 ----
Oid *dbIdP, Oid *ownerIdP,
int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
Oid *dbLastSysOidP, TransactionId *dbFrozenXidP,
! Oid *dbTablespace, Oid *dbCollation)
{
bool result = false;
Relation relation;
***************
*** 1259,1264 ****
--- 1330,1338 ----
/* default tablespace for this database */
if (dbTablespace)
*dbTablespace = dbform->dattablespace;
+ /* default locale settings for this database */
+ if (dbCollation)
+ *dbCollation = dbform->datcollation;
ReleaseSysCache(tuple);
result = true;
break;
Index: include/nodes/parsenodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.371
diff -c -r1.371 parsenodes.h
*** include/nodes/parsenodes.h 7 Aug 2008 01:11:51 -0000 1.371
--- include/nodes/parsenodes.h 31 Aug 2008 19:21:10 -0000
***************
*** 1224,1229 ****
--- 1224,1249 ----
bool skip_validation; /* skip validation of existing rows? */
} FkConstraint;

+ /* ----------------------
+ * Create/Drop Collation Statements
+ * ----------------------
+ */
+
+ typedef struct CreateCollationStmt
+ {
+ NodeTag type;
+ char *name;
+ char *for_charset;
+ char *parent_collation;
+ List *options;
+ } CreateCollationStmt;
+
+ typedef struct DropCollationStmt
+ {
+ NodeTag type;
+ char *name;
+
+ } DropCollationStmt;

/* ----------------------
* Create/Drop Table Space Statements
Index: include/nodes/nodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/nodes.h,v
retrieving revision 1.209
diff -c -r1.209 nodes.h
*** include/nodes/nodes.h 22 Aug 2008 00:16:04 -0000 1.209
--- include/nodes/nodes.h 31 Aug 2008 19:21:09 -0000
***************
*** 315,320 ****
--- 315,322 ----
T_CreateEnumStmt,
T_AlterTSDictionaryStmt,
T_AlterTSConfigurationStmt,
+ T_CreateCollationStmt,
+ T_DropCollationStmt,

/*
* TAGS FOR PARSE TREE NODES (parsenodes.h)
Index: backend/access/transam/xlog.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/access/transam/xlog.c,v
retrieving revision 1.317
diff -c -r1.317 xlog.c
*** backend/access/transam/xlog.c 11 Aug 2008 11:05:10 -0000 1.317
--- backend/access/transam/xlog.c 31 Aug 2008 19:21:07 -0000
***************
*** 3832,3850 ****
#endif
ControlFile->float4ByVal = FLOAT4PASSBYVAL;
ControlFile->float8ByVal = FLOAT8PASSBYVAL;
!
! ControlFile->localeBuflen = LOCALE_NAME_BUFLEN;
! localeptr = setlocale(LC_COLLATE, NULL);
! if (!localeptr)
! ereport(PANIC,
! (errmsg("invalid LC_COLLATE setting")));
! StrNCpy(ControlFile->lc_collate, localeptr, LOCALE_NAME_BUFLEN);
! localeptr = setlocale(LC_CTYPE, NULL);
! if (!localeptr)
! ereport(PANIC,
! (errmsg("invalid LC_CTYPE setting")));
! StrNCpy(ControlFile->lc_ctype, localeptr, LOCALE_NAME_BUFLEN);
!
/* Contents are protected with a CRC */
INIT_CRC32(ControlFile->crc);
COMP_CRC32(ControlFile->crc,
--- 3832,3838 ----
#endif
ControlFile->float4ByVal = FLOAT4PASSBYVAL;
ControlFile->float8ByVal = FLOAT8PASSBYVAL;
!
/* Contents are protected with a CRC */
INIT_CRC32(ControlFile->crc);
COMP_CRC32(ControlFile->crc,
***************
*** 4083,4116 ****
" but the server was compiled without USE_FLOAT8_BYVAL."),
errhint("It looks like you need to recompile or initdb.")));
#endif
-
- if (ControlFile->localeBuflen != LOCALE_NAME_BUFLEN)
- ereport(FATAL,
- (errmsg("database files are incompatible with server"),
- errdetail("The database cluster was initialized with LOCALE_NAME_BUFLEN %d,"
- " but the server was compiled with LOCALE_NAME_BUFLEN %d.",
- ControlFile->localeBuflen, LOCALE_NAME_BUFLEN),
- errhint("It looks like you need to recompile or initdb.")));
- if (pg_perm_setlocale(LC_COLLATE, ControlFile->lc_collate) == NULL)
- ereport(FATAL,
- (errmsg("database files are incompatible with operating system"),
- errdetail("The database cluster was initialized with LC_COLLATE \"%s\","
- " which is not recognized by setlocale().",
- ControlFile->lc_collate),
- errhint("It looks like you need to initdb or install locale support.")));
- if (pg_perm_setlocale(LC_CTYPE, ControlFile->lc_ctype) == NULL)
- ereport(FATAL,
- (errmsg("database files are incompatible with operating system"),
- errdetail("The database cluster was initialized with LC_CTYPE \"%s\","
- " which is not recognized by setlocale().",
- ControlFile->lc_ctype),
- errhint("It looks like you need to initdb or install locale support.")));
-
- /* Make the fixed locale settings visible as GUC variables, too */
- SetConfigOption("lc_collate", ControlFile->lc_collate,
- PGC_INTERNAL, PGC_S_OVERRIDE);
- SetConfigOption("lc_ctype", ControlFile->lc_ctype,
- PGC_INTERNAL, PGC_S_OVERRIDE);
}

void
--- 4071,4076 ----
Index: backend/catalog/Makefile
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/catalog/Makefile,v
retrieving revision 1.66
diff -c -r1.66 Makefile
*** backend/catalog/Makefile 19 Feb 2008 10:30:07 -0000 1.66
--- backend/catalog/Makefile 31 Aug 2008 19:21:07 -0000
***************
*** 11,18 ****
include $(top_builddir)/src/Makefile.global

OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
! pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \
! pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \
pg_type.o toasting.o

BKIFILES = postgres.bki postgres.description postgres.shdescription
--- 11,18 ----
include $(top_builddir)/src/Makefile.global

OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
! pg_aggregate.o pg_collation.o pg_charset.o pg_constraint.o pg_conversion.o pg_depend.o \
! pg_enum.o pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \
pg_type.o toasting.o

BKIFILES = postgres.bki postgres.description postgres.shdescription
***************
*** 27,34 ****

POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_proc.h pg_type.h pg_attribute.h pg_class.h pg_autovacuum.h \
! pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \
! pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \
--- 27,34 ----

POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_proc.h pg_type.h pg_attribute.h pg_class.h pg_autovacuum.h \
! pg_attrdef.h pg_charset.h pg_collation.h pg_constraint.h pg_inherits.h pg_index.h \
! pg_operator.h pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \
Index: backend/utils/adt/pg_locale.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v
retrieving revision 1.41
diff -c -r1.41 pg_locale.c
*** backend/utils/adt/pg_locale.c 19 May 2008 18:08:16 -0000 1.41
--- backend/utils/adt/pg_locale.c 31 Aug 2008 19:21:08 -0000
***************
*** 228,233 ****
--- 228,245 ----
return value;
}

+ const char *
+ locale_collate_assign(const char *value, bool doit, GucSource source)
+ {
+ return locale_xxx_assign(LC_COLLATE, value, doit, source);
+ }
+
+ const char *
+ locale_ctype_assign(const char *value, bool doit, GucSource source)
+ {
+ return locale_xxx_assign(LC_CTYPE, value, doit, source);
+ }
+

const char *
locale_monetary_assign(const char *value, bool doit, GucSource source)
Index: include/catalog/pg_control.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_control.h,v
retrieving revision 1.41
diff -c -r1.41 pg_control.h
*** include/catalog/pg_control.h 21 Apr 2008 00:26:47 -0000 1.41
--- include/catalog/pg_control.h 31 Aug 2008 19:21:09 -0000
***************
*** 144,154 ****
bool float4ByVal; /* float4 pass-by-value? */
bool float8ByVal; /* float8, int8, etc pass-by-value? */

- /* active locales */
- uint32 localeBuflen;
- char lc_collate[LOCALE_NAME_BUFLEN];
- char lc_ctype[LOCALE_NAME_BUFLEN];
-
/* CRC of all above ... MUST BE LAST! */
pg_crc32 crc;
} ControlFileData;
--- 144,149 ----
Index: include/catalog/pg_database.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_database.h,v
retrieving revision 1.47
diff -c -r1.47 pg_database.h
*** include/catalog/pg_database.h 27 Mar 2008 03:57:34 -0000 1.47
--- include/catalog/pg_database.h 31 Aug 2008 19:21:09 -0000
***************
*** 33,38 ****
--- 33,39 ----
NameData datname; /* database name */
Oid datdba; /* owner of database */
int4 encoding; /* character encoding */
+ Oid datcollation; /* collation */
bool datistemplate; /* allowed as CREATE DATABASE template? */
bool datallowconn; /* new connections allowed? */
int4 datconnlimit; /* max connections allowed (-1=no limit) */
***************
*** 54,73 ****
* compiler constants for pg_database
* ----------------
*/
! #define Natts_pg_database 11
#define Anum_pg_database_datname 1
#define Anum_pg_database_datdba 2
#define Anum_pg_database_encoding 3
! #define Anum_pg_database_datistemplate 4
! #define Anum_pg_database_datallowconn 5
! #define Anum_pg_database_datconnlimit 6
! #define Anum_pg_database_datlastsysoid 7
! #define Anum_pg_database_datfrozenxid 8
! #define Anum_pg_database_dattablespace 9
! #define Anum_pg_database_datconfig 10
! #define Anum_pg_database_datacl 11

! DATA(insert OID = 1 ( template1 PGUID ENCODING t t -1 0 0 1663 _null_ _null_ ));
SHDESCR("default template database");
#define TemplateDbOid 1

--- 55,75 ----
* compiler constants for pg_database
* ----------------
*/
! #define Natts_pg_database 12
#define Anum_pg_database_datname 1
#define Anum_pg_database_datdba 2
#define Anum_pg_database_encoding 3
! #define Anum_pg_database_datcollation 4
! #define Anum_pg_database_datistemplate 5
! #define Anum_pg_database_datallowconn 6
! #define Anum_pg_database_datconnlimit 7
! #define Anum_pg_database_datlastsysoid 8
! #define Anum_pg_database_datfrozenxid 9
! #define Anum_pg_database_dattablespace 10
! #define Anum_pg_database_datconfig 11
! #define Anum_pg_database_datacl 12

! DATA(insert OID = 1 ( template1 PGUID ENCODING 2988 t t -1 0 0 1663 _null_ _null_ ));
SHDESCR("default template database");
#define TemplateDbOid 1

Index: include/catalog/indexing.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/indexing.h,v
retrieving revision 1.103
diff -c -r1.103 indexing.h
*** include/catalog/indexing.h 19 Jun 2008 00:46:06 -0000 1.103
--- include/catalog/indexing.h 31 Aug 2008 19:21:09 -0000
***************
*** 105,115 ****
--- 105,125 ----
DECLARE_UNIQUE_INDEX(pg_cast_source_target_index, 2661, on pg_cast using btree(castsource oid_ops, casttarget oid_ops));
#define CastSourceTargetIndexId 2661

+ DECLARE_UNIQUE_INDEX(pg_charset_name_index, 2179, on pg_charset using btree(charsetname name_ops));
+ #define CharsetNameIndexId 2179
+ DECLARE_UNIQUE_INDEX(pg_charset_oid_index, 2316, on pg_charset using btree(oid oid_ops));
+ #define CharsetOidIndexId 2316
+
DECLARE_UNIQUE_INDEX(pg_class_oid_index, 2662, on pg_class using btree(oid oid_ops));
#define ClassOidIndexId 2662
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_index, 2181, on pg_collation using btree(colname name_ops));
+ #define CollationNameIndexId 2181
+ DECLARE_UNIQUE_INDEX(pg_collation_oid_index, 2232, on pg_collation using btree(oid oid_ops));
+ #define CollationOidIndexId 2232
+
/* 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
Index: backend/utils/init/postinit.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/init/postinit.c,v
retrieving revision 1.184
diff -c -r1.184 postinit.c
*** backend/utils/init/postinit.c 12 May 2008 00:00:52 -0000 1.184
--- backend/utils/init/postinit.c 31 Aug 2008 19:21:08 -0000
***************
*** 23,28 ****
--- 23,30 ----
#include "catalog/catalog.h"
#include "catalog/namespace.h"
#include "catalog/pg_authid.h"
+ #include "catalog/pg_collation.h"
+ #include "catalog/pg_charset.h"
#include "catalog/pg_database.h"
#include "catalog/pg_tablespace.h"
#include "libpq/hba.h"
***************
*** 156,164 ****
static void
CheckMyDatabase(const char *name, bool am_superuser)
{
! HeapTuple tup;
! Form_pg_database dbform;
!
/* Fetch our real pg_database row */
tup = SearchSysCache(DATABASEOID,
ObjectIdGetDatum(MyDatabaseId),
--- 158,173 ----
static void
CheckMyDatabase(const char *name, bool am_superuser)
{
! HeapTuple tup;
! HeapTuple localetup;
! Form_pg_database dbform;
! Form_pg_charset dbcharset;
! Form_pg_collation dbcollation;
! Oid collationoid;
! Oid charsetoid;
! char *collate;
! char *ctype;
!
/* Fetch our real pg_database row */
tup = SearchSysCache(DATABASEOID,
ObjectIdGetDatum(MyDatabaseId),
***************
*** 239,244 ****
--- 248,295 ----
/* If we have no other source of client_encoding, use server encoding */
SetConfigOption("client_encoding", GetDatabaseEncodingName(),
PGC_BACKEND, PGC_S_DEFAULT);
+ /* Get database collation oid */
+ collationoid = dbform->datcollation;
+ /* Fetch pg_collation record */
+ localetup = SearchSysCache(COLLOID,
+ ObjectIdGetDatum(collationoid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(localetup))
+ elog(ERROR, "cache lookup failed for collation %u", collationoid);
+ dbcollation = (Form_pg_collation) GETSTRUCT(localetup);
+ ReleaseSysCache(localetup);
+ /* Fetch pg_charset record */
+ charsetoid = dbcollation->colcharset;
+ localetup = SearchSysCache(CHARSETOID,
+ ObjectIdGetDatum(charsetoid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for charset %u", charsetoid);
+ dbcharset = (Form_pg_charset) GETSTRUCT(localetup);
+ ReleaseSysCache(localetup);
+
+ /* assign locale variables */
+ collate = NameStr(dbcollation->colcollate);
+ ctype = NameStr(dbcharset->charsettype);
+
+ if (setlocale(LC_COLLATE, collate) == NULL)
+ ereport(FATAL,
+ (errmsg("database local is incompatible with OS"),
+ errdetail("The database was initialized with LC_COLLATE \"%s\", "
+ " which is not recognized by setlocale().", collate),
+ errhint("Try to recreate the database or install locale support.")));
+
+ if (setlocale(LC_CTYPE, ctype) == NULL)
+ ereport(FATAL,
+ (errmsg("database local is incompatible with OS"),
+ errdetail("The database was initialized with LC_CTYPE \"%s\", "
+ " which is not recognized by setlocale().", ctype),
+ errhint("Try to recreate the database or install locale support.")));
+
+ /* Record it as a GUC internal option, too */
+
+ SetConfigOption("lc_collate", collate, PGC_INTERNAL, PGC_S_DATABASE);
+ SetConfigOption("lc_ctype", ctype, PGC_INTERNAL, PGC_S_DATABASE);

/*
* Lastly, set up any database-specific configuration variables.
Index: bin/initdb/initdb.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/initdb/initdb.c,v
retrieving revision 1.159
diff -c -r1.159 initdb.c
*** bin/initdb/initdb.c 5 Aug 2008 12:09:30 -0000 1.159
--- bin/initdb/initdb.c 31 Aug 2008 19:21:08 -0000
***************
*** 1171,1176 ****
--- 1171,1184 ----
conflines = replace_token(conflines, "#port = 5432", repltok);
#endif

+ snprintf(repltok, sizeof(repltok), "lc_collate = '%s'",
+ escape_quotes(lc_collate));
+ conflines = replace_token(conflines, "#lc_collate = 'C'", repltok);
+
+ snprintf(repltok, sizeof(repltok), "lc_ctype = '%s'",
+ escape_quotes(lc_collate));
+ conflines = replace_token(conflines, "#lc_ctype = 'C'", repltok);
+
snprintf(repltok, sizeof(repltok), "lc_messages = '%s'",
escape_quotes(lc_messages));
conflines = replace_token(conflines, "#lc_messages = 'C'", repltok);
***************
*** 1353,1358 ****
--- 1361,1370 ----

bki_lines = replace_token(bki_lines, "ENCODING", encodingid);

+ bki_lines = replace_token(bki_lines, "LC_COLLATE", lc_collate);
+
+ bki_lines = replace_token(bki_lines, "LC_CTYPE", lc_ctype);
+
/*
* Pass correct LC_xxx environment to bootstrap.
*
***************
*** 2806,2815 ****
strcmp(lc_ctype, lc_numeric) == 0 &&
strcmp(lc_ctype, lc_monetary) == 0 &&
strcmp(lc_ctype, lc_messages) == 0)
! printf(_("The database cluster will be initialized with locale %s.\n"), lc_ctype);
else
{
! printf(_("The database cluster will be initialized with locales\n"
" COLLATE: %s\n"
" CTYPE: %s\n"
" MESSAGES: %s\n"
--- 2818,2827 ----
strcmp(lc_ctype, lc_numeric) == 0 &&
strcmp(lc_ctype, lc_monetary) == 0 &&
strcmp(lc_ctype, lc_messages) == 0)
! printf(_("The database template1 will be initialized with locale %s.\n"), lc_ctype);
else
{
! printf(_("The database template1 will be initialized with locales\n"
" COLLATE: %s\n"
" CTYPE: %s\n"
" MESSAGES: %s\n"
Index: bin/scripts/createdb.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/scripts/createdb.c,v
retrieving revision 1.26
diff -c -r1.26 createdb.c
*** bin/scripts/createdb.c 1 Jan 2008 19:45:56 -0000 1.26
--- bin/scripts/createdb.c 31 Aug 2008 19:21:09 -0000
***************
*** 32,37 ****
--- 32,39 ----
{"tablespace", required_argument, NULL, 'D'},
{"template", required_argument, NULL, 'T'},
{"encoding", required_argument, NULL, 'E'},
+ {"lc-collate", required_argument, NULL, 1},
+ {"lc-ctype", required_argument, NULL, 2},
{NULL, 0, NULL, 0}
};

***************
*** 50,55 ****
--- 52,59 ----
char *tablespace = NULL;
char *template = NULL;
char *encoding = NULL;
+ char *lc_collate = NULL;
+ char *lc_ctype = NULL;

PQExpBufferData sql;

***************
*** 95,100 ****
--- 99,110 ----
case 'E':
encoding = optarg;
break;
+ case 1:
+ lc_collate = optarg;
+ break;
+ case 2:
+ lc_ctype = optarg;
+ break;
default:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(1);
***************
*** 152,159 ****
appendPQExpBuffer(&sql, " ENCODING '%s'", encoding);
if (template)
appendPQExpBuffer(&sql, " TEMPLATE %s", fmtId(template));
appendPQExpBuffer(&sql, ";\n");
!
conn = connectDatabase(strcmp(dbname, "postgres") == 0 ? "template1" : "postgres",
host, port, username, password, progname);

--- 162,174 ----
appendPQExpBuffer(&sql, " ENCODING '%s'", encoding);
if (template)
appendPQExpBuffer(&sql, " TEMPLATE %s", fmtId(template));
+ if (lc_collate)
+ appendPQExpBuffer(&sql, " LCCOLLATE %s", fmtId(lc_collate));
+ if (lc_ctype)
+ appendPQExpBuffer(&sql, " LCCTYPE %s", fmtId(lc_ctype));
+
appendPQExpBuffer(&sql, ";\n");
!
conn = connectDatabase(strcmp(dbname, "postgres") == 0 ? "template1" : "postgres",
host, port, username, password, progname);

***************
*** 207,224 ****
printf(_("Usage:\n"));
printf(_(" %s [OPTION]... [DBNAME] [DESCRIPTION]\n"), progname);
printf(_("\nOptions:\n"));
! printf(_(" -D, --tablespace=TABLESPACE default tablespace for the database\n"));
! printf(_(" -E, --encoding=ENCODING encoding for the database\n"));
! printf(_(" -O, --owner=OWNER database user to own the new database\n"));
! printf(_(" -T, --template=TEMPLATE template database to copy\n"));
! printf(_(" -e, --echo show the commands being sent to the server\n"));
! printf(_(" --help show this help, then exit\n"));
! printf(_(" --version output version information, then exit\n"));
printf(_("\nConnection options:\n"));
! printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
! printf(_(" -p, --port=PORT database server port\n"));
! printf(_(" -U, --username=USERNAME user name to connect as\n"));
! printf(_(" -W, --password force password prompt\n"));
printf(_("\nBy default, a database with the same name as the current user is created.\n"));
printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
}
--- 222,240 ----
printf(_("Usage:\n"));
printf(_(" %s [OPTION]... [DBNAME] [DESCRIPTION]\n"), progname);
printf(_("\nOptions:\n"));
! printf(_(" -D, --tablespace=TABLESPACE default tablespace for the database\n"));
! printf(_(" -E, --encoding=ENCODING encoding for the database\n"));
! printf(_(" --lc-collate, --lc-ctype=LOCALE locale for the database\n"));
! printf(_(" -O, --owner=OWNER database user to own the new database\n"));
! printf(_(" -T, --template=TEMPLATE template database to copy\n"));
! printf(_(" -e, --echo show the commands being sent to the server\n"));
! printf(_(" --help show this help, then exit\n"));
! printf(_(" --version output version information, then exit\n"));
printf(_("\nConnection options:\n"));
! printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
! printf(_(" -p, --port=PORT database server port\n"));
! printf(_(" -U, --username=USERNAME user name to connect as\n"));
! printf(_(" -W, --password force password prompt\n"));
printf(_("\nBy default, a database with the same name as the current user is created.\n"));
printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
}
Index: bin/pg_controldata/pg_controldata.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/pg_controldata/pg_controldata.c,v
retrieving revision 1.39
diff -c -r1.39 pg_controldata.c
*** bin/pg_controldata/pg_controldata.c 21 Apr 2008 00:26:46 -0000 1.39
--- bin/pg_controldata/pg_controldata.c 31 Aug 2008 19:21:08 -0000
***************
*** 220,231 ****
(ControlFile.float4ByVal ? _("by value") : _("by reference")));
printf(_("Float8 argument passing: %s\n"),
(ControlFile.float8ByVal ? _("by value") : _("by reference")));
- printf(_("Maximum length of locale name: %u\n"),
- ControlFile.localeBuflen);
- printf(_("LC_COLLATE: %s\n"),
- ControlFile.lc_collate);
- printf(_("LC_CTYPE: %s\n"),
- ControlFile.lc_ctype);
-
return 0;
}
--- 220,224 ----
Index: backend/tcop/utility.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.296
diff -c -r1.296 utility.c
*** backend/tcop/utility.c 13 Aug 2008 00:07:50 -0000 1.296
--- backend/tcop/utility.c 31 Aug 2008 19:21:08 -0000
***************
*** 24,29 ****
--- 24,30 ----
#include "commands/alter.h"
#include "commands/async.h"
#include "commands/cluster.h"
+ #include "commands/collation.h"
#include "commands/comment.h"
#include "commands/conversioncmds.h"
#include "commands/copy.h"
***************
*** 166,171 ****
--- 167,173 ----
case T_CommentStmt:
case T_DefineStmt:
case T_CreateCastStmt:
+ case T_CreateCollationStmt:
case T_CreateConversionStmt:
case T_CreatedbStmt:
case T_CreateDomainStmt:
***************
*** 1023,1028 ****
--- 1025,1038 ----
AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree);
break;

+ case T_CreateCollationStmt:
+ DefineCollation((CreateCollationStmt *) parsetree);
+ break;
+
+ case T_DropCollationStmt:
+ DropCollation((DropCollationStmt *) parsetree);
+ break;
+
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(parsetree));
Index: bin/pg_resetxlog/pg_resetxlog.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v
retrieving revision 1.65
diff -c -r1.65 pg_resetxlog.c
*** bin/pg_resetxlog/pg_resetxlog.c 21 Apr 2008 00:26:46 -0000 1.65
--- bin/pg_resetxlog/pg_resetxlog.c 31 Aug 2008 19:21:08 -0000
***************
*** 493,514 ****
#endif
ControlFile.float4ByVal = FLOAT4PASSBYVAL;
ControlFile.float8ByVal = FLOAT8PASSBYVAL;
- ControlFile.localeBuflen = LOCALE_NAME_BUFLEN;
-
- localeptr = setlocale(LC_COLLATE, "");
- if (!localeptr)
- {
- fprintf(stderr, _("%s: invalid LC_COLLATE setting\n"), progname);
- exit(1);
- }
- strlcpy(ControlFile.lc_collate, localeptr, sizeof(ControlFile.lc_collate));
- localeptr = setlocale(LC_CTYPE, "");
- if (!localeptr)
- {
- fprintf(stderr, _("%s: invalid LC_CTYPE setting\n"), progname);
- exit(1);
- }
- strlcpy(ControlFile.lc_ctype, localeptr, sizeof(ControlFile.lc_ctype));

/*
* XXX eventually, should try to grovel through old XLOG to develop more
--- 493,498 ----
***************
*** 584,595 ****
(ControlFile.float4ByVal ? _("by value") : _("by reference")));
printf(_("Float8 argument passing: %s\n"),
(ControlFile.float8ByVal ? _("by value") : _("by reference")));
- printf(_("Maximum length of locale name: %u\n"),
- ControlFile.localeBuflen);
- printf(_("LC_COLLATE: %s\n"),
- ControlFile.lc_collate);
- printf(_("LC_CTYPE: %s\n"),
- ControlFile.lc_ctype);
}


--- 568,573 ----
Index: src/include/catalog/pg_collation.h
===================================================================
RCS file: src/include/catalog/pg_collation.h
diff -N src/include/catalog/pg_collation.h
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- src/include/catalog/pg_collation.h 1 Jan 1970 00:00:00 -0000
***************
*** 0 ****
--- 1,115 ----
+ /*-------------------------------------------------------------------------
+ *
+ * pg_collation.h
+ * definition of the system "collation" relation (pg_collation)
+ * along with the relation's initial contents.
+ *
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL:
+ *
+ * NOTES
+ * the genbki.sh 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
+ *
+ * colname collation name
+ * colschema collation schema
+ * colencoding encoding name
+ * colpadattribute pad attribute
+ * colcasesensitive case sensitive
+ * colcollate lc_collate
+ * colcharset collation charset
+ * colfunc used collation function
+ *
+ * ----------------------------------------------------------------
+ */
+
+ #define CollationRelationId 2328
+
+
+ enum {
+ PAD_CHARACTERISTIC_NO_PAD = 0,
+ PAD_CHARACTERISTIC_PAD_SPACE = 1
+
+ } CollationPadCharacteristic;
+
+ enum {
+ CASE_INSENSITIVE = 0,
+ CASE_SENSITIVE = 1
+ } CollationCaseSensitive;
+
+ enum {
+ FUNCTION_BUILTIN = 0,
+ FUNCTION_SYSTEM = 1
+ } CollationFunction;
+
+ CATALOG(pg_collation,2328)
+ {
+ NameData colname;
+ Oid colschema;
+ bool colpadattribute;
+ bool colcasesensitive;
+ NameData colcollate;
+ Oid colcharset;
+ int2 colfunc;
+ } FormData_pg_collation;
+
+ /* ----------------
+ * Form_pg_collation corresponds to a pointer to a tuple with
+ * the format of pg_collation relation.
+ * ----------------
+ */
+ typedef FormData_pg_collation *Form_pg_collation;
+
+ /* ----------------
+ * compiler constants for pg_collation
+ * ----------------
+ */
+ #define Natts_pg_collation 7
+ #define Anum_pg_collation_colname 1
+ #define Anum_pg_collation_colschema 2
+ #define Anum_pg_collation_colpadattribute 3
+ #define Anum_pg_collation_colcasesensitive 4
+ #define Anum_pg_collation_colcollate 5
+ #define Anum_pg_collation_colcharset 6
+ #define Anum_pg_collation_colfunc 7
+
+ /* ----------------
+ * initial contents of pg_collation
+ * ----------------
+ */
+
+ DATA(insert OID = 2982 ( "LATIN1" PGNSP t t "C" 2182 1));
+ DATA(insert OID = 2983 ( "ISO8BIT" PGNSP t t "C" 2183 1));
+ DATA(insert OID = 2984 ( "UNICODE" PGNSP t t "C" 2184 1));
+ DATA(insert OID = 2988 ( "DEFAULT" PGNSP t t "LC_COLLATE" 2185 1));
+
+ /* ----------------
+ * prototypes for functions in pg_collation.c
+ * ----------------
+ */
+ extern Oid CollationCreateEntry(const char *collationName,
+ Oid collationSchema,
+ bool padAttribute,
+ bool caseSensitive,
+ const char *collate,
+ Oid charset,
+ int8 collationFunction);
+
+ extern void CollationDeleteEntry(const char *collationName);
+
+ #endif /* PG_COLLATION_H */
Index: src/interfaces/ecpg/include/ecpg_config.h
===================================================================
RCS file: src/interfaces/ecpg/include/ecpg_config.h
diff -N src/interfaces/ecpg/include/ecpg_config.h
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- src/interfaces/ecpg/include/ecpg_config.h 1 Jan 1970 00:00:00 -0000
***************
*** 0 ****
--- 1,18 ----
+ /* src/interfaces/ecpg/include/ecpg_config.h. Generated by configure. */
+ /* Define to 1 if the system has the type `int64'. */
+ /* #undef HAVE_INT64 */
+
+ /* Define to 1 if `long int' works and is 64 bits. */
+ /* #undef HAVE_LONG_INT_64 */
+
+ /* Define to 1 if `long long int' works and is 64 bits. */
+ #define HAVE_LONG_LONG_INT_64
+
+ /* Define to 1 if you want 64-bit integer timestamp and interval support.
+ (--enable-integer-datetimes) */
+ /* #undef USE_INTEGER_DATETIMES */
+
+ /* Define to 1 to build client libraries as thread-safe code.
+ * (--enable-thread-safety) */
+ /* #undef ENABLE_THREAD_SAFETY */
+
Index: src/backend/catalog/pg_collation.c
===================================================================
RCS file: src/backend/catalog/pg_collation.c
diff -N src/backend/catalog/pg_collation.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- src/backend/catalog/pg_collation.c 1 Jan 1970 00:00:00 -0000
***************
*** 0 ****
--- 1,138 ----
+ /*-------------------------------------------------------------------------
+ *
+ * pg_collation.c
+ * routines to support manipulation of the pg_collation relation
+ *
+ * Copyright (c) 2006-2008, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ * $PostgreSQL:
+ *
+ *-------------------------------------------------------------------------
+ */
+ #include "postgres.h"
+
+ #include "access/genam.h"
+ #include "access/heapam.h"
+ #include "access/htup.h"
+ #include "access/relscan.h"
+ #include "access/skey.h"
+ #include "catalog/catalog.h"
+ #include "catalog/indexing.h"
+ #include "catalog/pg_collation.h"
+ #include "utils/acl.h"
+ #include "utils/builtins.h"
+ #include "utils/fmgroids.h"
+ #include "utils/rel.h"
+ #include "utils/syscache.h"
+ #include "utils/tqual.h"
+
+
+ Oid
+ CollationCreateEntry(const char *collationName,
+ Oid collationSchema,
+ bool padAttribute,
+ bool caseSensitive,
+ const char *collate,
+ Oid charset,
+ int8 collationFunction)
+ {
+
+ Relation pg_collation;
+ HeapTuple tup;
+ TupleDesc tupDesc;
+ Datum values[Natts_pg_collation];
+ char nulls[Natts_pg_collation];
+ Oid oid;
+ Oid collOid;
+ NameData cname;
+ NameData ccollate;
+
+
+ /* ereport(WARNING, (errcode(ERRCODE_WARNING),
+ * errmsg("DEBUG (create collation): collation name - '%s', collate - '%s', padattribute - '%d', coll fn - '%d'",
+ * collationName,
+ * collate,
+ * padAttribute,
+ * collationFunction
+ * )));
+ *
+ * ereport(WARNING, (errcode(ERRCODE_WARNING),
+ * errmsg("TEST")));
+ */
+ Assert(collationName);
+ namestrcpy(&cname, collationName);
+
+ Assert(collate);
+ namestrcpy(&ccollate, collate);
+
+ pg_collation = heap_open(CollationRelationId, RowExclusiveLock);
+
+ /* check uniqueness */
+ if (HeapTupleIsValid(SearchSysCache(COLLNAME,
+ CStringGetDatum(collationName),
+ 0, 0, 0)))
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("collation \"%s\" already exists",
+ collationName)));
+
+ /* allocate new oid */
+ oid = GetNewOid(pg_collation);
+ if (!OidIsValid(oid))
+ ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
+ errmsg("Can't allocate new pg_collation oid.")));
+
+ tupDesc = RelationGetDescr(pg_collation);
+
+ /* prepare entries */
+ memset(nulls, ' ', sizeof(nulls));
+
+ values[Anum_pg_collation_colname - 1] = NameGetDatum(&cname);
+ values[Anum_pg_collation_colschema - 1] = ObjectIdGetDatum(collationSchema);
+ values[Anum_pg_collation_colpadattribute - 1] = BoolGetDatum(padAttribute);
+ values[Anum_pg_collation_colcasesensitive - 1] = BoolGetDatum(caseSensitive);
+ values[Anum_pg_collation_colcollate - 1] = NameGetDatum(&ccollate);
+ values[Anum_pg_collation_colcharset - 1] = ObjectIdGetDatum(charset);
+ values[Anum_pg_collation_colfunc - 1] = Int8GetDatum(collationFunction);
+
+ tup = heap_formtuple(tupDesc, values, nulls);
+ /* HeapTupleSetOid(tup, oid); */
+
+ collOid = simple_heap_insert(pg_collation, tup);
+
+ CatalogUpdateIndexes(pg_collation, tup);
+
+ heap_freetuple(tup);
+
+ heap_close(pg_collation, RowExclusiveLock);
+
+ return collOid;
+ }
+
+ void
+ CollationDeleteEntry(const char *collationName)
+ {
+ Relation pg_collation;
+ HeapTuple tup;
+
+ Assert(collationName);
+
+ pg_collation = heap_open(CollationRelationId, RowExclusiveLock);
+
+ tup = SearchSysCache(COLLNAME, CStringGetDatum(collationName), 0, 0, 0);
+
+ if (HeapTupleIsValid(tup))
+ simple_heap_delete(pg_collation, &tup->t_self);
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("collation \"%s\" does not exist",
+ collationName)));
+
+ ReleaseSysCache(tup);
+
+ heap_close(pg_collation, RowExclusiveLock);
+ }
+
Index: src/include/commands/collation.h
===================================================================
RCS file: src/include/commands/collation.h
diff -N src/include/commands/collation.h
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- src/include/commands/collation.h 1 Jan 1970 00:00:00 -0000
***************
*** 0 ****
--- 1,21 ----
+ /*-------------------------------------------------------------------------
+ *
+ * collation.h
+ * prototypes for commands/collation.c
+ *
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/include/commands/collation.h,v 1.1 2008/01/01 19:45:57 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef COLLATION_H
+ #define COLLATION_H
+
+ #include "nodes/parsenodes.h"
+
+ extern void DefineCollation(CreateCollationStmt *stmt);
+
+ #endif /* COLLATION_H */
Index: src/backend/commands/collation.c
===================================================================
RCS file: src/backend/commands/collation.c
diff -N src/backend/commands/collation.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- src/backend/commands/collation.c 1 Jan 1970 00:00:00 -0000
***************
*** 0 ****
--- 1,195 ----
+ /*-------------------------------------------------------------------------
+ *
+ * collation.c
+ * the Postgres collation support
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $PostgreSQL:
+ *
+ *-------------------------------------------------------------------------
+ */
+ #include "postgres.h"
+ #include "c.h"
+
+ #include "access/genam.h"
+ #include "access/heapam.h"
+ #include "access/htup.h"
+ #include "access/skey.h"
+ #include "access/xact.h"
+ #include "access/xlogutils.h"
+ #include "catalog/catalog.h"
+ #include "catalog/dependency.h"
+ #include "catalog/indexing.h"
+ #include "catalog/pg_charset.h"
+ #include "catalog/pg_collation.h"
+ #include "catalog/pg_namespace.h"
+ #include "commands/defrem.h"
+ #include "utils/builtins.h"
+ #include "utils/fmgroids.h"
+ #include "utils/pg_locale.h"
+ #include "utils/syscache.h"
+ #include "utils/tqual.h"
+
+ /*
+ * CREATE COLLATION
+ */
+ void
+ DefineCollation(CreateCollationStmt *stmt)
+ {
+ const char *collationname = stmt->name;
+ const char *charsetname = stmt->for_charset;
+ const char *parentcollationname = stmt->parent_collation;
+ char *charsetctype = NULL;
+ char *collationcollate = NULL;
+ Oid schemaid;
+ Oid charsetid;
+ HeapTuple coltuple;
+ HeapTuple chartuple;
+ Form_pg_collation parentcollation;
+ ListCell *option;
+
+ /* debug stuff */
+
+ /* ereport(WARNING, (errcode(ERRCODE_WARNING),
+ errmsg("DEBUG: collation name - '%s', parent collation - '%s', charset for - '%s'",
+ collationname, parentcollationname, charsetname))); */
+
+ /* retrieve parent collation and copy parameters */
+
+ /* colrel = heap_open(CollationRelationId, RowShareLock);
+ *
+ * ScanKeyInit(&colkey[0],
+ * Anum_pg_collation_colname,
+ * BTEqualStrategyNumber, F_NAMEEQ,
+ * NameGetDatum(parentcollationname));
+ *
+ * scan = systable_beginscan(colrel, CollationRelationId, true,
+ * SnapshotNow, 1, colkey);
+ *
+ * coltuple = systable_getnext(scan);
+ *
+ */
+
+ coltuple = SearchSysCache(COLLNAME,
+ CStringGetDatum(parentcollationname),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(coltuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("parent collation \"%s\" does not exist",
+ parentcollationname)));
+
+ parentcollation = (Form_pg_collation) GETSTRUCT(coltuple);
+
+ ReleaseSysCache(coltuple);
+
+ /* TODO sanity checks (duplicate options values etc.) */
+
+ /* override parent collation with new option values */
+
+ foreach(option, stmt->options)
+ {
+ DefElem *defel = (DefElem *) lfirst(option);
+
+ if (strcmp(defel->defname, "pad_characteristic") == 0)
+ {
+ if (defGetNumeric(defel) == FALSE)
+ parentcollation->colpadattribute = PAD_CHARACTERISTIC_NO_PAD;
+ else
+ parentcollation->colpadattribute = PAD_CHARACTERISTIC_PAD_SPACE;
+ }
+ else if (strcmp(defel->defname, "case_sensitive") == 0)
+ {
+ if (defGetNumeric(defel) == FALSE)
+ parentcollation->colcasesensitive = CASE_INSENSITIVE;
+ else
+ parentcollation->colcasesensitive = CASE_SENSITIVE;
+ }
+ else if (strcmp(defel->defname, "lc_collate_name") == 0)
+ {
+ if (defel->arg != NULL)
+ {
+ collationcollate = (char *)palloc((strlen(defGetString(defel)) + 1) * sizeof(char));
+ strcpy(collationcollate, defGetString(defel));
+ }
+ }
+ else if (strcmp(defel->defname, "lc_ctype_name") == 0)
+ {
+ if (defel->arg != NULL)
+ {
+ charsetctype = (char *)palloc((strlen(defGetString(defel)) + 1) * sizeof(char));
+ strcpy(charsetctype, defGetString(defel));
+ }
+ }
+ else if (strcmp(defel->defname, "str_col_function") == 0)
+ {
+ parentcollation->colfunc = defGetNumeric(defel);
+ }
+
+ }
+
+ if (collationcollate == NULL)
+ {
+ collationcollate = (char *)palloc((strlen((char *)parentcollation->colcollate.data) + 1) * sizeof(char));
+ strcpy(collationcollate, (char *)parentcollation->colcollate.data);
+ }
+
+ /* get character OID */
+ chartuple = SearchSysCache(CHARSETNAME,
+ CStringGetDatum(charsetname),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(chartuple))
+ {
+
+ /* create record in pg_charset */
+ if (charsetctype != NULL)
+ {
+ charsetid = CharsetCreateEntry(charsetname, PG_PUBLIC_NAMESPACE, charsetctype);
+ ereport(WARNING, (errcode(ERRCODE_WARNING),
+ errmsg("DEBUG (create charset): charset name - '%s', charset namespace - '%d', LC_CTYPE - '%s'",
+ charsetname,
+ PG_PUBLIC_NAMESPACE,
+ charsetctype
+ )));
+ }
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("LCCTYPE not specified")));
+
+ /* TODO check duplicite names */
+ }
+ else
+ {
+
+ /* all good */
+ charsetid = HeapTupleGetOid(chartuple);
+ ReleaseSysCache(chartuple);
+ }
+
+ /* create catalog record */
+ CollationCreateEntry(collationname,
+ PG_PUBLIC_NAMESPACE,
+ parentcollation->colpadattribute,
+ parentcollation->colcasesensitive,
+ collationcollate,
+ charsetid,
+ 1);
+
+
+ if (collationcollate != NULL) pfree(collationcollate);
+ if (charsetctype != NULL) pfree(charsetctype);
+
+ }
+
+ void
+ DropCollation(DropCollationStmt *stmt)
+ {
+ CollationDeleteEntry(stmt->name);
+ }
Index: src/backend/catalog/pg_charset.c
===================================================================
RCS file: src/backend/catalog/pg_charset.c
diff -N src/backend/catalog/pg_charset.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- src/backend/catalog/pg_charset.c 1 Jan 1970 00:00:00 -0000
***************
*** 0 ****
--- 1,83 ----
+ /*-------------------------------------------------------------------------
+ *
+ * pg_charset.c
+ * routines to support manipulation of the pg_collation relation
+ *
+ * Copyright (c) 2006-2008, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ * $PostgreSQL:
+ *
+ *-------------------------------------------------------------------------
+ */
+
+ #include "postgres.h"
+
+ #include "access/genam.h"
+ #include "access/heapam.h"
+ #include "catalog/catalog.h"
+ #include "catalog/indexing.h"
+ #include "catalog/pg_charset.h"
+ #include "utils/builtins.h"
+ #include "utils/rel.h"
+ #include "utils/syscache.h"
+ #include "utils/tqual.h"
+
+ Oid CharsetCreateEntry(const char *charsetName,
+ Oid charsetSchema,
+ const char *charsetType)
+ {
+ Relation pg_charset;
+ HeapTuple tup;
+ TupleDesc tupDesc;
+ Datum values[Natts_pg_charset];
+ char nulls[Natts_pg_charset];
+ Oid oid;
+ Oid charOid;
+ NameData chName;
+ NameData chType;
+
+ Assert(charsetName);
+ namestrcpy(&chName, charsetName);
+
+ Assert(charsetType);
+ namestrcpy(&chType, charsetType);
+
+ pg_charset = heap_open(CharsetRelationId, RowExclusiveLock);
+
+ /* check uniqueness */
+ if (HeapTupleIsValid(SearchSysCache(CHARSETNAME,
+ CStringGetDatum(charsetName),
+ 0, 0, 0)))
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("charset \"%s\" already exists",
+ charsetName)));
+
+ /* allocate new oid */
+ oid = GetNewOid(pg_charset);
+ if (!OidIsValid(oid))
+ ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
+ errmsg("Can't allocate new pg_charset oid.")));
+
+ tupDesc = RelationGetDescr(pg_charset);
+
+ /* prepare entries */
+ memset(nulls, ' ', sizeof(nulls));
+
+ values[Anum_pg_charset_charsetname - 1] = NameGetDatum(&chName);
+ values[Anum_pg_charset_charsetschema - 1] = ObjectIdGetDatum(charsetSchema);
+ values[Anum_pg_charset_charsettype - 1] = NameGetDatum(&chType);
+
+ tup = heap_formtuple(tupDesc, values, nulls);
+ /* HeapTupleSetOid(tup, oid); */
+
+ charOid = simple_heap_insert(pg_charset, tup);
+ CatalogUpdateIndexes(pg_charset, tup);
+ heap_freetuple(tup);
+
+ heap_close(pg_charset, RowExclusiveLock);
+
+ return charOid;
+ }
Index: src/include/catalog/pg_charset.h
===================================================================
RCS file: src/include/catalog/pg_charset.h
diff -N src/include/catalog/pg_charset.h
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- src/include/catalog/pg_charset.h 1 Jan 1970 00:00:00 -0000
***************
*** 0 ****
--- 1,82 ----
+ /*-------------------------------------------------------------------------
+ *
+ * pg_charset.h
+ * definition of the system "pg_charset" relation (pg_charset)
+ * along with the relation's initial contents.
+ *
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL:
+ *
+ * NOTES
+ * the genbki.sh script reads this file and generates .bki
+ * information from the DATA() statements.
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef PG_CHARSET_H
+ #define PG_CHARSET_H
+
+ #include "catalog/genbki.h"
+
+ /* ----------------------------------------------------------------
+ * pg_charset definition.
+ *
+ * cpp turns this into typedef struct FormData_pg_charset
+ *
+ * charsetname character set name
+ * charsetschema character set schema
+ * charsettype character set type
+ * charsetfunc character set function
+ * (sets the charset)
+ *
+ * ----------------------------------------------------------------
+ */
+
+ #define CharsetRelationId 2981
+
+ CATALOG(pg_charset,2981)
+ {
+ NameData charsetname;
+ Oid charsetschema;
+ NameData charsettype;
+ } FormData_pg_charset;
+
+ /* ----------------
+ * Form_pg_charset corresponds to a pointer to a tuple with
+ * the format of pg_collation relation.
+ * ----------------
+ */
+ typedef FormData_pg_charset *Form_pg_charset;
+
+ /* ----------------
+ * compiler constants for pg_collation
+ * ----------------
+ */
+ #define Natts_pg_charset 3
+ #define Anum_pg_charset_charsetname 1
+ #define Anum_pg_charset_charsetschema 2
+ #define Anum_pg_charset_charsettype 3
+
+ /* ----------------
+ * initial contents of pg_charset
+ * ----------------
+ */
+
+ DATA(insert OID = 2182 ( "LATIN1" PGNSP "C" ));
+ DATA(insert OID = 2183 ( "ISO8BIT" PGNSP "C" ));
+ DATA(insert OID = 2184 ( "UTF-8" PGNSP "C" ));
+ DATA(insert OID = 2185 ( "DEFAULT" PGNSP "LC_CTYPE" ));
+
+ /* ----------------
+ * prototypes for functions in pg_charset.c
+ * ----------------
+ */
+
+ extern Oid CharsetCreateEntry(const char *charsetName,
+ Oid charsetSchema,
+ const char *charsetType);
+
+ #endif /* PG_CHARSET_H */
I'm implementing collation support. Proposal can be found at http://archives.postgresql.org/pgsql-hackers/2008-07/msg00557.php

Progress so far:
- created catalogs pg_collation a pg_charset which are filled with three standard collations
- initdb changes rows called "DEFAULT" in both catalogs during the bki bootstrap phase with current system LC_COLLATE and LC_CTYPE or those set by command line.
- new collations can be defined with command CREATE COLLATION <collation name> FOR <character set specification>  FROM <existing collation name> [STRCOLFN <fn name>]
[ <pad characteristic> ] [ <case sensitive> ] [ LCCOLLATE <lc_collate> ] [ LCCTYPE <lc_ctype> ]
- because of pg_collation and pg_charset are catalogs individual for each database, if you want to create a database with collation other than specified, create it in template1 and then create database
- when connecting to database, it retrieves locales from pg_database and sets them

Design & functionality changes left:
- move retrieveing collation from pg_database to pg_type
- get case sensitivity and pad characteristic working
- wrap locale setting and text comparison into functions that will be referenced from pg_collation as regproc (make the code nice)
- when creating database with different collation than database cluster, the database has to be reindexed. Any idea how to do it? Function ReindexDatabase works only when database is opened.
- minor tweaks & fixes

Ideas? Comments?

Regards

Radek Strnad

No comments: