Patch for database locale settings

Started by Alexey Slynkoalmost 21 years ago8 messages
#1Alexey Slynko
slynko@tronet.ru
1 attachment(s)

Hi,

this patch allow to use database locale settings. It remove cluster locale
settings, and append LCCTYPE and
LCCOLLATE items to CREATE DATABASE syntax.

Any considerations ?

best regards,
Alexey Slynko

Attachments:

database_locale.patchtext/plain; charset=US-ASCII; name=database_locale.patchDownload
Index: src/backend/access/transam/xlog.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/access/transam/xlog.c,v
retrieving revision 1.182
diff -c -r1.182 xlog.c
*** src/backend/access/transam/xlog.c	24 Mar 2005 04:36:17 -0000	1.182
--- src/backend/access/transam/xlog.c	25 Mar 2005 09:42:17 -0000
***************
*** 3128,3145 ****
  	ControlFile->enableIntTimes = FALSE;
  #endif
  
- 	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_CRC64(ControlFile->crc);
  	COMP_CRC64(ControlFile->crc,
--- 3128,3133 ----
***************
*** 3309,3341 ****
  			 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 (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 (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
--- 3297,3302 ----
Index: src/backend/commands/dbcommands.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/dbcommands.c,v
retrieving revision 1.155
diff -c -r1.155 dbcommands.c
*** src/backend/commands/dbcommands.c	23 Mar 2005 00:03:28 -0000	1.155
--- src/backend/commands/dbcommands.c	25 Mar 2005 09:42:18 -0000
***************
*** 25,30 ****
--- 25,34 ----
  #include <unistd.h>
  #include <sys/stat.h>
  
+ #ifdef HAVE_LANGINFO_H
+ #include <langinfo.h>
+ #endif
+ 
  #include "access/genam.h"
  #include "access/heapam.h"
  #include "catalog/catname.h"
***************
*** 49,54 ****
--- 53,59 ----
  #include "utils/fmgroids.h"
  #include "utils/guc.h"
  #include "utils/lsyscache.h"
+ #include "utils/pg_locale.h"
  #include "utils/syscache.h"
  
  
***************
*** 57,65 ****
  			int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
  			Oid *dbLastSysOidP,
  			TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
! 			Oid *dbTablespace);
  static bool have_createdb_privilege(void);
  static void remove_dbtablespaces(Oid db_id);
  
  
  /*
--- 62,72 ----
  			int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
  			Oid *dbLastSysOidP,
  			TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
! 			Oid *dbTablespace, char **dbCollate, char **dbCtype);
  static bool have_createdb_privilege(void);
  static void remove_dbtablespaces(Oid db_id);
+ static char * get_locale_encoding(const char *ctype);
+ static int check_locale_encoding(int encid, const char *ctype);
  
  
  /*
***************
*** 70,78 ****
  {
  	HeapScanDesc scan;
  	Relation	rel;
! 	Oid			src_dboid;
  	AclId		src_owner;
! 	int			src_encoding;
  	bool		src_istemplate;
  	bool		src_allowconn;
  	Oid			src_lastsysoid;
--- 77,87 ----
  {
  	HeapScanDesc scan;
  	Relation	rel;
! 	Oid		src_dboid;
  	AclId		src_owner;
! 	int		src_encoding;
! 	char		*src_collate;
! 	char		*src_ctype;
  	bool		src_istemplate;
  	bool		src_allowconn;
  	Oid			src_lastsysoid;
***************
*** 85,101 ****
  	TupleDesc	pg_database_dsc;
  	Datum		new_record[Natts_pg_database];
  	char		new_record_nulls[Natts_pg_database];
! 	Oid			dboid;
  	AclId		datdba;
  	ListCell   *option;
  	DefElem    *dtablespacename = NULL;
  	DefElem    *downer = NULL;
  	DefElem    *dtemplate = NULL;
  	DefElem    *dencoding = NULL;
  	char	   *dbname = stmt->dbname;
  	char	   *dbowner = NULL;
  	char	   *dbtemplate = NULL;
! 	int			encoding = -1;
  
  #ifndef WIN32
  	char		buf[2 * MAXPGPATH + 100];
--- 94,114 ----
  	TupleDesc	pg_database_dsc;
  	Datum		new_record[Natts_pg_database];
  	char		new_record_nulls[Natts_pg_database];
! 	Oid		dboid;
  	AclId		datdba;
  	ListCell   *option;
  	DefElem    *dtablespacename = NULL;
  	DefElem    *downer = NULL;
  	DefElem    *dtemplate = NULL;
  	DefElem    *dencoding = NULL;
+ 	DefElem    *dlc_collate = NULL;
+ 	DefElem    *dlc_ctype = NULL;
  	char	   *dbname = stmt->dbname;
  	char	   *dbowner = NULL;
  	char	   *dbtemplate = NULL;
! 	char	   *lc_collate = NULL;
! 	char	   *lc_ctype = NULL;
! 	int	   encoding = -1;
  
  #ifndef WIN32
  	char		buf[2 * MAXPGPATH + 100];
***************
*** 141,146 ****
--- 154,175 ----
  						 errmsg("conflicting or redundant options")));
  			dencoding = defel;
  		}
+ 		else if (strcmp(defel->defname, "lccollate") == 0)
+ 		{
+ 			if (dlc_collate)
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_SYNTAX_ERROR),
+ 						errmsg("conflicting or redundant options")));
+ 			dlc_collate = defel;
+ 		}
+ 		else if (strcmp(defel->defname, "lcctype") == 0)
+ 		{
+ 			if (dlc_ctype)
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_SYNTAX_ERROR),
+ 						errmsg("conflicting or redundant options")));
+ 			dlc_ctype = defel;
+ 		}
  		else if (strcmp(defel->defname, "location") == 0)
  		{
  			ereport(WARNING,
***************
*** 186,191 ****
--- 215,236 ----
  			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 (dlc_ctype && dlc_ctype->arg) {
+ 		lc_ctype = strVal(dlc_ctype->arg);
+ 		if ((locale_collate_assign(lc_ctype, false, (GucSource)NULL)) == NULL)
+ 			ereport(ERROR,
+ 				(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 				errmsg("%s is not a valid LC_CTYPE name",
+ 						lc_ctype)));
+ 	}
  
  	/* obtain sysid of proposed owner */
  	if (dbowner)
***************
*** 220,226 ****
  	 * after we grab the exclusive lock.
  	 */
  	if (get_db_info(dbname, NULL, NULL, NULL,
! 					NULL, NULL, NULL, NULL, NULL, NULL))
  		ereport(ERROR,
  				(errcode(ERRCODE_DUPLICATE_DATABASE),
  				 errmsg("database \"%s\" already exists", dbname)));
--- 265,271 ----
  	 * after we grab the exclusive lock.
  	 */
  	if (get_db_info(dbname, NULL, NULL, NULL,
! 					NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
  		ereport(ERROR,
  				(errcode(ERRCODE_DUPLICATE_DATABASE),
  				 errmsg("database \"%s\" already exists", dbname)));
***************
*** 233,239 ****
  
  	if (!get_db_info(dbtemplate, &src_dboid, &src_owner, &src_encoding,
  					 &src_istemplate, &src_allowconn, &src_lastsysoid,
! 					 &src_vacuumxid, &src_frozenxid, &src_deftablespace))
  		ereport(ERROR,
  				(errcode(ERRCODE_UNDEFINED_DATABASE),
  		 errmsg("template database \"%s\" does not exist", dbtemplate)));
--- 278,285 ----
  
  	if (!get_db_info(dbtemplate, &src_dboid, &src_owner, &src_encoding,
  					 &src_istemplate, &src_allowconn, &src_lastsysoid,
! 					 &src_vacuumxid, &src_frozenxid, &src_deftablespace,
! 					 &src_collate, &src_ctype))
  		ereport(ERROR,
  				(errcode(ERRCODE_UNDEFINED_DATABASE),
  		 errmsg("template database \"%s\" does not exist", dbtemplate)));
***************
*** 263,268 ****
--- 309,315 ----
  		errmsg("source database \"%s\" is being accessed by other users",
  			   dbtemplate)));
  
+ 
  	/* If encoding is defaulted, use source's encoding */
  	if (encoding < 0)
  		encoding = src_encoding;
***************
*** 273,278 ****
--- 320,340 ----
  				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
  				 errmsg("invalid server encoding %d", encoding)));
  
