Commit 61d96749 authored by Heikki Linnakangas's avatar Heikki Linnakangas

Make LC_COLLATE and LC_CTYPE database-level settings. Collation and

ctype are now more like encoding, stored in new datcollate and datctype
columns in pg_database.

This is a stripped-down version of Radek Strnad's patch, with further
changes by me.
parent c52aab55
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.175 2008/09/19 19:03:40 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.176 2008/09/23 09:20:33 heikki Exp $ -->
<!-- <!--
Documentation of the system catalogs, directed toward PostgreSQL developers Documentation of the system catalogs, directed toward PostgreSQL developers
--> -->
...@@ -2149,6 +2149,20 @@ ...@@ -2149,6 +2149,20 @@
this number to the encoding name)</entry> this number to the encoding name)</entry>
</row> </row>
<row>
<entry><structfield>datcollate</structfield></entry>
<entry><type>name</type></entry>
<entry></entry>
<entry>LC_COLLATE for this database</entry>
</row>
<row>
<entry><structfield>datctype</structfield></entry>
<entry><type>name</type></entry>
<entry></entry>
<entry>LC_CTYPE for this database</entry>
</row>
<row> <row>
<entry><structfield>datistemplate</structfield></entry> <entry><structfield>datistemplate</structfield></entry>
<entry><type>bool</type></entry> <entry><type>bool</type></entry>
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/charset.sgml,v 2.87 2008/07/15 17:45:03 momjian Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/charset.sgml,v 2.88 2008/09/23 09:20:34 heikki Exp $ -->
<chapter id="charset"> <chapter id="charset">
<title>Localization</> <title>Localization</>
...@@ -130,23 +130,23 @@ initdb --locale=sv_SE ...@@ -130,23 +130,23 @@ initdb --locale=sv_SE
<para> <para>
The nature of some locale categories is that their value has to be The nature of some locale categories is that their value has to be
fixed for the lifetime of a database cluster. That is, once fixed when the database is created. You can use different settings
<command>initdb</command> has run, you cannot change them anymore. for different databases, but once a database is created, you cannot
<literal>LC_COLLATE</literal> and <literal>LC_CTYPE</literal> are change them for that database anymore. <literal>LC_COLLATE</literal>
those categories. They affect the sort order of indexes, so they and <literal>LC_CTYPE</literal> are those categories. They affect
must be kept fixed, or indexes on text columns will become corrupt. the sort order of indexes, so they must be kept fixed, or indexes on
<productname>PostgreSQL</productname> enforces this by recording text columns will become corrupt. The default values for these
the values of <envar>LC_COLLATE</> and <envar>LC_CTYPE</> that are categories are defined when <command>initdb</command> is run, and
seen by <command>initdb</>. The server automatically adopts those values are used when new databases are created, unless
those two values when it is started. specified otherwise in the <command>CREATE DATABASE</command> command.
</para> </para>
<para> <para>
The other locale categories can be changed as desired whenever the The other locale categories can be changed as desired whenever the
server is running by setting the run-time configuration variables server is running by setting the run-time configuration variables
that have the same name as the locale categories (see <xref that have the same name as the locale categories (see <xref
linkend="runtime-config-client-format"> for details). The defaults that are linkend="runtime-config-client-format"> for details). The defaults
chosen by <command>initdb</command> are actually only written into that are chosen by <command>initdb</command> are actually only written into
the configuration file <filename>postgresql.conf</filename> to the configuration file <filename>postgresql.conf</filename> to
serve as defaults when the server is started. If you delete these serve as defaults when the server is started. If you delete these
assignments from <filename>postgresql.conf</filename> then the assignments from <filename>postgresql.conf</filename> then the
...@@ -261,7 +261,7 @@ initdb --locale=sv_SE ...@@ -261,7 +261,7 @@ initdb --locale=sv_SE
<para> <para>
Check that <productname>PostgreSQL</> is actually using the locale Check that <productname>PostgreSQL</> is actually using the locale
that you think it is. <envar>LC_COLLATE</> and <envar>LC_CTYPE</> that you think it is. The default <envar>LC_COLLATE</> and <envar>LC_CTYPE</>
settings are determined at <command>initdb</> time and cannot be settings are determined at <command>initdb</> time and cannot be
changed without repeating <command>initdb</>. Other locale changed without repeating <command>initdb</>. Other locale
settings including <envar>LC_MESSAGES</> and <envar>LC_MONETARY</> settings including <envar>LC_MESSAGES</> and <envar>LC_MONETARY</>
...@@ -319,17 +319,11 @@ initdb --locale=sv_SE ...@@ -319,17 +319,11 @@ initdb --locale=sv_SE
</para> </para>
<para> <para>
An important restriction, however, is that each database character set An important restriction, however, is that each database's character set
must be compatible with the server's <envar>LC_CTYPE</> setting. must be compatible with the database's <envar>LC_CTYPE</> setting.
When <envar>LC_CTYPE</> is <literal>C</> or <literal>POSIX</>, any When <envar>LC_CTYPE</> is <literal>C</> or <literal>POSIX</>, any
character set is allowed, but for other settings of <envar>LC_CTYPE</> character set is allowed, but for other settings of <envar>LC_CTYPE</>
there is only one character set that will work correctly. there is only one character set that will work correctly.
Since the <envar>LC_CTYPE</> setting is frozen by <command>initdb</>, the
apparent flexibility to use different encodings in different databases
of a cluster is more theoretical than real, except when you select
<literal>C</> or <literal>POSIX</> locale (thus disabling any real locale
awareness). It is likely that these mechanisms will be revisited in future
versions of <productname>PostgreSQL</productname>.
</para> </para>
<sect2 id="multibyte-charset-supported"> <sect2 id="multibyte-charset-supported">
...@@ -734,19 +728,19 @@ initdb -E EUC_JP ...@@ -734,19 +728,19 @@ initdb -E EUC_JP
</para> </para>
<para> <para>
If you have selected <literal>C</> or <literal>POSIX</> locale, You can specify a non-default encoding at database creation time,
you can create a database with a different character set: provided that the encoding is compatible with the selected locale:
<screen> <screen>
createdb -E EUC_KR korean createdb -E EUC_KR -T template0 --lc-collate=ko_KR.euckr --lc-ctype=ko_KR.euckr korean
</screen> </screen>
This will create a database named <literal>korean</literal> that This will create a database named <literal>korean</literal> that
uses the character set <literal>EUC_KR</literal>. Another way to uses the character set <literal>EUC_KR</literal>, and locale <literal>ko_KR</literal>.
accomplish this is to use this SQL command: Another way to accomplish this is to use this SQL command:
<programlisting> <programlisting>
CREATE DATABASE korean WITH ENCODING 'EUC_KR'; CREATE DATABASE korean WITH ENCODING 'EUC_KR' COLLATE='ko_KR.euckr' CTYPE='ko_KR.euckr' TEMPLATE=template0;
</programlisting> </programlisting>
The encoding for a database is stored in the system catalog The encoding for a database is stored in the system catalog
...@@ -756,20 +750,17 @@ CREATE DATABASE korean WITH ENCODING 'EUC_KR'; ...@@ -756,20 +750,17 @@ CREATE DATABASE korean WITH ENCODING 'EUC_KR';
<screen> <screen>
$ <userinput>psql -l</userinput> $ <userinput>psql -l</userinput>
List of databases List of databases
Database | Owner | Encoding Name | Owner | Encoding | Collation | Ctype | Access Privileges
---------------+---------+--------------- -----------+----------+-----------+-------------+-------------+-------------------------------------
euc_cn | t-ishii | EUC_CN clocaledb | hlinnaka | SQL_ASCII | C | C |
euc_jp | t-ishii | EUC_JP englishdb | hlinnaka | UTF8 | en_GB.UTF8 | en_GB.UTF8 |
euc_kr | t-ishii | EUC_KR japanese | hlinnaka | UTF8 | ja_JP.UTF8 | ja_JP.UTF8 |
euc_tw | t-ishii | EUC_TW korean | hlinnaka | EUC_KR | ko_KR.euckr | ko_KR.euckr |
mule_internal | t-ishii | MULE_INTERNAL postgres | hlinnaka | UTF8 | fi_FI.UTF8 | fi_FI.UTF8 |
postgres | t-ishii | EUC_JP template0 | hlinnaka | UTF8 | fi_FI.UTF8 | fi_FI.UTF8 | {=c/hlinnaka,hlinnaka=CTc/hlinnaka}
regression | t-ishii | SQL_ASCII template1 | hlinnaka | UTF8 | fi_FI.UTF8 | fi_FI.UTF8 | {=c/hlinnaka,hlinnaka=CTc/hlinnaka}
template1 | t-ishii | EUC_JP (7 rows)
test | t-ishii | EUC_JP
utf8 | t-ishii | UTF8
(9 rows)
</screen> </screen>
</para> </para>
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/indices.sgml,v 1.74 2008/07/11 21:06:28 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/indices.sgml,v 1.75 2008/09/23 09:20:34 heikki Exp $ -->
<chapter id="indexes"> <chapter id="indexes">
<title id="indexes-title">Indexes</title> <title id="indexes-title">Indexes</title>
...@@ -157,7 +157,7 @@ CREATE INDEX test1_id_index ON test1 (id); ...@@ -157,7 +157,7 @@ CREATE INDEX test1_id_index ON test1 (id);
<emphasis>if</emphasis> the pattern is a constant and is anchored to <emphasis>if</emphasis> the pattern is a constant and is anchored to
the beginning of the string &mdash; for example, <literal>col LIKE the beginning of the string &mdash; for example, <literal>col LIKE
'foo%'</literal> or <literal>col ~ '^foo'</literal>, but not 'foo%'</literal> or <literal>col ~ '^foo'</literal>, but not
<literal>col LIKE '%bar'</literal>. However, if your server does not <literal>col LIKE '%bar'</literal>. However, if your database does not
use the C locale you will need to create the index with a special use the C locale you will need to create the index with a special
operator class to support indexing of pattern-matching queries. See operator class to support indexing of pattern-matching queries. See
<xref linkend="indexes-opclass"> below. It is also possible to use <xref linkend="indexes-opclass"> below. It is also possible to use
...@@ -922,7 +922,7 @@ CREATE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable> ...@@ -922,7 +922,7 @@ CREATE INDEX <replaceable>name</replaceable> ON <replaceable>table</replaceable>
according to the locale-specific collation rules. This makes according to the locale-specific collation rules. This makes
these operator classes suitable for use by queries involving these operator classes suitable for use by queries involving
pattern matching expressions (<literal>LIKE</literal> or POSIX pattern matching expressions (<literal>LIKE</literal> or POSIX
regular expressions) when the server does not use the standard regular expressions) when the database does not use the standard
<quote>C</quote> locale. As an example, you might index a <quote>C</quote> locale. As an example, you might index a
<type>varchar</type> column like this: <type>varchar</type> column like this:
<programlisting> <programlisting>
......
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_database.sgml,v 1.48 2007/09/28 22:25:49 tgl Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/create_database.sgml,v 1.49 2008/09/23 09:20:34 heikki Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -24,6 +24,8 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> ...@@ -24,6 +24,8 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
[ [ WITH ] [ OWNER [=] <replaceable class="parameter">dbowner</replaceable> ] [ [ WITH ] [ OWNER [=] <replaceable class="parameter">dbowner</replaceable> ]
[ TEMPLATE [=] <replaceable class="parameter">template</replaceable> ] [ TEMPLATE [=] <replaceable class="parameter">template</replaceable> ]
[ ENCODING [=] <replaceable class="parameter">encoding</replaceable> ] [ ENCODING [=] <replaceable class="parameter">encoding</replaceable> ]
[ COLLATE [=] <replaceable class="parameter">collate</replaceable> ]
[ CTYPE [=] <replaceable class="parameter">ctype</replaceable> ]
[ TABLESPACE [=] <replaceable class="parameter">tablespace</replaceable> ] [ TABLESPACE [=] <replaceable class="parameter">tablespace</replaceable> ]
[ CONNECTION LIMIT [=] <replaceable class="parameter">connlimit</replaceable> ] ] [ CONNECTION LIMIT [=] <replaceable class="parameter">connlimit</replaceable> ] ]
</synopsis> </synopsis>
...@@ -112,6 +114,29 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> ...@@ -112,6 +114,29 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><replaceable class="parameter">collate</replaceable></term>
<listitem>
<para>
Collation order (<literal>LC_COLLATE</>) to use in the new database.
This affects the sort order applied to strings, e.g in queries with
ORDER BY, as well as the order used in indexes on text columns.
The default is to use the collation order of the template database.
See below for additional restrictions.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">ctype</replaceable></term>
<listitem>
<para>
Character classification (<literal>LC_CTYPE</>) to use in the new
database. This affects the categorization of characters, e.g. lower,
upper and digit. The default is to use the character classification of
the template database. See below for additional restrictions.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><replaceable class="parameter">tablespace</replaceable></term> <term><replaceable class="parameter">tablespace</replaceable></term>
<listitem> <listitem>
...@@ -180,13 +205,11 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> ...@@ -180,13 +205,11 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
</para> </para>
<para> <para>
Any character set encoding specified for the new database must be The character set encoding specified for the new database must be
compatible with the server's <envar>LC_CTYPE</> locale setting. compatible with the chosen COLLATE and CTYPE settings.
If <envar>LC_CTYPE</> is <literal>C</> (or equivalently If <envar>LC_CTYPE</> is <literal>C</> (or equivalently
<literal>POSIX</>), then all encodings are allowed, but for other <literal>POSIX</>), then all encodings are allowed, but for other
locale settings there is only one encoding that will work properly, locale settings there is only one encoding that will work properly.
and so the apparent freedom to specify an encoding is illusory if
you didn't initialize the database cluster in <literal>C</> locale.
<command>CREATE DATABASE</> will allow superusers to specify <command>CREATE DATABASE</> will allow superusers to specify
<literal>SQL_ASCII</> encoding regardless of the locale setting, <literal>SQL_ASCII</> encoding regardless of the locale setting,
but this choice is deprecated and may result in misbehavior of but this choice is deprecated and may result in misbehavior of
...@@ -194,6 +217,16 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> ...@@ -194,6 +217,16 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
with the locale is stored in the database. with the locale is stored in the database.
</para> </para>
<para>
The <literal>COLLATE</> and <literal>CTYPE</> settings must match
those of the template database, except when template0 is used as
template. This is because <literal>COLLATE</> and <literal>CTYPE</>
affects the ordering in indexes, so that any indexes copied from the
template database would be invalid in the new database with different
settings. <literal>template0</literal>, however, is known to not
contain any indexes that would be affected.
</para>
<para> <para>
The <literal>CONNECTION LIMIT</> option is only enforced approximately; The <literal>CONNECTION LIMIT</> option is only enforced approximately;
if two new sessions start at about the same time when just one if two new sessions start at about the same time when just one
......
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/initdb.sgml,v 1.43 2007/03/26 17:23:36 tgl Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/initdb.sgml,v 1.44 2008/09/23 09:20:34 heikki Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -76,25 +76,34 @@ PostgreSQL documentation ...@@ -76,25 +76,34 @@ PostgreSQL documentation
<para> <para>
<command>initdb</command> initializes the database cluster's default <command>initdb</command> initializes the database cluster's default
locale and character set encoding. The collation order locale and character set encoding. The character set encoding,
(<literal>LC_COLLATE</>) and character set classes collation order (<literal>LC_COLLATE</>) and character set classes
(<literal>LC_CTYPE</>, e.g. upper, lower, digit) are fixed for all (<literal>LC_CTYPE</>, e.g. upper, lower, digit) can be set separately
databases and cannot be changed. Collation orders other than for a database when it is created. <command>initdb</command> determines
<literal>C</> or <literal>POSIX</> also have a performance penalty. those settings for the <literal>template1</literal> database, which will
For these reasons it is important to choose the right locale when serve as the default for all other databases.
running <command>initdb</command>. The remaining locale categories </para>
can be changed later when the server is started. All server locale
values (<literal>lc_*</>) can be displayed via <command>SHOW ALL</>. <para>
To alter the default collation order or character set classes, use the
<option>--lc-collate</option> and <option>--lc-ctype</option> options.
Collation orders other than <literal>C</> or <literal>POSIX</> also have
a performance penalty. For these reasons it is important to choose the
right locale when running <command>initdb</command>.
</para>
<para>
The remaining locale categories can be changed later when the server
is started. You can also use <option>--locale</option> to set the
default for all locale categories, including collation order and
character set classes. All server locale values (<literal>lc_*</>) can
be displayed via <command>SHOW ALL</>.
More details can be found in <xref linkend="locale">. More details can be found in <xref linkend="locale">.
</para> </para>
<para> <para>
The character set encoding can be set separately for a database when To alter the default encoding, use the <option>--encoding</option>.
it is created. <command>initdb</command> determines the encoding for More details can be found in <xref linkend="multibyte">.
the <literal>template1</literal> database, which will serve as the
default for all other databases. To alter the default encoding use
the <option>--encoding</option> option. More details can be found in
<xref linkend="multibyte">.
</para> </para>
</refsect1> </refsect1>
......
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/pg_controldata.sgml,v 1.10 2007/02/20 18:10:58 momjian Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/pg_controldata.sgml,v 1.11 2008/09/23 09:20:35 heikki Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -30,7 +30,7 @@ PostgreSQL documentation ...@@ -30,7 +30,7 @@ PostgreSQL documentation
<title>Description</title> <title>Description</title>
<para> <para>
<command>pg_controldata</command> prints information initialized during <command>pg_controldata</command> prints information initialized during
<command>initdb</>, such as the catalog version and server locale. <command>initdb</>, such as the catalog version.
It also shows information about write-ahead logging and checkpoint It also shows information about write-ahead logging and checkpoint
processing. This information is cluster-wide, and not specific to any one processing. This information is cluster-wide, and not specific to any one
database. database.
......
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/pg_resetxlog.sgml,v 1.20 2007/01/31 23:26:04 momjian Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/pg_resetxlog.sgml,v 1.21 2008/09/23 09:20:35 heikki Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -62,14 +62,10 @@ PostgreSQL documentation ...@@ -62,14 +62,10 @@ PostgreSQL documentation
by specifying the <literal>-f</> (force) switch. In this case plausible by specifying the <literal>-f</> (force) switch. In this case plausible
values will be substituted for the missing data. Most of the fields can be values will be substituted for the missing data. Most of the fields can be
expected to match, but manual assistance might be needed for the next OID, expected to match, but manual assistance might be needed for the next OID,
next transaction ID and epoch, next multitransaction ID and offset, next transaction ID and epoch, next multitransaction ID and offset, and
WAL starting address, and database locale fields. WAL starting address fields. These fields can be set using the switches
The first six of these can be set using the switches discussed below. discussed below. If you are not able to determine correct values for all
<command>pg_resetxlog</command>'s own environment is the source for its these fields, <literal>-f</> can still be used, but
guess at the locale fields; take care that <envar>LANG</> and so forth
match the environment that <command>initdb</> was run in.
If you are not able to determine correct values for all these fields,
<literal>-f</> can still be used, but
the recovered database must be treated with even more suspicion than the recovered database must be treated with even more suspicion than
usual: an immediate dump and reload is imperative. <emphasis>Do not</> usual: an immediate dump and reload is imperative. <emphasis>Do not</>
execute any data-modifying operations in the database before you dump, execute any data-modifying operations in the database before you dump,
......
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/select.sgml,v 1.103 2008/02/15 22:17:06 tgl Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/select.sgml,v 1.104 2008/09/23 09:20:35 heikki Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -747,8 +747,7 @@ SELECT name FROM distributors ORDER BY code; ...@@ -747,8 +747,7 @@ SELECT name FROM distributors ORDER BY code;
<para> <para>
Character-string data is sorted according to the locale-specific Character-string data is sorted according to the locale-specific
collation order that was established when the database cluster collation order that was established when the database was created.
was initialized.
</para> </para>
</refsect2> </refsect2>
......
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/show.sgml,v 1.45 2008/01/03 21:23:15 tgl Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/show.sgml,v 1.46 2008/09/23 09:20:35 heikki Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -82,8 +82,8 @@ SHOW ALL ...@@ -82,8 +82,8 @@ SHOW ALL
<para> <para>
Shows the database's locale setting for collation (text Shows the database's locale setting for collation (text
ordering). At present, this parameter can be shown but not ordering). At present, this parameter can be shown but not
set, because the setting is determined at set, because the setting is determined at database creation
<command>initdb</> time. time.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -94,8 +94,8 @@ SHOW ALL ...@@ -94,8 +94,8 @@ SHOW ALL
<para> <para>
Shows the database's locale setting for character Shows the database's locale setting for character
classification. At present, this parameter can be shown but classification. At present, this parameter can be shown but
not set, because the setting is determined at not set, because the setting is determined at database creation
<command>initdb</> time. time.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.416 2008/04/26 22:47:40 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.417 2008/09/23 09:20:34 heikki Exp $ -->
<chapter Id="runtime"> <chapter Id="runtime">
<title>Operating System Environment</title> <title>Operating System Environment</title>
...@@ -145,11 +145,12 @@ postgres$ <userinput>initdb -D /usr/local/pgsql/data</userinput> ...@@ -145,11 +145,12 @@ postgres$ <userinput>initdb -D /usr/local/pgsql/data</userinput>
Normally, it will just take the locale settings in the environment Normally, it will just take the locale settings in the environment
and apply them to the initialized database. It is possible to and apply them to the initialized database. It is possible to
specify a different locale for the database; more information about specify a different locale for the database; more information about
that can be found in <xref linkend="locale">. The sort order used that can be found in <xref linkend="locale">. The default sort order used
within a particular database cluster is set by within the particular database cluster is set by
<command>initdb</command> and cannot be changed later, short of <command>initdb</command>, and while you can create new databases using
dumping all data, rerunning <command>initdb</command>, and reloading different sort order, the order used in the template databases that initdb
the data. There is also a performance impact for using locales creates cannot be changed without dropping and recreating them.
There is also a performance impact for using locales
other than <literal>C</> or <literal>POSIX</>. Therefore, it is other than <literal>C</> or <literal>POSIX</>. Therefore, it is
important to make this choice correctly the first time. important to make this choice correctly the first time.
</para> </para>
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/textsearch.sgml,v 1.44 2008/05/16 16:31:01 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/textsearch.sgml,v 1.45 2008/09/23 09:20:34 heikki Exp $ -->
<chapter id="textsearch"> <chapter id="textsearch">
<title id="textsearch-title">Full Text Search</title> <title id="textsearch-title">Full Text Search</title>
...@@ -1896,7 +1896,7 @@ LIMIT 10; ...@@ -1896,7 +1896,7 @@ LIMIT 10;
<note> <note>
<para> <para>
The parser's notion of a <quote>letter</> is determined by the server's The parser's notion of a <quote>letter</> is determined by the database's
locale setting, specifically <varname>lc_ctype</>. Words containing locale setting, specifically <varname>lc_ctype</>. Words containing
only the basic ASCII letters are reported as a separate token type, only the basic ASCII letters are reported as a separate token type,
since it is sometimes useful to distinguish them. In most European since it is sometimes useful to distinguish them. In most European
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.318 2008/09/08 16:42:15 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.319 2008/09/23 09:20:35 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
#include "storage/smgr.h" #include "storage/smgr.h"
#include "storage/spin.h" #include "storage/spin.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/pg_locale.h" #include "utils/guc.h"
#include "utils/ps_status.h" #include "utils/ps_status.h"
...@@ -3847,7 +3847,6 @@ WriteControlFile(void) ...@@ -3847,7 +3847,6 @@ WriteControlFile(void)
{ {
int fd; int fd;
char buffer[PG_CONTROL_SIZE]; /* need not be aligned */ char buffer[PG_CONTROL_SIZE]; /* need not be aligned */
char *localeptr;
/* /*
* Initialize version and compatibility-check fields * Initialize version and compatibility-check fields
...@@ -3876,18 +3875,6 @@ WriteControlFile(void) ...@@ -3876,18 +3875,6 @@ WriteControlFile(void)
ControlFile->float4ByVal = FLOAT4PASSBYVAL; ControlFile->float4ByVal = FLOAT4PASSBYVAL;
ControlFile->float8ByVal = FLOAT8PASSBYVAL; 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 */ /* Contents are protected with a CRC */
INIT_CRC32(ControlFile->crc); INIT_CRC32(ControlFile->crc);
COMP_CRC32(ControlFile->crc, COMP_CRC32(ControlFile->crc,
...@@ -4126,34 +4113,6 @@ ReadControlFile(void) ...@@ -4126,34 +4113,6 @@ ReadControlFile(void)
" but the server was compiled without USE_FLOAT8_BYVAL."), " but the server was compiled without USE_FLOAT8_BYVAL."),
errhint("It looks like you need to recompile or initdb."))); errhint("It looks like you need to recompile or initdb.")));
#endif #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 void
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -53,6 +53,7 @@
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/guc.h" #include "utils/guc.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/pg_locale.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "utils/tqual.h" #include "utils/tqual.h"
...@@ -69,7 +70,7 @@ static bool get_db_info(const char *name, LOCKMODE lockmode, ...@@ -69,7 +70,7 @@ static bool get_db_info(const char *name, LOCKMODE lockmode,
Oid *dbIdP, Oid *ownerIdP, Oid *dbIdP, Oid *ownerIdP,
int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP, int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
Oid *dbLastSysOidP, TransactionId *dbFrozenXidP, Oid *dbLastSysOidP, TransactionId *dbFrozenXidP,
Oid *dbTablespace); Oid *dbTablespace, char **dbCollate, char **dbCtype);
static bool have_createdb_privilege(void); static bool have_createdb_privilege(void);
static void remove_dbtablespaces(Oid db_id); static void remove_dbtablespaces(Oid db_id);
static bool check_db_file_conflict(Oid db_id); static bool check_db_file_conflict(Oid db_id);
...@@ -87,6 +88,8 @@ createdb(const CreatedbStmt *stmt) ...@@ -87,6 +88,8 @@ createdb(const CreatedbStmt *stmt)
Oid src_dboid; Oid src_dboid;
Oid src_owner; Oid src_owner;
int src_encoding; int src_encoding;
char *src_collate;
char *src_ctype;
bool src_istemplate; bool src_istemplate;
bool src_allowconn; bool src_allowconn;
Oid src_lastsysoid; Oid src_lastsysoid;
...@@ -104,10 +107,14 @@ createdb(const CreatedbStmt *stmt) ...@@ -104,10 +107,14 @@ createdb(const CreatedbStmt *stmt)
DefElem *downer = NULL; DefElem *downer = NULL;
DefElem *dtemplate = NULL; DefElem *dtemplate = NULL;
DefElem *dencoding = NULL; DefElem *dencoding = NULL;
DefElem *dcollate = NULL;
DefElem *dctype = NULL;
DefElem *dconnlimit = NULL; DefElem *dconnlimit = NULL;
char *dbname = stmt->dbname; char *dbname = stmt->dbname;
char *dbowner = NULL; char *dbowner = NULL;
const char *dbtemplate = NULL; const char *dbtemplate = NULL;
char *dbcollate = NULL;
char *dbctype = NULL;
int encoding = -1; int encoding = -1;
int dbconnlimit = -1; int dbconnlimit = -1;
int ctype_encoding; int ctype_encoding;
...@@ -152,6 +159,22 @@ createdb(const CreatedbStmt *stmt) ...@@ -152,6 +159,22 @@ createdb(const CreatedbStmt *stmt)
errmsg("conflicting or redundant options"))); errmsg("conflicting or redundant options")));
dencoding = defel; 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) else if (strcmp(defel->defname, "connectionlimit") == 0)
{ {
if (dconnlimit) if (dconnlimit)
...@@ -205,6 +228,11 @@ createdb(const CreatedbStmt *stmt) ...@@ -205,6 +228,11 @@ createdb(const CreatedbStmt *stmt)
elog(ERROR, "unrecognized node type: %d", elog(ERROR, "unrecognized node type: %d",
nodeTag(dencoding->arg)); nodeTag(dencoding->arg));
} }
if (dcollate && dcollate->arg)
dbcollate = strVal(dcollate->arg);
if (dctype && dctype->arg)
dbctype = strVal(dctype->arg);
if (dconnlimit && dconnlimit->arg) if (dconnlimit && dconnlimit->arg)
dbconnlimit = intVal(dconnlimit->arg); dbconnlimit = intVal(dconnlimit->arg);
...@@ -243,7 +271,8 @@ createdb(const CreatedbStmt *stmt) ...@@ -243,7 +271,8 @@ createdb(const CreatedbStmt *stmt)
if (!get_db_info(dbtemplate, ShareLock, if (!get_db_info(dbtemplate, ShareLock,
&src_dboid, &src_owner, &src_encoding, &src_dboid, &src_owner, &src_encoding,
&src_istemplate, &src_allowconn, &src_lastsysoid, &src_istemplate, &src_allowconn, &src_lastsysoid,
&src_frozenxid, &src_deftablespace)) &src_frozenxid, &src_deftablespace,
&src_collate, &src_ctype))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE), (errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("template database \"%s\" does not exist", errmsg("template database \"%s\" does not exist",
...@@ -262,9 +291,13 @@ createdb(const CreatedbStmt *stmt) ...@@ -262,9 +291,13 @@ createdb(const CreatedbStmt *stmt)
dbtemplate))); dbtemplate)));
} }
/* If encoding is defaulted, use source's encoding */ /* If encoding or locales are defaulted, use source's setting */
if (encoding < 0) if (encoding < 0)
encoding = src_encoding; encoding = src_encoding;
if (dbcollate == NULL)
dbcollate = src_collate;
if (dbctype == NULL)
dbctype = src_ctype;
/* Some encodings are client only */ /* Some encodings are client only */
if (!PG_VALID_BE_ENCODING(encoding)) if (!PG_VALID_BE_ENCODING(encoding))
...@@ -272,6 +305,16 @@ createdb(const CreatedbStmt *stmt) ...@@ -272,6 +305,16 @@ createdb(const CreatedbStmt *stmt)
(errcode(ERRCODE_WRONG_OBJECT_TYPE), (errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("invalid server encoding %d", encoding))); 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 * Check whether encoding matches server locale settings. We allow
* mismatch in three cases: * mismatch in three cases:
...@@ -290,7 +333,7 @@ createdb(const CreatedbStmt *stmt) ...@@ -290,7 +333,7 @@ createdb(const CreatedbStmt *stmt)
* *
* Note: if you change this policy, fix initdb to match. * 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 || if (!(ctype_encoding == encoding ||
ctype_encoding == PG_SQL_ASCII || ctype_encoding == PG_SQL_ASCII ||
...@@ -299,12 +342,32 @@ createdb(const CreatedbStmt *stmt) ...@@ -299,12 +342,32 @@ createdb(const CreatedbStmt *stmt)
#endif #endif
(encoding == PG_SQL_ASCII && superuser()))) (encoding == PG_SQL_ASCII && superuser())))
ereport(ERROR, 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), pg_encoding_to_char(encoding),
setlocale(LC_CTYPE, NULL)), dbctype),
errdetail("The server's LC_CTYPE setting requires encoding %s.", errdetail("The chosen LC_CTYPE setting requires encoding %s.",
pg_encoding_to_char(ctype_encoding)))); 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 */ /* Resolve default tablespace for new database */
if (dtablespacename && dtablespacename->arg) if (dtablespacename && dtablespacename->arg)
{ {
...@@ -421,6 +484,10 @@ createdb(const CreatedbStmt *stmt) ...@@ -421,6 +484,10 @@ createdb(const CreatedbStmt *stmt)
DirectFunctionCall1(namein, CStringGetDatum(dbname)); DirectFunctionCall1(namein, CStringGetDatum(dbname));
new_record[Anum_pg_database_datdba - 1] = ObjectIdGetDatum(datdba); new_record[Anum_pg_database_datdba - 1] = ObjectIdGetDatum(datdba);
new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding); 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_datistemplate - 1] = BoolGetDatum(false);
new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(true); new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(true);
new_record[Anum_pg_database_datconnlimit - 1] = Int32GetDatum(dbconnlimit); new_record[Anum_pg_database_datconnlimit - 1] = Int32GetDatum(dbconnlimit);
...@@ -629,7 +696,7 @@ dropdb(const char *dbname, bool missing_ok) ...@@ -629,7 +696,7 @@ dropdb(const char *dbname, bool missing_ok)
pgdbrel = heap_open(DatabaseRelationId, RowExclusiveLock); pgdbrel = heap_open(DatabaseRelationId, RowExclusiveLock);
if (!get_db_info(dbname, AccessExclusiveLock, &db_id, NULL, NULL, 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) if (!missing_ok)
{ {
...@@ -781,7 +848,7 @@ RenameDatabase(const char *oldname, const char *newname) ...@@ -781,7 +848,7 @@ RenameDatabase(const char *oldname, const char *newname)
rel = heap_open(DatabaseRelationId, RowExclusiveLock); rel = heap_open(DatabaseRelationId, RowExclusiveLock);
if (!get_db_info(oldname, AccessExclusiveLock, &db_id, NULL, NULL, if (!get_db_info(oldname, AccessExclusiveLock, &db_id, NULL, NULL,
NULL, NULL, NULL, NULL, NULL)) NULL, NULL, NULL, NULL, NULL, NULL, NULL))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE), (errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database \"%s\" does not exist", oldname))); errmsg("database \"%s\" does not exist", oldname)));
...@@ -1168,7 +1235,7 @@ get_db_info(const char *name, LOCKMODE lockmode, ...@@ -1168,7 +1235,7 @@ get_db_info(const char *name, LOCKMODE lockmode,
Oid *dbIdP, Oid *ownerIdP, Oid *dbIdP, Oid *ownerIdP,
int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP, int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
Oid *dbLastSysOidP, TransactionId *dbFrozenXidP, Oid *dbLastSysOidP, TransactionId *dbFrozenXidP,
Oid *dbTablespace) Oid *dbTablespace, char **dbCollate, char **dbCtype)
{ {
bool result = false; bool result = false;
Relation relation; Relation relation;
...@@ -1259,6 +1326,11 @@ get_db_info(const char *name, LOCKMODE lockmode, ...@@ -1259,6 +1326,11 @@ get_db_info(const char *name, LOCKMODE lockmode,
/* default tablespace for this database */ /* default tablespace for this database */
if (dbTablespace) if (dbTablespace)
*dbTablespace = dbform->dattablespace; *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); ReleaseSysCache(tuple);
result = true; result = true;
break; break;
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.623 2008/09/11 15:27:30 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.624 2008/09/23 09:20:35 heikki Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -398,7 +398,7 @@ static TypeName *TableFuncTypeName(List *columns); ...@@ -398,7 +398,7 @@ static TypeName *TableFuncTypeName(List *columns);
CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS
CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CREATEDB CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CREATEDB
CREATEROLE CREATEUSER CROSS CSV CURRENT_P CURRENT_DATE CURRENT_ROLE CREATEROLE CREATEUSER CROSS CSV CTYPE CURRENT_P CURRENT_DATE CURRENT_ROLE
CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
...@@ -5458,6 +5458,22 @@ createdb_opt_item: ...@@ -5458,6 +5458,22 @@ createdb_opt_item:
{ {
$$ = makeDefElem("encoding", NULL); $$ = makeDefElem("encoding", NULL);
} }
| COLLATE opt_equal Sconst
{
$$ = makeDefElem("collate", (Node *)makeString($3));
}
| COLLATE opt_equal DEFAULT
{
$$ = makeDefElem("collate", NULL);
}
| CTYPE opt_equal Sconst
{
$$ = makeDefElem("ctype", (Node *)makeString($3));
}
| CTYPE opt_equal DEFAULT
{
$$ = makeDefElem("ctype", NULL);
}
| CONNECTION LIMIT opt_equal SignedIconst | CONNECTION LIMIT opt_equal SignedIconst
{ {
$$ = makeDefElem("connectionlimit", (Node *)makeInteger($4)); $$ = makeDefElem("connectionlimit", (Node *)makeInteger($4));
...@@ -9216,6 +9232,7 @@ unreserved_keyword: ...@@ -9216,6 +9232,7 @@ unreserved_keyword:
| CREATEROLE | CREATEROLE
| CREATEUSER | CREATEUSER
| CSV | CSV
| CTYPE
| CURRENT_P | CURRENT_P
| CURSOR | CURSOR
| CYCLE | CYCLE
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.200 2008/08/29 13:02:32 petere Exp $ * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.201 2008/09/23 09:20:36 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -114,6 +114,7 @@ const ScanKeyword ScanKeywords[] = { ...@@ -114,6 +114,7 @@ const ScanKeyword ScanKeywords[] = {
{"createuser", CREATEUSER, UNRESERVED_KEYWORD}, {"createuser", CREATEUSER, UNRESERVED_KEYWORD},
{"cross", CROSS, TYPE_FUNC_NAME_KEYWORD}, {"cross", CROSS, TYPE_FUNC_NAME_KEYWORD},
{"csv", CSV, UNRESERVED_KEYWORD}, {"csv", CSV, UNRESERVED_KEYWORD},
{"ctype", CTYPE, UNRESERVED_KEYWORD},
{"current", CURRENT_P, UNRESERVED_KEYWORD}, {"current", CURRENT_P, UNRESERVED_KEYWORD},
{"current_date", CURRENT_DATE, RESERVED_KEYWORD}, {"current_date", CURRENT_DATE, RESERVED_KEYWORD},
{"current_role", CURRENT_ROLE, RESERVED_KEYWORD}, {"current_role", CURRENT_ROLE, RESERVED_KEYWORD},
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.563 2008/09/15 12:32:57 mha Exp $ * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.564 2008/09/23 09:20:36 heikki Exp $
* *
* NOTES * NOTES
* *
...@@ -403,8 +403,8 @@ typedef struct ...@@ -403,8 +403,8 @@ typedef struct
char my_exec_path[MAXPGPATH]; char my_exec_path[MAXPGPATH];
char pkglib_path[MAXPGPATH]; char pkglib_path[MAXPGPATH];
char ExtraOptions[MAXPGPATH]; char ExtraOptions[MAXPGPATH];
char lc_collate[LOCALE_NAME_BUFLEN]; char lc_collate[NAMEDATALEN];
char lc_ctype[LOCALE_NAME_BUFLEN]; char lc_ctype[NAMEDATALEN];
} BackendParameters; } BackendParameters;
static void read_backend_variables(char *id, Port *port); static void read_backend_variables(char *id, Port *port);
...@@ -4294,8 +4294,8 @@ save_backend_variables(BackendParameters * param, Port *port, ...@@ -4294,8 +4294,8 @@ save_backend_variables(BackendParameters * param, Port *port,
strlcpy(param->ExtraOptions, ExtraOptions, MAXPGPATH); strlcpy(param->ExtraOptions, ExtraOptions, MAXPGPATH);
strlcpy(param->lc_collate, setlocale(LC_COLLATE, NULL), LOCALE_NAME_BUFLEN); strlcpy(param->lc_collate, setlocale(LC_COLLATE, NULL), NAMEDATALEN);
strlcpy(param->lc_ctype, setlocale(LC_CTYPE, NULL), LOCALE_NAME_BUFLEN); strlcpy(param->lc_ctype, setlocale(LC_CTYPE, NULL), NAMEDATALEN);
return true; return true;
} }
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* *
* Portions Copyright (c) 2002-2008, PostgreSQL Global Development Group * Portions Copyright (c) 2002-2008, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.41 2008/05/19 18:08:16 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.42 2008/09/23 09:20:36 heikki Exp $
* *
*----------------------------------------------------------------------- *-----------------------------------------------------------------------
*/ */
...@@ -76,7 +76,7 @@ static bool CurrentLCTimeValid = false; ...@@ -76,7 +76,7 @@ static bool CurrentLCTimeValid = false;
/* Environment variable storage area */ /* Environment variable storage area */
#define LC_ENV_BUFSIZE (LOCALE_NAME_BUFLEN + 20) #define LC_ENV_BUFSIZE (NAMEDATALEN + 20)
static char lc_collate_envbuf[LC_ENV_BUFSIZE]; static char lc_collate_envbuf[LC_ENV_BUFSIZE];
static char lc_ctype_envbuf[LC_ENV_BUFSIZE]; static char lc_ctype_envbuf[LC_ENV_BUFSIZE];
...@@ -189,6 +189,31 @@ pg_perm_setlocale(int category, const char *locale) ...@@ -189,6 +189,31 @@ pg_perm_setlocale(int category, const char *locale)
} }
/*
* Is the locale name valid for the locale category?
*/
bool
check_locale(int category, const char *value)
{
char *save;
bool ret;
save = setlocale(category, NULL);
if (!save)
return false; /* won't happen, we hope */
/* save may be pointing at a modifiable scratch variable, see above */
save = pstrdup(save);
/* set the locale with setlocale, to see if it accepts it. */
ret = (setlocale(category, value) != NULL);
setlocale(category, save); /* assume this won't fail */
pfree(save);
return ret;
}
/* GUC assign hooks */ /* GUC assign hooks */
/* /*
...@@ -203,21 +228,9 @@ pg_perm_setlocale(int category, const char *locale) ...@@ -203,21 +228,9 @@ pg_perm_setlocale(int category, const char *locale)
static const char * static const char *
locale_xxx_assign(int category, const char *value, bool doit, GucSource source) locale_xxx_assign(int category, const char *value, bool doit, GucSource source)
{ {
char *save; if (!check_locale(category, value))
save = setlocale(category, NULL);
if (!save)
return NULL; /* won't happen, we hope */
/* save may be pointing at a modifiable scratch variable, see above */
save = pstrdup(save);
if (!setlocale(category, value))
value = NULL; /* set failure return marker */ value = NULL; /* set failure return marker */
setlocale(category, save); /* assume this won't fail */
pfree(save);
/* need to reload cache next time? */ /* need to reload cache next time? */
if (doit && value != NULL) if (doit && value != NULL)
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.185 2008/09/11 14:01:09 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.186 2008/09/23 09:20:36 heikki Exp $
* *
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
...@@ -159,6 +159,8 @@ CheckMyDatabase(const char *name, bool am_superuser) ...@@ -159,6 +159,8 @@ CheckMyDatabase(const char *name, bool am_superuser)
{ {
HeapTuple tup; HeapTuple tup;
Form_pg_database dbform; Form_pg_database dbform;
char *collate;
char *ctype;
/* Fetch our real pg_database row */ /* Fetch our real pg_database row */
tup = SearchSysCache(DATABASEOID, tup = SearchSysCache(DATABASEOID,
...@@ -240,6 +242,28 @@ CheckMyDatabase(const char *name, bool am_superuser) ...@@ -240,6 +242,28 @@ CheckMyDatabase(const char *name, bool am_superuser)
/* If we have no other source of client_encoding, use server encoding */ /* If we have no other source of client_encoding, use server encoding */
SetConfigOption("client_encoding", GetDatabaseEncodingName(), SetConfigOption("client_encoding", GetDatabaseEncodingName(),
PGC_BACKEND, PGC_S_DEFAULT); PGC_BACKEND, PGC_S_DEFAULT);
/* assign locale variables */
collate = NameStr(dbform->datcollate);
ctype = NameStr(dbform->datctype);
if (setlocale(LC_COLLATE, 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().", collate),
errhint("Recreate the database with another locale or install the missing locale.")));
if (setlocale(LC_CTYPE, ctype) == NULL)
ereport(FATAL,
(errmsg("database locale is incompatible with operating system"),
errdetail("The database was initialized with LC_CTYPE \"%s\", "
" which is not recognized by setlocale().", ctype),
errhint("Recreate the database with another locale or install the missing locale.")));
/* Make the locale settings visible as GUC variables, too */
SetConfigOption("lc_collate", collate, PGC_INTERNAL, PGC_S_OVERRIDE);
SetConfigOption("lc_ctype", ctype, PGC_INTERNAL, PGC_S_OVERRIDE);
/* /*
* Lastly, set up any database-specific configuration variables. * Lastly, set up any database-specific configuration variables.
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* Portions taken from FreeBSD. * Portions taken from FreeBSD.
* *
* $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.159 2008/08/05 12:09:30 mha Exp $ * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.160 2008/09/23 09:20:37 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1353,6 +1353,10 @@ bootstrap_template1(char *short_version) ...@@ -1353,6 +1353,10 @@ bootstrap_template1(char *short_version)
bki_lines = replace_token(bki_lines, "ENCODING", encodingid); 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. * Pass correct LC_xxx environment to bootstrap.
* *
...@@ -2179,6 +2183,8 @@ locale_date_order(const char *locale) ...@@ -2179,6 +2183,8 @@ locale_date_order(const char *locale)
/* /*
* check if given string is a valid locale specifier * check if given string is a valid locale specifier
*
* this should match the backend check_locale() function
*/ */
static bool static bool
chklocale(const char *locale) chklocale(const char *locale)
...@@ -2378,12 +2384,12 @@ usage(const char *progname) ...@@ -2378,12 +2384,12 @@ usage(const char *progname)
printf(_("\nOptions:\n")); printf(_("\nOptions:\n"));
printf(_(" [-D, --pgdata=]DATADIR location for this database cluster\n")); printf(_(" [-D, --pgdata=]DATADIR location for this database cluster\n"));
printf(_(" -E, --encoding=ENCODING set default encoding for new databases\n")); printf(_(" -E, --encoding=ENCODING set default encoding for new databases\n"));
printf(_(" --locale=LOCALE initialize database cluster with given locale\n")); printf(_(" --locale=LOCALE set default locale for new databases\n"));
printf(_(" --lc-collate, --lc-ctype, --lc-messages=LOCALE\n" printf(_(" --lc-collate, --lc-ctype, --lc-messages=LOCALE\n"
" --lc-monetary, --lc-numeric, --lc-time=LOCALE\n" " --lc-monetary, --lc-numeric, --lc-time=LOCALE\n"
" initialize database cluster with given locale\n" " set default locale in the respective\n"
" in the respective category (default taken from\n" " category for new databases (default\n"
" environment)\n")); " taken from environment)\n"));
printf(_(" --no-locale equivalent to --locale=C\n")); printf(_(" --no-locale equivalent to --locale=C\n"));
printf(_(" -T, --text-search-config=CFG\n" printf(_(" -T, --text-search-config=CFG\n"
" default text search configuration\n")); " default text search configuration\n"));
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* copyright (c) Oliver Elphick <olly@lfix.co.uk>, 2001; * copyright (c) Oliver Elphick <olly@lfix.co.uk>, 2001;
* licence: BSD * licence: BSD
* *
* $PostgreSQL: pgsql/src/bin/pg_controldata/pg_controldata.c,v 1.39 2008/04/21 00:26:46 tgl Exp $ * $PostgreSQL: pgsql/src/bin/pg_controldata/pg_controldata.c,v 1.40 2008/09/23 09:20:37 heikki Exp $
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
...@@ -220,12 +220,5 @@ main(int argc, char *argv[]) ...@@ -220,12 +220,5 @@ main(int argc, char *argv[])
(ControlFile.float4ByVal ? _("by value") : _("by reference"))); (ControlFile.float4ByVal ? _("by value") : _("by reference")));
printf(_("Float8 argument passing: %s\n"), printf(_("Float8 argument passing: %s\n"),
(ControlFile.float8ByVal ? _("by value") : _("by reference"))); (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; return 0;
} }
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* by PostgreSQL * by PostgreSQL
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.500 2008/09/08 15:26:23 tgl Exp $ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.501 2008/09/23 09:20:37 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1542,12 +1542,16 @@ dumpDatabase(Archive *AH) ...@@ -1542,12 +1542,16 @@ dumpDatabase(Archive *AH)
i_oid, i_oid,
i_dba, i_dba,
i_encoding, i_encoding,
i_collate,
i_ctype,
i_tablespace; i_tablespace;
CatalogId dbCatId; CatalogId dbCatId;
DumpId dbDumpId; DumpId dbDumpId;
const char *datname, const char *datname,
*dba, *dba,
*encoding, *encoding,
*collate,
*ctype,
*tablespace; *tablespace;
datname = PQdb(g_conn); datname = PQdb(g_conn);
...@@ -1559,11 +1563,26 @@ dumpDatabase(Archive *AH) ...@@ -1559,11 +1563,26 @@ dumpDatabase(Archive *AH)
selectSourceSchema("pg_catalog"); selectSourceSchema("pg_catalog");
/* Get the database owner and parameters from pg_database */ /* Get the database owner and parameters from pg_database */
if (g_fout->remoteVersion >= 80200) if (g_fout->remoteVersion >= 80400)
{
appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
"(%s datdba) as dba, "
"pg_encoding_to_char(encoding) as encoding, "
"datcollate, datctype, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) as tablespace, "
"shobj_description(oid, 'pg_database') as description "
"FROM pg_database "
"WHERE datname = ",
username_subquery);
appendStringLiteralAH(dbQry, datname, AH);
}
else if (g_fout->remoteVersion >= 80200)
{ {
appendPQExpBuffer(dbQry, "SELECT tableoid, oid, " appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
"(%s datdba) as dba, " "(%s datdba) as dba, "
"pg_encoding_to_char(encoding) as encoding, " "pg_encoding_to_char(encoding) as encoding, "
"NULL as datcollate, NULL as datctype, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) as tablespace, " "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) as tablespace, "
"shobj_description(oid, 'pg_database') as description " "shobj_description(oid, 'pg_database') as description "
...@@ -1577,6 +1596,7 @@ dumpDatabase(Archive *AH) ...@@ -1577,6 +1596,7 @@ dumpDatabase(Archive *AH)
appendPQExpBuffer(dbQry, "SELECT tableoid, oid, " appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
"(%s datdba) as dba, " "(%s datdba) as dba, "
"pg_encoding_to_char(encoding) as encoding, " "pg_encoding_to_char(encoding) as encoding, "
"NULL as datcollate, NULL as datctype, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) as tablespace " "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) as tablespace "
"FROM pg_database " "FROM pg_database "
"WHERE datname = ", "WHERE datname = ",
...@@ -1588,6 +1608,7 @@ dumpDatabase(Archive *AH) ...@@ -1588,6 +1608,7 @@ dumpDatabase(Archive *AH)
appendPQExpBuffer(dbQry, "SELECT tableoid, oid, " appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
"(%s datdba) as dba, " "(%s datdba) as dba, "
"pg_encoding_to_char(encoding) as encoding, " "pg_encoding_to_char(encoding) as encoding, "
"NULL as datcollate, NULL as datctype, "
"NULL as tablespace " "NULL as tablespace "
"FROM pg_database " "FROM pg_database "
"WHERE datname = ", "WHERE datname = ",
...@@ -1601,6 +1622,7 @@ dumpDatabase(Archive *AH) ...@@ -1601,6 +1622,7 @@ dumpDatabase(Archive *AH)
"oid, " "oid, "
"(%s datdba) as dba, " "(%s datdba) as dba, "
"pg_encoding_to_char(encoding) as encoding, " "pg_encoding_to_char(encoding) as encoding, "
"NULL as datcollate, NULL as datctype, "
"NULL as tablespace " "NULL as tablespace "
"FROM pg_database " "FROM pg_database "
"WHERE datname = ", "WHERE datname = ",
...@@ -1631,12 +1653,16 @@ dumpDatabase(Archive *AH) ...@@ -1631,12 +1653,16 @@ dumpDatabase(Archive *AH)
i_oid = PQfnumber(res, "oid"); i_oid = PQfnumber(res, "oid");
i_dba = PQfnumber(res, "dba"); i_dba = PQfnumber(res, "dba");
i_encoding = PQfnumber(res, "encoding"); i_encoding = PQfnumber(res, "encoding");
i_collate = PQfnumber(res, "collate");
i_ctype = PQfnumber(res, "ctype");
i_tablespace = PQfnumber(res, "tablespace"); i_tablespace = PQfnumber(res, "tablespace");
dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid)); dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid)); dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
dba = PQgetvalue(res, 0, i_dba); dba = PQgetvalue(res, 0, i_dba);
encoding = PQgetvalue(res, 0, i_encoding); encoding = PQgetvalue(res, 0, i_encoding);
collate = PQgetvalue(res, 0, i_collate);
ctype = PQgetvalue(res, 0, i_ctype);
tablespace = PQgetvalue(res, 0, i_tablespace); tablespace = PQgetvalue(res, 0, i_tablespace);
appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0", appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
...@@ -1646,6 +1672,16 @@ dumpDatabase(Archive *AH) ...@@ -1646,6 +1672,16 @@ dumpDatabase(Archive *AH)
appendPQExpBuffer(creaQry, " ENCODING = "); appendPQExpBuffer(creaQry, " ENCODING = ");
appendStringLiteralAH(creaQry, encoding, AH); appendStringLiteralAH(creaQry, encoding, AH);
} }
if (strlen(collate) > 0)
{
appendPQExpBuffer(creaQry, " COLLATE = ");
appendStringLiteralAH(creaQry, collate, AH);
}
if (strlen(ctype) > 0)
{
appendPQExpBuffer(creaQry, " CTYPE = ");
appendStringLiteralAH(creaQry, ctype, AH);
}
if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0) if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
appendPQExpBuffer(creaQry, " TABLESPACE = %s", appendPQExpBuffer(creaQry, " TABLESPACE = %s",
fmtId(tablespace)); fmtId(tablespace));
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* *
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.106 2008/08/29 17:28:43 alvherre Exp $ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.107 2008/09/23 09:20:38 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -925,11 +925,22 @@ dumpCreateDB(PGconn *conn) ...@@ -925,11 +925,22 @@ dumpCreateDB(PGconn *conn)
fprintf(OPF, "--\n-- Database creation\n--\n\n"); fprintf(OPF, "--\n-- Database creation\n--\n\n");
if (server_version >= 80100) if (server_version >= 80400)
res = executeQuery(conn, res = executeQuery(conn,
"SELECT datname, " "SELECT datname, "
"coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), " "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
"pg_encoding_to_char(d.encoding), " "pg_encoding_to_char(d.encoding), "
"datcollate, datctype, "
"datistemplate, datacl, datconnlimit, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
"FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
"WHERE datallowconn ORDER BY 1");
else if (server_version >= 80100)
res = executeQuery(conn,
"SELECT datname, "
"coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
"pg_encoding_to_char(d.encoding), "
"null::text AS datcollate, null::text AS datctype, "
"datistemplate, datacl, datconnlimit, " "datistemplate, datacl, datconnlimit, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace " "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
"FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) " "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
...@@ -939,6 +950,7 @@ dumpCreateDB(PGconn *conn) ...@@ -939,6 +950,7 @@ dumpCreateDB(PGconn *conn)
"SELECT datname, " "SELECT datname, "
"coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
"pg_encoding_to_char(d.encoding), " "pg_encoding_to_char(d.encoding), "
"null::text AS datcollate, null::text AS datctype, "
"datistemplate, datacl, -1 as datconnlimit, " "datistemplate, datacl, -1 as datconnlimit, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace " "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
"FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) " "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
...@@ -948,6 +960,7 @@ dumpCreateDB(PGconn *conn) ...@@ -948,6 +960,7 @@ dumpCreateDB(PGconn *conn)
"SELECT datname, " "SELECT datname, "
"coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
"pg_encoding_to_char(d.encoding), " "pg_encoding_to_char(d.encoding), "
"null::text AS datcollate, null::text AS datctype, "
"datistemplate, datacl, -1 as datconnlimit, " "datistemplate, datacl, -1 as datconnlimit, "
"'pg_default' AS dattablespace " "'pg_default' AS dattablespace "
"FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) " "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
...@@ -959,6 +972,7 @@ dumpCreateDB(PGconn *conn) ...@@ -959,6 +972,7 @@ dumpCreateDB(PGconn *conn)
"(select usename from pg_shadow where usesysid=datdba), " "(select usename from pg_shadow where usesysid=datdba), "
"(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " "(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
"pg_encoding_to_char(d.encoding), " "pg_encoding_to_char(d.encoding), "
"null::text AS datcollate, null::text AS datctype, "
"datistemplate, '' as datacl, -1 as datconnlimit, " "datistemplate, '' as datacl, -1 as datconnlimit, "
"'pg_default' AS dattablespace " "'pg_default' AS dattablespace "
"FROM pg_database d " "FROM pg_database d "
...@@ -973,6 +987,7 @@ dumpCreateDB(PGconn *conn) ...@@ -973,6 +987,7 @@ dumpCreateDB(PGconn *conn)
"SELECT datname, " "SELECT datname, "
"(select usename from pg_shadow where usesysid=datdba), " "(select usename from pg_shadow where usesysid=datdba), "
"pg_encoding_to_char(d.encoding), " "pg_encoding_to_char(d.encoding), "
"null::text AS datcollate, null::text AS datctype, "
"'f' as datistemplate, " "'f' as datistemplate, "
"'' as datacl, -1 as datconnlimit, " "'' as datacl, -1 as datconnlimit, "
"'pg_default' AS dattablespace " "'pg_default' AS dattablespace "
...@@ -985,10 +1000,12 @@ dumpCreateDB(PGconn *conn) ...@@ -985,10 +1000,12 @@ dumpCreateDB(PGconn *conn)
char *dbname = PQgetvalue(res, i, 0); char *dbname = PQgetvalue(res, i, 0);
char *dbowner = PQgetvalue(res, i, 1); char *dbowner = PQgetvalue(res, i, 1);
char *dbencoding = PQgetvalue(res, i, 2); char *dbencoding = PQgetvalue(res, i, 2);
char *dbistemplate = PQgetvalue(res, i, 3); char *dbcollate = PQgetvalue(res, i, 3);
char *dbacl = PQgetvalue(res, i, 4); char *dbctype = PQgetvalue(res, i, 4);
char *dbconnlimit = PQgetvalue(res, i, 5); char *dbistemplate = PQgetvalue(res, i, 5);
char *dbtablespace = PQgetvalue(res, i, 6); char *dbacl = PQgetvalue(res, i, 6);
char *dbconnlimit = PQgetvalue(res, i, 7);
char *dbtablespace = PQgetvalue(res, i, 8);
char *fdbname; char *fdbname;
fdbname = strdup(fmtId(dbname)); fdbname = strdup(fmtId(dbname));
...@@ -1016,6 +1033,18 @@ dumpCreateDB(PGconn *conn) ...@@ -1016,6 +1033,18 @@ dumpCreateDB(PGconn *conn)
appendPQExpBuffer(buf, " ENCODING = "); appendPQExpBuffer(buf, " ENCODING = ");
appendStringLiteralConn(buf, dbencoding, conn); appendStringLiteralConn(buf, dbencoding, conn);
if (strlen(dbcollate) != 0)
{
appendPQExpBuffer(buf, " COLLATE = ");
appendStringLiteralConn(buf, dbcollate, conn);
}
if (strlen(dbctype) != 0)
{
appendPQExpBuffer(buf, " CTYPE = ");
appendStringLiteralConn(buf, dbctype, conn);
}
/* /*
* Output tablespace if it isn't the default. For default, it * Output tablespace if it isn't the default. For default, it
* uses the default from the template database. If tablespace is * uses the default from the template database. If tablespace is
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v 1.65 2008/04/21 00:26:46 tgl Exp $ * $PostgreSQL: pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v 1.66 2008/09/23 09:20:38 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -493,22 +493,6 @@ GuessControlValues(void) ...@@ -493,22 +493,6 @@ GuessControlValues(void)
#endif #endif
ControlFile.float4ByVal = FLOAT4PASSBYVAL; ControlFile.float4ByVal = FLOAT4PASSBYVAL;
ControlFile.float8ByVal = FLOAT8PASSBYVAL; 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 * XXX eventually, should try to grovel through old XLOG to develop more
...@@ -584,12 +568,6 @@ PrintControlValues(bool guessed) ...@@ -584,12 +568,6 @@ PrintControlValues(bool guessed)
(ControlFile.float4ByVal ? _("by value") : _("by reference"))); (ControlFile.float4ByVal ? _("by value") : _("by reference")));
printf(_("Float8 argument passing: %s\n"), printf(_("Float8 argument passing: %s\n"),
(ControlFile.float8ByVal ? _("by value") : _("by reference"))); (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);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* Copyright (c) 2000-2008, PostgreSQL Global Development Group * Copyright (c) 2000-2008, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.184 2008/07/18 04:20:24 tgl Exp $ * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.185 2008/09/23 09:20:38 heikki Exp $
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
...@@ -454,11 +454,18 @@ listAllDbs(bool verbose) ...@@ -454,11 +454,18 @@ listAllDbs(bool verbose)
printfPQExpBuffer(&buf, printfPQExpBuffer(&buf,
"SELECT d.datname as \"%s\",\n" "SELECT d.datname as \"%s\",\n"
" pg_catalog.pg_get_userbyid(d.datdba) as \"%s\",\n" " pg_catalog.pg_get_userbyid(d.datdba) as \"%s\",\n"
" pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\",\n" " pg_catalog.pg_encoding_to_char(d.encoding) as \"%s\",\n",
" d.datacl as \"%s\"",
gettext_noop("Name"), gettext_noop("Name"),
gettext_noop("Owner"), gettext_noop("Owner"),
gettext_noop("Encoding"), gettext_noop("Encoding"));
if (pset.sversion >= 80400)
appendPQExpBuffer(&buf,
" d.datcollate as \"%s\",\n"
" d.datctype as \"%s\",\n",
gettext_noop("Collation"),
gettext_noop("Ctype"));
appendPQExpBuffer(&buf,
" d.datacl as \"%s\"",
gettext_noop("Access Privileges")); gettext_noop("Access Privileges"));
if (verbose && pset.sversion >= 80200) if (verbose && pset.sversion >= 80200)
appendPQExpBuffer(&buf, appendPQExpBuffer(&buf,
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/bin/scripts/createdb.c,v 1.26 2008/01/01 19:45:56 momjian Exp $ * $PostgreSQL: pgsql/src/bin/scripts/createdb.c,v 1.27 2008/09/23 09:20:38 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -32,6 +32,8 @@ main(int argc, char *argv[]) ...@@ -32,6 +32,8 @@ main(int argc, char *argv[])
{"tablespace", required_argument, NULL, 'D'}, {"tablespace", required_argument, NULL, 'D'},
{"template", required_argument, NULL, 'T'}, {"template", required_argument, NULL, 'T'},
{"encoding", required_argument, NULL, 'E'}, {"encoding", required_argument, NULL, 'E'},
{"lc-collate", required_argument, NULL, 1},
{"lc-ctype", required_argument, NULL, 2},
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
}; };
...@@ -50,6 +52,8 @@ main(int argc, char *argv[]) ...@@ -50,6 +52,8 @@ main(int argc, char *argv[])
char *tablespace = NULL; char *tablespace = NULL;
char *template = NULL; char *template = NULL;
char *encoding = NULL; char *encoding = NULL;
char *lc_collate = NULL;
char *lc_ctype = NULL;
PQExpBufferData sql; PQExpBufferData sql;
...@@ -95,6 +99,12 @@ main(int argc, char *argv[]) ...@@ -95,6 +99,12 @@ main(int argc, char *argv[])
case 'E': case 'E':
encoding = optarg; encoding = optarg;
break; break;
case 1:
lc_collate = optarg;
break;
case 2:
lc_ctype = optarg;
break;
default: default:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(1); exit(1);
...@@ -152,6 +162,11 @@ main(int argc, char *argv[]) ...@@ -152,6 +162,11 @@ main(int argc, char *argv[])
appendPQExpBuffer(&sql, " ENCODING '%s'", encoding); appendPQExpBuffer(&sql, " ENCODING '%s'", encoding);
if (template) if (template)
appendPQExpBuffer(&sql, " TEMPLATE %s", fmtId(template)); appendPQExpBuffer(&sql, " TEMPLATE %s", fmtId(template));
if (lc_collate)
appendPQExpBuffer(&sql, " COLLATE '%s'", lc_collate);
if (lc_ctype)
appendPQExpBuffer(&sql, " CTYPE '%s'", lc_ctype);
appendPQExpBuffer(&sql, ";\n"); appendPQExpBuffer(&sql, ";\n");
conn = connectDatabase(strcmp(dbname, "postgres") == 0 ? "template1" : "postgres", conn = connectDatabase(strcmp(dbname, "postgres") == 0 ? "template1" : "postgres",
...@@ -209,6 +224,8 @@ help(const char *progname) ...@@ -209,6 +224,8 @@ help(const char *progname)
printf(_("\nOptions:\n")); printf(_("\nOptions:\n"));
printf(_(" -D, --tablespace=TABLESPACE default tablespace for the database\n")); printf(_(" -D, --tablespace=TABLESPACE default tablespace for the database\n"));
printf(_(" -E, --encoding=ENCODING encoding for the database\n")); printf(_(" -E, --encoding=ENCODING encoding for the database\n"));
printf(_(" --lc-collate=LOCALE LC_COLLATE setting for the database\n"));
printf(_(" --lc-ctype=LOCALE LC_CTYPE setting for the database\n"));
printf(_(" -O, --owner=OWNER database user to own the new database\n")); printf(_(" -O, --owner=OWNER database user to own the new database\n"));
printf(_(" -T, --template=TEMPLATE template database to copy\n")); printf(_(" -T, --template=TEMPLATE template database to copy\n"));
printf(_(" -e, --echo show the commands being sent to the server\n")); printf(_(" -e, --echo show the commands being sent to the server\n"));
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.487 2008/09/19 19:03:40 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.488 2008/09/23 09:20:38 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200809191 #define CATALOG_VERSION_NO 200809231
#endif #endif
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_control.h,v 1.41 2008/04/21 00:26:47 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_control.h,v 1.42 2008/09/23 09:20:39 heikki Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
/* Version identifier for this pg_control format */ /* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 842 #define PG_CONTROL_VERSION 843
/* /*
* Body of CheckPoint XLOG records. This is declared here because we keep * Body of CheckPoint XLOG records. This is declared here because we keep
...@@ -59,15 +59,12 @@ typedef enum DBState ...@@ -59,15 +59,12 @@ typedef enum DBState
DB_IN_PRODUCTION DB_IN_PRODUCTION
} DBState; } DBState;
#define LOCALE_NAME_BUFLEN 128
/* /*
* Contents of pg_control. * Contents of pg_control.
* *
* NOTE: try to keep this under 512 bytes so that it will fit on one physical * NOTE: try to keep this under 512 bytes so that it will fit on one physical
* sector of typical disk drives. This reduces the odds of corruption due to * sector of typical disk drives. This reduces the odds of corruption due to
* power failure midway through a write. Currently it fits comfortably, * power failure midway through a write.
* but we could probably reduce LOCALE_NAME_BUFLEN if things get tight.
*/ */
typedef struct ControlFileData typedef struct ControlFileData
...@@ -144,11 +141,6 @@ typedef struct ControlFileData ...@@ -144,11 +141,6 @@ typedef struct ControlFileData
bool float4ByVal; /* float4 pass-by-value? */ bool float4ByVal; /* float4 pass-by-value? */
bool float8ByVal; /* float8, int8, etc 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! */ /* CRC of all above ... MUST BE LAST! */
pg_crc32 crc; pg_crc32 crc;
} ControlFileData; } ControlFileData;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_database.h,v 1.47 2008/03/27 03:57:34 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_database.h,v 1.48 2008/09/23 09:20:39 heikki Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -33,6 +33,8 @@ CATALOG(pg_database,1262) BKI_SHARED_RELATION ...@@ -33,6 +33,8 @@ CATALOG(pg_database,1262) BKI_SHARED_RELATION
NameData datname; /* database name */ NameData datname; /* database name */
Oid datdba; /* owner of database */ Oid datdba; /* owner of database */
int4 encoding; /* character encoding */ int4 encoding; /* character encoding */
NameData datcollate; /* LC_COLLATE setting */
NameData datctype; /* LC_CTYPE setting */
bool datistemplate; /* allowed as CREATE DATABASE template? */ bool datistemplate; /* allowed as CREATE DATABASE template? */
bool datallowconn; /* new connections allowed? */ bool datallowconn; /* new connections allowed? */
int4 datconnlimit; /* max connections allowed (-1=no limit) */ int4 datconnlimit; /* max connections allowed (-1=no limit) */
...@@ -54,20 +56,22 @@ typedef FormData_pg_database *Form_pg_database; ...@@ -54,20 +56,22 @@ typedef FormData_pg_database *Form_pg_database;
* compiler constants for pg_database * compiler constants for pg_database
* ---------------- * ----------------
*/ */
#define Natts_pg_database 11 #define Natts_pg_database 13
#define Anum_pg_database_datname 1 #define Anum_pg_database_datname 1
#define Anum_pg_database_datdba 2 #define Anum_pg_database_datdba 2
#define Anum_pg_database_encoding 3 #define Anum_pg_database_encoding 3
#define Anum_pg_database_datistemplate 4 #define Anum_pg_database_datcollate 4
#define Anum_pg_database_datallowconn 5 #define Anum_pg_database_datctype 5
#define Anum_pg_database_datconnlimit 6 #define Anum_pg_database_datistemplate 6
#define Anum_pg_database_datlastsysoid 7 #define Anum_pg_database_datallowconn 7
#define Anum_pg_database_datfrozenxid 8 #define Anum_pg_database_datconnlimit 8
#define Anum_pg_database_dattablespace 9 #define Anum_pg_database_datlastsysoid 9
#define Anum_pg_database_datconfig 10 #define Anum_pg_database_datfrozenxid 10
#define Anum_pg_database_datacl 11 #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 t t -1 0 0 1663 _null_ _null_ )); DATA(insert OID = 1 ( template1 PGUID ENCODING "LC_COLLATE" "LC_CTYPE" t t -1 0 0 1663 _null_ _null_));
SHDESCR("default template database"); SHDESCR("default template database");
#define TemplateDbOid 1 #define TemplateDbOid 1
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* *
* PostgreSQL locale utilities * PostgreSQL locale utilities
* *
* $PostgreSQL: pgsql/src/include/utils/pg_locale.h,v 1.25 2008/05/19 18:08:16 tgl Exp $ * $PostgreSQL: pgsql/src/include/utils/pg_locale.h,v 1.26 2008/09/23 09:20:39 heikki Exp $
* *
* Copyright (c) 2002-2008, PostgreSQL Global Development Group * Copyright (c) 2002-2008, PostgreSQL Global Development Group
* *
...@@ -39,6 +39,7 @@ extern const char *locale_numeric_assign(const char *value, ...@@ -39,6 +39,7 @@ extern const char *locale_numeric_assign(const char *value,
extern const char *locale_time_assign(const char *value, extern const char *locale_time_assign(const char *value,
bool doit, GucSource source); bool doit, GucSource source);
extern bool check_locale(int category, const char *locale);
extern char *pg_perm_setlocale(int category, const char *locale); extern char *pg_perm_setlocale(int category, const char *locale);
extern bool lc_collate_is_c(void); extern bool lc_collate_is_c(void);
......
/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.371 2008/08/20 14:09:16 meskes Exp $ */ /* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.372 2008/09/23 09:20:39 heikki Exp $ */
/* Copyright comment */ /* Copyright comment */
%{ %{
...@@ -428,7 +428,7 @@ add_typedef(char *name, char * dimension, char * length, enum ECPGttype type_enu ...@@ -428,7 +428,7 @@ add_typedef(char *name, char * dimension, char * length, enum ECPGttype type_enu
CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS
CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CREATEDB CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CREATEDB
CREATEROLE CREATEUSER CROSS CSV CURRENT_P CURRENT_DATE CURRENT_ROLE CREATEROLE CREATEUSER CROSS CSV CTYPE CURRENT_P CURRENT_DATE CURRENT_ROLE
CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment