aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/dbcommands.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/dbcommands.c')
-rw-r--r--src/backend/commands/dbcommands.c94
1 files changed, 83 insertions, 11 deletions
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index f4bfa5cf6db..ce3754f5928 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.210 2008/08/04 18:03:46 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.211 2008/09/23 09:20:35 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,7 @@
#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,7 +70,7 @@ static bool get_db_info(const char *name, LOCKMODE lockmode,
Oid *dbIdP, Oid *ownerIdP,
int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
Oid *dbLastSysOidP, TransactionId *dbFrozenXidP,
- Oid *dbTablespace);
+ Oid *dbTablespace, char **dbCollate, char **dbCtype);
static bool have_createdb_privilege(void);
static void remove_dbtablespaces(Oid db_id);
static bool check_db_file_conflict(Oid db_id);
@@ -87,6 +88,8 @@ createdb(const CreatedbStmt *stmt)
Oid src_dboid;
Oid src_owner;
int src_encoding;
+ char *src_collate;
+ char *src_ctype;
bool src_istemplate;
bool src_allowconn;
Oid src_lastsysoid;
@@ -104,10 +107,14 @@ createdb(const CreatedbStmt *stmt)
DefElem *downer = NULL;
DefElem *dtemplate = NULL;
DefElem *dencoding = NULL;
+ DefElem *dcollate = NULL;
+ DefElem *dctype = NULL;
DefElem *dconnlimit = NULL;
char *dbname = stmt->dbname;
char *dbowner = NULL;
const char *dbtemplate = NULL;
+ char *dbcollate = NULL;
+ char *dbctype = NULL;
int encoding = -1;
int dbconnlimit = -1;
int ctype_encoding;
@@ -152,6 +159,22 @@ createdb(const CreatedbStmt *stmt)
errmsg("conflicting or redundant options")));
dencoding = defel;
}
+ else if (strcmp(defel->defname, "collate") == 0)
+ {
+ if (dcollate)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ dcollate = defel;
+ }
+ else if (strcmp(defel->defname, "ctype") == 0)
+ {
+ if (dctype)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ dctype = defel;
+ }
else if (strcmp(defel->defname, "connectionlimit") == 0)
{
if (dconnlimit)
@@ -205,6 +228,11 @@ createdb(const CreatedbStmt *stmt)
elog(ERROR, "unrecognized node type: %d",
nodeTag(dencoding->arg));
}
+ if (dcollate && dcollate->arg)
+ dbcollate = strVal(dcollate->arg);
+ if (dctype && dctype->arg)
+ dbctype = strVal(dctype->arg);
+
if (dconnlimit && dconnlimit->arg)
dbconnlimit = intVal(dconnlimit->arg);
@@ -243,7 +271,8 @@ createdb(const CreatedbStmt *stmt)
if (!get_db_info(dbtemplate, ShareLock,
&src_dboid, &src_owner, &src_encoding,
&src_istemplate, &src_allowconn, &src_lastsysoid,
- &src_frozenxid, &src_deftablespace))
+ &src_frozenxid, &src_deftablespace,
+ &src_collate, &src_ctype))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("template database \"%s\" does not exist",
@@ -262,9 +291,13 @@ createdb(const CreatedbStmt *stmt)
dbtemplate)));
}
- /* If encoding is defaulted, use source's encoding */
+ /* If encoding or locales are defaulted, use source's setting */
if (encoding < 0)
encoding = src_encoding;
+ if (dbcollate == NULL)
+ dbcollate = src_collate;
+ if (dbctype == NULL)
+ dbctype = src_ctype;
/* Some encodings are client only */
if (!PG_VALID_BE_ENCODING(encoding))
@@ -272,6 +305,16 @@ createdb(const CreatedbStmt *stmt)
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("invalid server encoding %d", encoding)));
+ /* Check that the chosen locales are valid */
+ if (!check_locale(LC_COLLATE, dbcollate))
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("invalid locale name %s", dbcollate)));
+ if (!check_locale(LC_CTYPE, dbctype))
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("invalid locale name %s", dbctype)));
+
/*
* Check whether encoding matches server locale settings. We allow
* mismatch in three cases:
@@ -290,7 +333,7 @@ createdb(const CreatedbStmt *stmt)
*
* Note: if you change this policy, fix initdb to match.
*/
- ctype_encoding = pg_get_encoding_from_locale(NULL);
+ ctype_encoding = pg_get_encoding_from_locale(dbctype);
if (!(ctype_encoding == encoding ||
ctype_encoding == PG_SQL_ASCII ||
@@ -299,12 +342,32 @@ createdb(const CreatedbStmt *stmt)
#endif
(encoding == PG_SQL_ASCII && superuser())))
ereport(ERROR,
- (errmsg("encoding %s does not match server's locale %s",
+ (errmsg("encoding %s does not match locale %s",
pg_encoding_to_char(encoding),
- setlocale(LC_CTYPE, NULL)),
- errdetail("The server's LC_CTYPE setting requires encoding %s.",
+ dbctype),
+ errdetail("The chosen LC_CTYPE setting requires encoding %s.",
pg_encoding_to_char(ctype_encoding))));
+ /*
+ * Check that the new locale is compatible with the source database.
+ *
+ * We know that template0 doesn't contain any indexes that depend on
+ * collation or ctype, so template0 can be used as template for
+ * any locale.
+ */
+ if (strcmp(dbtemplate, "template0") != 0)
+ {
+ if (strcmp(dbcollate, src_collate))
+ ereport(ERROR,
+ (errmsg("new collation is incompatible with the collation of the template database (%s)", src_collate),
+ errhint("Use the same collation as in the template database, or use template0 as template")));
+
+ if (strcmp(dbctype, src_ctype))
+ ereport(ERROR,
+ (errmsg("new ctype is incompatible with the ctype of the template database (%s)", src_ctype),
+ errhint("Use the same ctype as in the template database, or use template0 as template")));
+ }
+
/* Resolve default tablespace for new database */
if (dtablespacename && dtablespacename->arg)
{
@@ -421,6 +484,10 @@ createdb(const CreatedbStmt *stmt)
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_datcollate - 1] =
+ DirectFunctionCall1(namein, CStringGetDatum(dbcollate));
+ new_record[Anum_pg_database_datctype - 1] =
+ DirectFunctionCall1(namein, CStringGetDatum(dbctype));
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);
@@ -629,7 +696,7 @@ dropdb(const char *dbname, bool missing_ok)
pgdbrel = heap_open(DatabaseRelationId, RowExclusiveLock);
if (!get_db_info(dbname, AccessExclusiveLock, &db_id, NULL, NULL,
- &db_istemplate, NULL, NULL, NULL, NULL))
+ &db_istemplate, NULL, NULL, NULL, NULL, NULL, NULL))
{
if (!missing_ok)
{
@@ -781,7 +848,7 @@ RenameDatabase(const char *oldname, const char *newname)
rel = heap_open(DatabaseRelationId, RowExclusiveLock);
if (!get_db_info(oldname, AccessExclusiveLock, &db_id, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL))
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database \"%s\" does not exist", oldname)));
@@ -1168,7 +1235,7 @@ get_db_info(const char *name, LOCKMODE lockmode,
Oid *dbIdP, Oid *ownerIdP,
int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
Oid *dbLastSysOidP, TransactionId *dbFrozenXidP,
- Oid *dbTablespace)
+ Oid *dbTablespace, char **dbCollate, char **dbCtype)
{
bool result = false;
Relation relation;
@@ -1259,6 +1326,11 @@ get_db_info(const char *name, LOCKMODE lockmode,
/* default tablespace for this database */
if (dbTablespace)
*dbTablespace = dbform->dattablespace;
+ /* default locale settings for this database */
+ if (dbCollate)
+ *dbCollate = pstrdup(NameStr(dbform->datcollate));
+ if (dbCtype)
+ *dbCtype = pstrdup(NameStr(dbform->datctype));
ReleaseSysCache(tuple);
result = true;
break;