+ 	/* Set database lc_collate and lc_ctype */
+ 	if (!lc_collate)
+ 		lc_collate = src_collate;
+ 	if (!lc_ctype) 
+ 		lc_ctype = src_ctype;
+ 
+ #if defined(HAVE_LANGINFO_H) && defined(CODESET)
+ 	if (encoding > 0 && check_locale_encoding(encoding, lc_ctype) == -1)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ 				 errmsg("encoding %s is not suitable for locale %s", 
+ 							pg_encoding_to_char(encoding), 
+ 							lc_ctype)));
+ #endif
+ 
  	/* Resolve default tablespace for new database */
  	if (dtablespacename && dtablespacename->arg)
  	{
***************
*** 463,469 ****
  
  	/* Check to see if someone else created same DB name meanwhile. */
  	if (get_db_info(dbname, NULL, NULL, NULL,
! 					NULL, NULL, NULL, NULL, NULL, NULL))
  	{
  		/* Don't hold lock while doing recursive remove */
  		heap_close(pg_database_rel, ExclusiveLock);
--- 525,531 ----
  
  	/* Check to see if someone else created same DB name meanwhile. */
  	if (get_db_info(dbname, NULL, NULL, NULL,
! 					NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
  	{
  		/* Don't hold lock while doing recursive remove */
  		heap_close(pg_database_rel, ExclusiveLock);
***************
*** 486,491 ****
--- 548,557 ----
  		DirectFunctionCall1(namein, CStringGetDatum(dbname));
  	new_record[Anum_pg_database_datdba - 1] = Int32GetDatum(datdba);
  	new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding);
+ 	new_record[Anum_pg_database_datcollate - 1] = 
+ 		DirectFunctionCall1(namein, CStringGetDatum(lc_collate));
+ 	new_record[Anum_pg_database_datctype - 1] = 
+ 		DirectFunctionCall1(namein, CStringGetDatum(lc_ctype));
  	new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(false);
  	new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(true);
  	new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(src_lastsysoid);
***************
*** 560,566 ****
  	pgdbrel = heap_openr(DatabaseRelationName, ExclusiveLock);
  
  	if (!get_db_info(dbname, &db_id, &db_owner, NULL,
! 					 &db_istemplate, NULL, NULL, NULL, NULL, NULL))
  		ereport(ERROR,
  				(errcode(ERRCODE_UNDEFINED_DATABASE),
  				 errmsg("database \"%s\" does not exist", dbname)));
--- 626,632 ----
  	pgdbrel = heap_openr(DatabaseRelationName, ExclusiveLock);
  
  	if (!get_db_info(dbname, &db_id, &db_owner, NULL,
! 					 &db_istemplate, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
  		ereport(ERROR,
  				(errcode(ERRCODE_UNDEFINED_DATABASE),
  				 errmsg("database \"%s\" does not exist", dbname)));
***************
*** 947,953 ****
  			int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
  			Oid *dbLastSysOidP,
  			TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
! 			Oid *dbTablespace)
  {
  	Relation	relation;
  	ScanKeyData scanKey;
--- 1013,1019 ----
  			int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
  			Oid *dbLastSysOidP,
  			TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
! 			Oid *dbTablespace, char **dbCollate, char **dbCtype)
  {
  	Relation	relation;
  	ScanKeyData scanKey;
***************
*** 1002,1007 ****
--- 1068,1078 ----
  		/* default tablespace for this database */
  		if (dbTablespace)
  			*dbTablespace = dbform->dattablespace;
+ 		/* default locale settings for this database */
+ 		if (dbCollate)
+ 			*dbCollate = NameStr(dbform->datcollate);
+ 		if (dbCtype)
+ 			*dbCtype = NameStr(dbform->datctype);
  	}
  
  	systable_endscan(scan);
***************
*** 1379,1381 ****
--- 1450,1494 ----
  	else
  		strcat(buf, "UNKNOWN");
  }
+ 
+ #if defined(HAVE_LANGINFO_H) && defined(CODESET)
+    
+ static char *
+ get_locale_encoding(const char *ctype)
+ {
+ 	char       *save;
+ 	char       *sys;
+                         
+         save = setlocale(LC_CTYPE, NULL);
+         if (!save)
+                 return NULL;
+         save = pstrdup(save);
+                                 
+         setlocale(LC_CTYPE, ctype);
+         sys = nl_langinfo(CODESET);
+         sys = pstrdup(sys);
+                         
+         setlocale(LC_CTYPE, save);
+         pfree(save);
+             
+         return sys;
+ }
+         
+ static int
+ check_locale_encoding(int encid, const char *ctype)
+ {
+         char       *sys;
+         
+         sys = get_locale_encoding(ctype);
+         if (encid == pg_char_to_encoding(sys))
+         {
+                 pfree(sys);
+                 return 0;
+         }
+         
+         pfree(sys);
+         return -1;
+ }
+ 
+ #endif
+ 
Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.484
diff -c -r2.484 gram.y
*** src/backend/parser/gram.y	14 Mar 2005 00:19:36 -0000	2.484
--- src/backend/parser/gram.y	25 Mar 2005 09:42:18 -0000
***************
*** 368,376 ****
  
  	KEY
  
! 	LANCOMPILER LANGUAGE LARGE_P LAST_P LEADING LEFT LEVEL LIKE LIMIT
! 	LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
! 	LOCK_P
  
  	MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
  
--- 368,377 ----
  
  	KEY
  
! 	LANCOMPILER LANGUAGE LARGE_P LAST_P 
! 	LCCOLLATE LCCTYPE LEADING LEFT LEVEL 
! 	LIKE LIMIT LISTEN LOAD LOCAL 
! 	LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P
  
  	MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
  
***************
*** 4220,4225 ****
--- 4221,4242 ----
  				{
  					$$ = makeDefElem("encoding", NULL);
  				}
+ 			| LCCOLLATE opt_equal name
+ 				{
+ 					$$ = makeDefElem("lccollate", (Node *)makeString($3));
+ 				}
+ 			| LCCOLLATE opt_equal DEFAULT
+ 				{
+ 					$$ = makeDefElem("lccollate", NULL);
+ 				}
+ 			| LCCTYPE opt_equal name
+ 				{
+ 					$$ = makeDefElem("lcctype", (Node *)makeString($3));
+ 				}
+ 			| LCCTYPE opt_equal DEFAULT
+ 				{
+ 					$$ = makeDefElem("lcctype", NULL);
+ 				}
  			| OWNER opt_equal name
  				{
  					$$ = makeDefElem("owner", (Node *)makeString($3));
***************
*** 7763,7768 ****
--- 7780,7787 ----
  			| LANGUAGE
  			| LARGE_P
  			| LAST_P
+ 			| LCCOLLATE
+ 			| LCCTYPE
  			| LEVEL
  			| LISTEN
  			| LOAD
Index: src/backend/parser/keywords.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/keywords.c,v
retrieving revision 1.154
diff -c -r1.154 keywords.c
*** src/backend/parser/keywords.c	31 Dec 2004 22:00:27 -0000	1.154
--- src/backend/parser/keywords.c	25 Mar 2005 09:42:18 -0000
***************
*** 181,186 ****
--- 181,188 ----
  	{"language", LANGUAGE},
  	{"large", LARGE_P},
  	{"last", LAST_P},
+ 	{"lccollate", LCCOLLATE},
+ 	{"lcctype", LCCTYPE},
  	{"leading", LEADING},
  	{"left", LEFT},
  	{"level", LEVEL},
Index: src/backend/utils/adt/pg_locale.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v
retrieving revision 1.31
diff -c -r1.31 pg_locale.c
*** src/backend/utils/adt/pg_locale.c	16 Mar 2005 00:02:49 -0000	1.31
--- src/backend/utils/adt/pg_locale.c	25 Mar 2005 09:42:18 -0000
***************
*** 10,19 ****
   */
  
  /*----------
!  * Here is how the locale stuff is handled: LC_COLLATE and LC_CTYPE
!  * are fixed by initdb, stored in pg_control, and cannot be changed.
!  * Thus, the effects of strcoll(), strxfrm(), isupper(), toupper(),
!  * etc. are always in the same fixed locale.
   *
   * LC_MESSAGES is settable at run time and will take effect
   * immediately.
--- 10,17 ----
   */
  
  /*----------
!  * Here is how the locale stuff is handled: 
!  * LC_COLLATE and LC_CTYPE are defined by createdb and stored in pg_database.
   *
   * LC_MESSAGES is settable at run time and will take effect
   * immediately.
***************
*** 97,102 ****
--- 95,111 ----
  	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: src/backend/utils/init/postinit.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/init/postinit.c,v
retrieving revision 1.144
diff -c -r1.144 postinit.c
*** src/backend/utils/init/postinit.c	19 Mar 2005 23:27:06 -0000	1.144
--- src/backend/utils/init/postinit.c	25 Mar 2005 09:42:18 -0000
***************
*** 36,41 ****
--- 36,42 ----
  #include "storage/proc.h"
  #include "storage/sinval.h"
  #include "storage/smgr.h"
+ #include "utils/builtins.h"
  #include "utils/flatfiles.h"
  #include "utils/fmgroids.h"
  #include "utils/guc.h"
***************
*** 114,120 ****
   * invalid database.  If we quit now, we should have managed to avoid
   * creating any serious problems.
   *
!  * This is also a handy place to fetch the database encoding info out
   * of pg_database.
   *
   * To avoid having to read pg_database more times than necessary
--- 115,121 ----
   * invalid database.  If we quit now, we should have managed to avoid
   * creating any serious problems.
   *
!  * This is also a handy place to fetch the database encoding and locale info out
   * of pg_database.
   *
   * To avoid having to read pg_database more times than necessary
***************
*** 129,134 ****
--- 130,137 ----
  	ScanKeyData key;
  	HeapTuple	tup;
  	Form_pg_database dbform;
+ 	char		*lc_ctype;
+ 	char		*lc_collate;
  
  	/*
  	 * Because we grab RowShareLock here, we can be sure that dropdb()
***************
*** 175,181 ****
  				name)));
  
  	/*
! 	 * OK, we're golden.  Next to-do item is to save the encoding
  	 * info out of the pg_database tuple.
  	 */
  	SetDatabaseEncoding(dbform->encoding);
--- 178,184 ----
  				name)));
  
  	/*
! 	 * OK, we're golden.  Next to-do item is to save the encoding 
  	 * info out of the pg_database tuple.
  	 */
  	SetDatabaseEncoding(dbform->encoding);
***************
*** 186,191 ****
--- 189,221 ----
  	SetConfigOption("client_encoding", GetDatabaseEncodingName(),
  					PGC_BACKEND, PGC_S_DEFAULT);
  
+ 	/* 
+ 	 * Set up database locale 
+ 	 */
+ 	lc_collate = NameStr(dbform->datcollate);
+ 	lc_ctype = NameStr(dbform->datctype);
+ 
+ 	if (setlocale(LC_COLLATE, lc_collate) == NULL)
+ 		ereport(FATAL,
+ 			(errmsg("database locale is incompatible with operating system"),
+ 			errdetail("The database was initialized with LC_COLLATE \"%s\","
+ 					" which is not recognized by setlocale().",
+ 					lc_collate),
+ 			errhint("It looks like you need to recreate database or install locale support.")));
+ 	if (setlocale(LC_CTYPE, lc_ctype) == NULL)
+ 		ereport(FATAL,
+ 			(errmsg("database locale are incompatible with operating system"),
+ 			errdetail("The database was initialized with LC_CTYPE \"%s\","
+ 					" which is not recognized by setlocale().",
+ 					lc_ctype),
+ 			errhint("It looks like you need to recreate database or install locale support.")));
+ 
+ 	/* Record it as a GUC internal option, too */
+ 	SetConfigOption("lc_collate", lc_collate,
+ 					PGC_INTERNAL, PGC_S_DATABASE);
+ 	SetConfigOption("lc_ctype", lc_ctype,
+ 					PGC_INTERNAL, PGC_S_DATABASE);
+ 
  	/*
  	 * Lastly, set up any database-specific configuration variables.
  	 */
***************
*** 466,471 ****
--- 496,502 ----
  	/* set default namespace search path */
  	InitializeSearchPath();
  
+ 		
  	/* initialize client encoding */
  	InitializeClientEncoding();
  
Index: src/bin/initdb/initdb.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/initdb/initdb.c,v
retrieving revision 1.79
diff -c -r1.79 initdb.c
*** src/bin/initdb/initdb.c	14 Mar 2005 18:31:23 -0000	1.79
--- src/bin/initdb/initdb.c	25 Mar 2005 09:42:18 -0000
***************
*** 1272,1277 ****
--- 1272,1281 ----
  
  	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.
  	 *
***************
*** 2423,2429 ****
  		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"
--- 2427,2433 ----
  		printf(_("The database cluster 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: src/bin/pg_controldata/pg_controldata.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/pg_controldata/pg_controldata.c,v
retrieving revision 1.21
diff -c -r1.21 pg_controldata.c
*** src/bin/pg_controldata/pg_controldata.c	22 Feb 2005 04:39:00 -0000	1.21
--- src/bin/pg_controldata/pg_controldata.c	25 Mar 2005 09:42:18 -0000
***************
*** 173,181 ****
  	printf(_("Maximum number of function arguments: %u\n"), ControlFile.funcMaxArgs);
  	printf(_("Date/time type storage:               %s\n"),
  		   (ControlFile.enableIntTimes ? _("64-bit integers") : _("floating-point numbers")));
- 	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;
  }
--- 173,177 ----
Index: src/bin/pg_resetxlog/pg_resetxlog.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v
retrieving revision 1.29
diff -c -r1.29 pg_resetxlog.c
*** src/bin/pg_resetxlog/pg_resetxlog.c	22 Feb 2005 04:40:20 -0000	1.29
--- src/bin/pg_resetxlog/pg_resetxlog.c	25 Mar 2005 09:42:18 -0000
***************
*** 423,444 ****
  #else
  	ControlFile.enableIntTimes = FALSE;
  #endif
- 	ControlFile.localeBuflen = LOCALE_NAME_BUFLEN;
- 
- 	localeptr = setlocale(LC_COLLATE, "");
- 	if (!localeptr)
- 	{
- 		fprintf(stderr, _("%s: invalid LC_COLLATE setting\n"), progname);
- 		exit(1);
- 	}
- 	StrNCpy(ControlFile.lc_collate, localeptr, LOCALE_NAME_BUFLEN);
- 	localeptr = setlocale(LC_CTYPE, "");
- 	if (!localeptr)
- 	{
- 		fprintf(stderr, _("%s: invalid LC_CTYPE setting\n"), progname);
- 		exit(1);
- 	}
- 	StrNCpy(ControlFile.lc_ctype, localeptr, LOCALE_NAME_BUFLEN);
  
  	/*
  	 * XXX eventually, should try to grovel through old XLOG to develop
--- 423,428 ----
***************
*** 484,492 ****
  	printf(_("Maximum number of function arguments: %u\n"), ControlFile.funcMaxArgs);
  	printf(_("Date/time type storage:               %s\n"),
  		   (ControlFile.enableIntTimes ? _("64-bit integers") : _("floating-point numbers")));
- 	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);
  }
  
  
--- 468,473 ----
Index: src/bin/psql/describe.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/describe.c,v
retrieving revision 1.113
diff -c -r1.113 describe.c
*** src/bin/psql/describe.c	16 Mar 2005 23:52:18 -0000	1.113
--- src/bin/psql/describe.c	25 Mar 2005 09:42:18 -0000
***************
*** 361,366 ****
--- 361,372 ----
  	appendPQExpBuffer(&buf,
  		",\n       pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\"",
  					  _("Encoding"));
+ 	appendPQExpBuffer(&buf,
+ 		",\n       d.datcollate as \"%s\"",
+ 					 _("LC_COLLATE"));
+ 	appendPQExpBuffer(&buf,
+ 		",\n       d.datctype as \"%s\"",
+ 					 _("LC_CTYPE"));
  	if (verbose)
  		appendPQExpBuffer(&buf,
  						  ",\n       pg_catalog.obj_description(d.oid, 'pg_database') as \"%s\"",
Index: src/bin/scripts/createdb.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/scripts/createdb.c,v
retrieving revision 1.14
diff -c -r1.14 createdb.c
*** src/bin/scripts/createdb.c	31 Dec 2004 22:03:17 -0000	1.14
--- src/bin/scripts/createdb.c	25 Mar 2005 09:42:18 -0000
***************
*** 34,39 ****
--- 34,41 ----
  		{"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}
  	};
  
***************
*** 53,58 ****
--- 55,62 ----
  	char	   *tablespace = NULL;
  	char	   *template = NULL;
  	char	   *encoding = NULL;
+ 	char	   *lc_collate = NULL;
+ 	char	   *lc_ctype = NULL;
  
  	PQExpBufferData sql;
  
***************
*** 98,103 ****
--- 102,113 ----
  			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);
***************
*** 155,161 ****
--- 165,176 ----
  		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("template1", host, port, username, password, progname);
  
***************
*** 218,236 ****
  	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(_("  -q, --quiet                  don't write any messages\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               prompt for password\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"));
  }
--- 233,252 ----
  	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	initialize database with given locale\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(_("  -q, --quiet                  	don't write any messages\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               	prompt for password\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: src/include/catalog/pg_attribute.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_attribute.h,v
retrieving revision 1.113
diff -c -r1.113 pg_attribute.h
*** src/include/catalog/pg_attribute.h	31 Dec 2004 22:03:24 -0000	1.113
--- src/include/catalog/pg_attribute.h	25 Mar 2005 09:42:18 -0000
***************
*** 285,298 ****
  DATA(insert ( 1262 datname			19 -1 NAMEDATALEN	1 0 -1 -1 f p i t f f t 0));
  DATA(insert ( 1262 datdba			23 -1 4   2 0 -1 -1 t p i t f f t 0));
  DATA(insert ( 1262 encoding			23 -1 4   3 0 -1 -1 t p i t f f t 0));
! DATA(insert ( 1262 datistemplate	16 -1 1   4 0 -1 -1 t p c t f f t 0));
! DATA(insert ( 1262 datallowconn		16 -1 1   5 0 -1 -1 t p c t f f t 0));
! DATA(insert ( 1262 datlastsysoid	26 -1 4   6 0 -1 -1 t p i t f f t 0));
! DATA(insert ( 1262 datvacuumxid		28 -1 4   7 0 -1 -1 t p i t f f t 0));
! DATA(insert ( 1262 datfrozenxid		28 -1 4   8 0 -1 -1 t p i t f f t 0));
! DATA(insert ( 1262 dattablespace	26 -1 4   9 0 -1 -1 t p i t f f t 0));
! DATA(insert ( 1262 datconfig	  1009 -1 -1 10 1 -1 -1 f x i f f f t 0));
! DATA(insert ( 1262 datacl		  1034 -1 -1 11 1 -1 -1 f x i f f f t 0));
  DATA(insert ( 1262 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0));
  DATA(insert ( 1262 oid				26 0  4  -2 0 -1 -1 t p i t f f t 0));
  DATA(insert ( 1262 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0));
--- 285,300 ----
  DATA(insert ( 1262 datname			19 -1 NAMEDATALEN	1 0 -1 -1 f p i t f f t 0));
  DATA(insert ( 1262 datdba			23 -1 4   2 0 -1 -1 t p i t f f t 0));
  DATA(insert ( 1262 encoding			23 -1 4   3 0 -1 -1 t p i t f f t 0));
! DATA(insert ( 1262 datcollate		19 -1 NAMEDATALEN 4 0 -1 -1 f p i t f f t 0));
! DATA(insert ( 1262 datctype		19 -1 NAMEDATALEN 5 0 -1 -1 f p i t f f t 0));
! DATA(insert ( 1262 datistemplate	16 -1 1   6 0 -1 -1 t p c t f f t 0));
! DATA(insert ( 1262 datallowconn		16 -1 1   7 0 -1 -1 t p c t f f t 0));
! DATA(insert ( 1262 datlastsysoid	26 -1 4   8 0 -1 -1 t p i t f f t 0));
! DATA(insert ( 1262 datvacuumxid		28 -1 4   9 0 -1 -1 t p i t f f t 0));
! DATA(insert ( 1262 datfrozenxid		28 -1 4  10 0 -1 -1 t p i t f f t 0));
! DATA(insert ( 1262 dattablespace	26 -1 4  11 0 -1 -1 t p i t f f t 0));
! DATA(insert ( 1262 datconfig		1009 -1 -1 12 1 -1 -1 f x i f f f t 0));
! DATA(insert ( 1262 datacl		1034 -1 -1 13 1 -1 -1 f x i f f f t 0));
  DATA(insert ( 1262 ctid				27 0  6  -1 0 -1 -1 f p s t f f t 0));
  DATA(insert ( 1262 oid				26 0  4  -2 0 -1 -1 t p i t f f t 0));
  DATA(insert ( 1262 xmin				28 0  4  -3 0 -1 -1 t p i t f f t 0));
Index: src/include/catalog/pg_class.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_class.h,v
retrieving revision 1.85
diff -c -r1.85 pg_class.h
*** src/include/catalog/pg_class.h	31 Dec 2004 22:03:24 -0000	1.85
--- src/include/catalog/pg_class.h	25 Mar 2005 09:42:18 -0000
***************
*** 148,154 ****
  DESCR("");
  DATA(insert OID = 1261 (  pg_group		PGNSP 87 PGUID 0 1261 1664 0 0 0 0 f t r 3	0 0 0 0 0 f f f f _null_ ));
  DESCR("");
! DATA(insert OID = 1262 (  pg_database	PGNSP 88 PGUID 0 1262 1664 0 0 0 0 f t r 11 0 0 0 0 0 t f f f _null_ ));
  DESCR("");
  DATA(insert OID = 1213 (  pg_tablespace PGNSP 90 PGUID 0 1213 1664 0 0 0 0 f t r 4	0 0 0 0 0 t f f f _null_ ));
  DESCR("");
--- 148,154 ----
  DESCR("");
  DATA(insert OID = 1261 (  pg_group		PGNSP 87 PGUID 0 1261 1664 0 0 0 0 f t r 3	0 0 0 0 0 f f f f _null_ ));
  DESCR("");
! DATA(insert OID = 1262 (  pg_database	PGNSP 88 PGUID 0 1262 1664 0 0 0 0 f t r 13 0 0 0 0 0 t f f f _null_ ));
  DESCR("");
  DATA(insert OID = 1213 (  pg_tablespace PGNSP 90 PGUID 0 1213 1664 0 0 0 0 f t r 4	0 0 0 0 0 t f f f _null_ ));
  DESCR("");
Index: src/include/catalog/pg_control.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_control.h,v
retrieving revision 1.19
diff -c -r1.19 pg_control.h
*** src/include/catalog/pg_control.h	31 Dec 2004 22:03:24 -0000	1.19
--- src/include/catalog/pg_control.h	25 Mar 2005 09:42:18 -0000
***************
*** 121,130 ****
  	/* flag indicating internal format of timestamp, interval, time */
  	uint32		enableIntTimes; /* int64 storage enabled? */
  
- 	/* active locales */
- 	uint32		localeBuflen;
- 	char		lc_collate[LOCALE_NAME_BUFLEN];
- 	char		lc_ctype[LOCALE_NAME_BUFLEN];
  } ControlFileData;
  
  #endif   /* PG_CONTROL_H */
--- 121,126 ----
Index: src/include/catalog/pg_database.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_database.h,v
retrieving revision 1.34
diff -c -r1.34 pg_database.h
*** src/include/catalog/pg_database.h	31 Dec 2004 22:03:24 -0000	1.34
--- src/include/catalog/pg_database.h	25 Mar 2005 09:42:18 -0000
***************
*** 36,41 ****
--- 36,43 ----
  	NameData	datname;		/* database name */
  	int4		datdba;			/* sysid of owner */
  	int4		encoding;		/* character encoding */
+ 	NameData	datcollate;		/* locale LC_COLLATE */
+ 	NameData	datctype;		/* locale LC_CTYPE */
  	bool		datistemplate;	/* allowed as CREATE DATABASE template? */
  	bool		datallowconn;	/* new connections allowed? */
  	Oid			datlastsysoid;	/* highest OID to consider a system OID */
***************
*** 57,76 ****
   *		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_datlastsysoid	6
! #define Anum_pg_database_datvacuumxid	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 0 0 0 1663 _null_ _null_ ));
  DESCR("Default template database");
  #define TemplateDbOid			1
  
--- 59,80 ----
   *		compiler constants for pg_database
   * ----------------
   */
! #define Natts_pg_database				13
  #define Anum_pg_database_datname		1
  #define Anum_pg_database_datdba			2
  #define Anum_pg_database_encoding		3
! #define Anum_pg_database_datcollate	4
! #define Anum_pg_database_datctype	5	
! #define Anum_pg_database_datistemplate	6
! #define Anum_pg_database_datallowconn	7
! #define Anum_pg_database_datlastsysoid	8
! #define Anum_pg_database_datvacuumxid	9
! #define Anum_pg_database_datfrozenxid	10	
! #define Anum_pg_database_dattablespace	11	
! #define Anum_pg_database_datconfig		12
! #define Anum_pg_database_datacl			13
  
! DATA(insert OID = 1 (  template1 PGUID ENCODING LC_CTYPE LC_COLLATE t t 0 0 0 1663 _null_ _null_ ));
  DESCR("Default template database");
  #define TemplateDbOid			1
  
Index: src/include/utils/pg_locale.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/pg_locale.h,v
retrieving revision 1.20
diff -c -r1.20 pg_locale.h
*** src/include/utils/pg_locale.h	16 Mar 2005 00:02:49 -0000	1.20
--- src/include/utils/pg_locale.h	25 Mar 2005 09:42:18 -0000
***************
*** 22,27 ****
--- 22,31 ----
  extern char *locale_numeric;
  extern char *locale_time;
  
+ 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,
#2Alvaro Herrera
alvherre@dcc.uchile.cl
In reply to: Alexey Slynko (#1)
Re: [PATCHES] Patch for database locale settings

On Mon, Mar 28, 2005 at 12:16:42PM +0400, Alexey Slynko wrote:

this patch allow to use database locale settings. It remove cluster locale
settings, and append LCCTYPE and
LCCOLLATE items to CREATE DATABASE syntax.

Any considerations ?

The problem with this is what happens to indexes on shared relations.
If you change the collation, they are no longer valid. And you can't
just reindex them, because then they would no longer be valid for other
databases.

Maybe it would work if we forced indexes on shared relations to be
scanned using a fixed collation.

Not sure about the ctype part ...

--
Alvaro Herrera (<alvherre[@]dcc.uchile.cl>)
"Los rom�nticos son seres que mueren de deseos de vida"

#3Tom Lane
tgl@sss.pgh.pa.us
In reply to: Alvaro Herrera (#2)
Re: [PATCHES] Patch for database locale settings

Alvaro Herrera <alvherre@dcc.uchile.cl> writes:

Maybe it would work if we forced indexes on shared relations to be
scanned using a fixed collation.

The shared relations only have indexes on name, oid, and integer:
select distinct atttypid::regtype
from pg_class c join pg_attribute a on c.oid = a.attrelid
where relisshared and relkind = 'i';
and name has non-locale-sensitive ordering rules anyway. So that's
not the big problem; we could probably get away with decreeing that
name will always be that way and that shared relations can't have
locale-dependent indexes.

The big problem (and the reason why this idea has been shot down in
the past) is that CREATE DATABASE can't change the locale from what it
is in the template database unless it's prepared to reindex any locale-
sensitive indexes in the non-shared part of the template database.
Which would be a difficult undertaking seeing that we can't even connect
to the copied database until after commit.

We could maybe say that we will never have any locale-dependent indexes
at all on any system catalog, but what of user-defined tables in
template databases? It would simply not work to do something as simple
as creating a table with an indexed text column in template1.

On the other hand you could argue that people already run the same kind
of risk when changing database encoding at CREATE, which is a feature
that's been there a long time and hasn't garnered many complaints.
Not so much that their indexes will break as that their data will.
So perhaps we should be willing to document "don't do that". Certainly
it would be a lot more useful if both locale and encoding could be set
per-database.

regards, tom lane

#4Alexey Slynko
slynko@tronet.ru
In reply to: Tom Lane (#3)
Re: Patch for database locale settings

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

--0-1348485674-1112025858=:22875
Content-Type: TEXT/PLAIN; charset=KOI8-R; format=flowed
Content-Transfer-Encoding: 8BIT

On Mon, Mar 28, 2005 at 12:16:42PM +0400, Alexey Slynko wrote:

this patch allow to use database locale settings. It remove cluster locale
settings, and append LCCTYPE and
LCCOLLATE items to CREATE DATABASE syntax.

Any considerations ?

The problem with this is what happens to indexes on shared relations.
If you change the collation, they are no longer valid. And you can't
just reindex them, because then they would no longer be valid for other
databases.

I havn't see any shared indices, that uses any variable collation, like text
indices. All shared indexed columns have integer and name type. As I understand,
all this types have fixed collation. Or I've missed something ?

Maybe it would work if we forced indexes on shared relations to be
scanned using a fixed collation.

Not sure about the ctype part ...

--
Alvaro Herrera (<alvherre[@]dcc.uchile.cl>)
"Los romО©╫nticos son seres que mueren de deseos de vida"

Alexey Slynko
E-mail: slynko@tronet.ru

--0-1348485674-1112025858=:22875--

#5Alexey Slynko
slynko@tronet.ru
In reply to: Tom Lane (#3)
Re: [PATCHES] Patch for database locale settings

Alvaro Herrera <alvherre@dcc.uchile.cl> writes:

Maybe it would work if we forced indexes on shared relations to be
scanned using a fixed collation.

The shared relations only have indexes on name, oid, and integer:
select distinct atttypid::regtype
from pg_class c join pg_attribute a on c.oid = a.attrelid
where relisshared and relkind = 'i';
and name has non-locale-sensitive ordering rules anyway. So that's
not the big problem; we could probably get away with decreeing that
name will always be that way and that shared relations can't have
locale-dependent indexes.

The big problem (and the reason why this idea has been shot down in
the past) is that CREATE DATABASE can't change the locale from what it
is in the template database unless it's prepared to reindex any locale-
sensitive indexes in the non-shared part of the template database.
Which would be a difficult undertaking seeing that we can't even connect
to the copied database until after commit.

We could maybe say that we will never have any locale-dependent indexes
at all on any system catalog, but what of user-defined tables in
template databases? It would simply not work to do something as simple
as creating a table with an indexed text column in template1.

There is another way to broke indexes, like specify another user-defined
template database in CREATE DATABASE.

I think, that we can add new parameter, like LOCALEDEPEND, in CREATE TYPE
syntax. It allows to separate locale-dependent indexes and reindex them. But I
havn't yet any idea, how we can reindex database immediately after creation. Any
suggestions ?

On the other hand you could argue that people already run the same kind
of risk when changing database encoding at CREATE, which is a feature
that's been there a long time and hasn't garnered many complaints.
Not so much that their indexes will break as that their data will.
So perhaps we should be willing to document "don't do that". Certainly
it would be a lot more useful if both locale and encoding could be set
per-database.

regards, tom lane

Alexey Slynko
E-mail: slynko@tronet.ru

#6Alvaro Herrera
alvherre@dcc.uchile.cl
In reply to: Tom Lane (#3)
Re: [PATCHES] Patch for database locale settings

On Mon, Mar 28, 2005 at 10:54:16AM -0500, Tom Lane wrote:

Alvaro Herrera <alvherre@dcc.uchile.cl> writes:

Maybe it would work if we forced indexes on shared relations to be
scanned using a fixed collation.

The shared relations only have indexes on name, oid, and integer:
select distinct atttypid::regtype
from pg_class c join pg_attribute a on c.oid = a.attrelid
where relisshared and relkind = 'i';
and name has non-locale-sensitive ordering rules anyway. So that's
not the big problem; we could probably get away with decreeing that
name will always be that way and that shared relations can't have
locale-dependent indexes.

This is good news.

The big problem (and the reason why this idea has been shot down in
the past) is that CREATE DATABASE can't change the locale from what it
is in the template database unless it's prepared to reindex any locale-
sensitive indexes in the non-shared part of the template database.
Which would be a difficult undertaking seeing that we can't even connect
to the copied database until after commit.

I don't see how this is a showstopper. At creation time we may decree
that the database is "incomplete", and users can't normally connect to
it; we only allow that after a phase of correcting minor issues, such as
reindexing if necessary. I recall Fabien Coelho wanted to do something
on this area too.

We could do this with a new column (say) datready in pg_database, set to
false by CreateDb(); at connection time this could be checked. The
downside I see to this is that the bit has to be checked at each
connection start; not sure if this is exceedingly onerous.

--
Alvaro Herrera (<alvherre[@]dcc.uchile.cl>)
Licensee shall have no right to use the Licensed Software
for productive or commercial use. (Licencia de StarOffice 6.0 beta)

#7Tom Lane
tgl@sss.pgh.pa.us
In reply to: Alvaro Herrera (#6)
Re: [PATCHES] Patch for database locale settings

Alvaro Herrera <alvherre@dcc.uchile.cl> writes:

I don't see how this is a showstopper. At creation time we may decree
that the database is "incomplete", and users can't normally connect to
it; we only allow that after a phase of correcting minor issues, such as
reindexing if necessary. I recall Fabien Coelho wanted to do something
on this area too.

I didn't like his patch then, and I don't like it now ;-). It strikes
me as a mighty dirty solution to the problem.

regards, tom lane

#8Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Tom Lane (#3)
Re: [PATCHES] Patch for database locale settings

Description added to TODO:

* Allow locale to be set at database creation

Currently locale can only be set during initdb. No global tables have
locale-aware columns. However, the database template used during
database creation might have locale-aware indexes. The indexes would
need to be reindexed to match the new locale.

---------------------------------------------------------------------------

Tom Lane wrote:

Alvaro Herrera <alvherre@dcc.uchile.cl> writes:

Maybe it would work if we forced indexes on shared relations to be
scanned using a fixed collation.

The shared relations only have indexes on name, oid, and integer:
select distinct atttypid::regtype
from pg_class c join pg_attribute a on c.oid = a.attrelid
where relisshared and relkind = 'i';
and name has non-locale-sensitive ordering rules anyway. So that's
not the big problem; we could probably get away with decreeing that
name will always be that way and that shared relations can't have
locale-dependent indexes.

The big problem (and the reason why this idea has been shot down in
the past) is that CREATE DATABASE can't change the locale from what it
is in the template database unless it's prepared to reindex any locale-
sensitive indexes in the non-shared part of the template database.
Which would be a difficult undertaking seeing that we can't even connect
to the copied database until after commit.

We could maybe say that we will never have any locale-dependent indexes
at all on any system catalog, but what of user-defined tables in
template databases? It would simply not work to do something as simple
as creating a table with an indexed text column in template1.

On the other hand you could argue that people already run the same kind
of risk when changing database encoding at CREATE, which is a feature
that's been there a long time and hasn't garnered many complaints.
Not so much that their indexes will break as that their data will.
So perhaps we should be willing to document "don't do that". Certainly
it would be a lot more useful if both locale and encoding could be set
per-database.

regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 5: Have you checked our extensive FAQ?

http://www.postgresql.org/docs/faq

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073