Sunday, August 31, 2008

[HACKERS] [PATCH] In case module has wrong magic, report exact problem

*** a/src/backend/utils/fmgr/dfmgr.c
--- b/src/backend/utils/fmgr/dfmgr.c
***************
*** 19,28 ****
--- 19,29 ----
#ifndef WIN32_ONLY_COMPILER
#include "dynloader.h"
#else
#include "port/dynloader/win32.h"
#endif
+ #include "lib/stringinfo.h"
#include "miscadmin.h"
#include "utils/dynamic_loader.h"
#include "utils/hsearch.h"


*************** PGFunction
*** 163,172 ****
--- 164,213 ----
lookup_external_function(void *filehandle, char *funcname)
{
return (PGFunction) pg_dlsym(filehandle, funcname);
}

+ /*
+ * Detailed error report when module incompatibility is detected.
+ */
+
+ #define MAGIC_FIELD_TEST(field) do { \
+ if (srv->field != mod->field) { \
+ if (det->len) \
+ appendStringInfo(det, ", "); \
+ appendStringInfo(det, "%s: %d != %d", #field, mod->field, srv->field); \
+ } \
+ } while (0)
+
+ static void
+ module_incompat_error(const Pg_magic_struct *mod, const Pg_magic_struct *srv, const char *libname)
+ {
+ StringInfo det;
+
+ if (mod->version != srv->version)
+ ereport(ERROR,
+ (errmsg("incompatible library \"%s\": version mismatch",
+ libname),
+ errdetail("Server is version %d.%d, library is version %d.%d.",
+ srv->version / 100,
+ srv->version % 100,
+ mod->version / 100,
+ mod->version % 100)));
+
+ det = makeStringInfo();
+
+ MAGIC_FIELD_TEST(funcmaxargs);
+ MAGIC_FIELD_TEST(indexmaxkeys);
+ MAGIC_FIELD_TEST(namedatalen);
+ MAGIC_FIELD_TEST(float4byval);
+ MAGIC_FIELD_TEST(float8byval);
+
+ ereport(ERROR,
+ (errmsg("incompatible library \"%s\": magic block mismatch: %s",
+ libname, det->data)));
+ }
+ #undef MAGIC_FIELD_TEST

/*
* Load the specified dynamic-link library file, unless it already is
* loaded. Return the pg_dl* handle for the file.
*
*************** internal_load_library(const char *libnam
*** 255,281 ****

/* try to unlink library */
pg_dlclose(file_scanner->handle);
free((char *) file_scanner);

! /*
! * Report suitable error. It's probably not worth writing a
! * separate error message for each field; only the most common
! * case of wrong major version gets its own message.
! */
! if (module_magic_data.version != magic_data.version)
! ereport(ERROR,
! (errmsg("incompatible library \"%s\": version mismatch",
! libname),
! errdetail("Server is version %d.%d, library is version %d.%d.",
! magic_data.version / 100,
! magic_data.version % 100,
! module_magic_data.version / 100,
! module_magic_data.version % 100)));
! ereport(ERROR,
! (errmsg("incompatible library \"%s\": magic block mismatch",
! libname)));
}
}
else
{
/* try to unlink library */
--- 296,306 ----

/* try to unlink library */
pg_dlclose(file_scanner->handle);
free((char *) file_scanner);

! module_incompat_error(&module_magic_data, &magic_data, libname);
}
}
else
{
/* try to unlink library */
In case module and server magic blocks do not match
report exact parameters that differ.

It is quite cumbersome problem to track down unless
user already knows the cause.

As we want to encourage module use, such situations
can happen more often.

Re: [HACKERS] WIP patch: Collation support

Radek Strnad escribió:

> - 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.

We have this Todo item:

Set proper permissions on non-system schemas during db creation
Currently all schemas are owned by the super-user because they are
copied from the template1 database. However, since all objects are
inherited from the template database, it is not clear that setting
schemas to the db owner is correct.

When this was discussed years ago, one proposed idea was that on the
first connection the backend should, as a first task, ensure that
certain administrative chores be done. The first of those was changing
the ownership of schemas. It sounds like this reindexing you propose
falls into the same category.

--
Alvaro Herrera http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

[HACKERS] Is this really really as designed or defined in some standard

It seems that we allow several function arguments to have same
name (or is it label :)

hannu=# create or replace function ff(a int, a int) returns int language
plpgsql as $$begin return $1+$2; end;$$;
CREATE FUNCTION
hannu=# select ff(1,1);
ff
----
2
(1 row)

hannu=# select ff(1,2);
ff
----
3
(1 row)

hannu=# create or replace function ffa(a int, a int) returns int
language plpgsql as $$begin return a + a; end;$$;
CREATE FUNCTION
hannu=# select ffa(1,2);
ffa
-----
2
(1 row)

Is this defined by some standard or just an oversight ?

----------------------
Hannu

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

[HACKERS] Prototype: In-place upgrade

Attached patch is prototype of in-place upgrade as was presented on PGCon this year.

Main idea is to learn postgres to handle different version of page and tuple
structures.

1) page - Patch contains new page API and all code access page through this API.
Functions check page version and return correct data to caller. It is mostly
complete now. Only ItemId flags need finish.

2) tuple - HeapTuple structure has been extended with t_ver attribute which
contains page layout version and direct access to HeapTupleHeader is forbidden.
It is possible now only through HeapTuple* functions (see htup.c).
(HeapTupleHeader access still stays in a several functions like heap_form_tuple).

This patch version still does not allow to read old database, but it shows how
it should work. Main disadvantage of this approach is performance penalty.

Please, let me know your opinion about this approach.

Future work:
1) learn WAL to process different tuple structure version
2) tuple conversion to new version and put it into executor (ExecStoreTuple)
3) multiversion MaxItemSize constant

thanks for your comments Zdenek


--
Zdenek Kotala Sun Microsystems
Prague, Czech Republic http://sun.com/postgresql

[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