Commit f0811a74 authored by Tom Lane's avatar Tom Lane

Merge the last few variable.c configuration variables into the generic

GUC support.  It's now possible to set datestyle, timezone, and
client_encoding from postgresql.conf and per-database or per-user
settings.  Also, implement rollback of SET commands that occur in a
transaction that later fails.  Create a SET LOCAL var = value syntax
that sets the variable only for the duration of the current transaction.
All per previous discussions in pghackers.
parent fa613fa1
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_database.sgml,v 1.2 2002/04/23 02:07:15 tgl Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_database.sgml,v 1.3 2002/05/17 01:19:16 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -28,10 +28,9 @@ ALTER DATABASE <replaceable class="PARAMETER">name</replaceable> RESET <replacea ...@@ -28,10 +28,9 @@ ALTER DATABASE <replaceable class="PARAMETER">name</replaceable> RESET <replacea
<command>ALTER DATABASE</command> is used to change the session <command>ALTER DATABASE</command> is used to change the session
default of a run-time configuration variable for a default of a run-time configuration variable for a
<productname>PostgreSQL</productname> database. Whenever a new <productname>PostgreSQL</productname> database. Whenever a new
session is subsequently started in that database, <literal>SET session is subsequently started in that database, the specified
<replaceable>variable</replaceable> TO value becomes the session default value.
<replaceable>value</replaceable></literal> is effectively executed The database-specific default
before the start of the session. The database-specific default
overrides whatever setting is present in <filename>postgresql.conf</> overrides whatever setting is present in <filename>postgresql.conf</>
or has been received from the postmaster. or has been received from the postmaster.
</para> </para>
...@@ -64,7 +63,8 @@ ALTER DATABASE <replaceable class="PARAMETER">name</replaceable> RESET <replacea ...@@ -64,7 +63,8 @@ ALTER DATABASE <replaceable class="PARAMETER">name</replaceable> RESET <replacea
configuration variable to the given value. If configuration variable to the given value. If
<replaceable>value</replaceable> is <literal>DEFAULT</literal> <replaceable>value</replaceable> is <literal>DEFAULT</literal>
or, equivalently, <literal>RESET</literal> is used, the or, equivalently, <literal>RESET</literal> is used, the
database-specific variable setting is removed and the default database-specific variable setting is removed and the system-wide
default
setting will be inherited in new sessions. Use <literal>RESET setting will be inherited in new sessions. Use <literal>RESET
ALL</literal> to clear all settings. ALL</literal> to clear all settings.
</para> </para>
......
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_user.sgml,v 1.21 2002/03/22 19:20:36 petere Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_user.sgml,v 1.22 2002/05/17 01:19:16 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -48,14 +48,13 @@ ALTER USER <replaceable class="PARAMETER">username</replaceable> RESET <replacea ...@@ -48,14 +48,13 @@ ALTER USER <replaceable class="PARAMETER">username</replaceable> RESET <replacea
</para> </para>
<para> <para>
The second and the third variant change a user's session default of The second and the third variant change a user's session default for
a specified configuration variable. Whenever the user subsequently a specified configuration variable. Whenever the user subsequently
starts a new session, <literal>SET starts a new session, the specified value becomes the session default,
<replaceable>variable</replaceable> TO overriding whatever setting is present in <filename>postgresql.conf</>
<replaceable>value</replaceable></literal> is effectively executed or has been received from the postmaster.
before the start of the session. Ordinary users can change their Ordinary users can change their own session defaults.
own session defaults. Superusers can change anyone's session Superusers can change anyone's session defaults.
defaults.
</para> </para>
<refsect2> <refsect2>
...@@ -135,12 +134,12 @@ ALTER USER <replaceable class="PARAMETER">username</replaceable> RESET <replacea ...@@ -135,12 +134,12 @@ ALTER USER <replaceable class="PARAMETER">username</replaceable> RESET <replacea
<term><replaceable>value</replaceable></term> <term><replaceable>value</replaceable></term>
<listitem> <listitem>
<para> <para>
Set this user's session default of the specified configuration Set this user's session default for the specified configuration
variable to the given value. If variable to the given value. If
<replaceable>value</replaceable> is <literal>DEFAULT</literal> <replaceable>value</replaceable> is <literal>DEFAULT</literal>
or, equivalently, <literal>RESET</literal> is used, the or, equivalently, <literal>RESET</literal> is used, the
user-specific variable setting is removed and the user will user-specific variable setting is removed and the user will
inherit the default setting in new sessions. Use inherit the system-wide default setting in new sessions. Use
<literal>RESET ALL</literal> to clear all settings. <literal>RESET ALL</literal> to clear all settings.
</para> </para>
......
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/reset.sgml,v 1.13 2001/12/08 03:24:39 thomas Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/reset.sgml,v 1.14 2002/05/17 01:19:16 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -37,7 +37,7 @@ RESET ALL ...@@ -37,7 +37,7 @@ RESET ALL
<term>ALL</term> <term>ALL</term>
<listitem> <listitem>
<para> <para>
Resets all run-time parameters to default values. Resets all settable run-time parameters to default values.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -53,11 +53,18 @@ RESET ALL ...@@ -53,11 +53,18 @@ RESET ALL
<command>RESET</command> restores run-time parameters to their <command>RESET</command> restores run-time parameters to their
default values. Refer to default values. Refer to
<xref linkend="sql-set" endterm="sql-set-title"> <xref linkend="sql-set" endterm="sql-set-title">
for details. <command>RESET</command> is an alternate form for for details. <command>RESET</command> is an alternate spelling for
<synopsis> <synopsis>
SET <replaceable class="parameter">variable</replaceable> TO DEFAULT SET <replaceable class="parameter">variable</replaceable> TO DEFAULT
</synopsis> </synopsis>
The default value is defined as the value that the variable would
have had, had no <command>SET</> ever been issued for it in the
current session. The actual source of this value might be a
compiled-in default, the postmaster's configuration file or command-line
switches, or per-database or per-user default settings. See the
<citetitle>Administrator's Guide</citetitle> for details.
</para> </para>
</refsect1> </refsect1>
......
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/set.sgml,v 1.59 2002/04/21 19:02:39 thomas Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/set.sgml,v 1.60 2002/05/17 01:19:16 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -14,14 +14,40 @@ PostgreSQL documentation ...@@ -14,14 +14,40 @@ PostgreSQL documentation
</refnamediv> </refnamediv>
<refsynopsisdiv> <refsynopsisdiv>
<synopsis> <synopsis>
SET <replaceable class="PARAMETER">variable</replaceable> { TO | = } { <replaceable class="PARAMETER">value</replaceable> | '<replaceable class="PARAMETER">value</replaceable>' | DEFAULT } SET [ SESSION | LOCAL ] <replaceable class="PARAMETER">variable</replaceable> { TO | = } { <replaceable class="PARAMETER">value</replaceable> | '<replaceable class="PARAMETER">value</replaceable>' | DEFAULT }
SET TIME ZONE { '<replaceable class="PARAMETER">timezone</replaceable>' | LOCAL | DEFAULT } SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</replaceable> | LOCAL | DEFAULT }
</synopsis> </synopsis>
<refsect2 id="R2-SQL-SET-1"> <refsect2 id="R2-SQL-SET-1">
<title>Inputs</title> <title>Inputs</title>
<para> <para>
<variablelist> <variablelist>
<varlistentry>
<term><option>SESSION</></term>
<listitem>
<para>
Specifies that the command takes effect for the current session.
(This is the default if neither <option>SESSION</> nor
<option>LOCAL</> appears.)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>LOCAL</></term>
<listitem>
<para>
Specifies that the command takes effect for only the current
transaction. After <command>COMMIT</> or <command>ROLLBACK</>,
the session-level setting takes effect again. Note that
<command>SET LOCAL</> will appear to have no effect if it's
executed outside a <command>BEGIN</> block, since the transaction
will end immediately.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><replaceable class="PARAMETER">variable</replaceable></term> <term><replaceable class="PARAMETER">variable</replaceable></term>
<listitem> <listitem>
...@@ -30,6 +56,7 @@ SET TIME ZONE { '<replaceable class="PARAMETER">timezone</replaceable>' | LOCAL ...@@ -30,6 +56,7 @@ SET TIME ZONE { '<replaceable class="PARAMETER">timezone</replaceable>' | LOCAL
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><replaceable class="PARAMETER">value</replaceable></term> <term><replaceable class="PARAMETER">value</replaceable></term>
<listitem> <listitem>
...@@ -49,34 +76,49 @@ SET TIME ZONE { '<replaceable class="PARAMETER">timezone</replaceable>' | LOCAL ...@@ -49,34 +76,49 @@ SET TIME ZONE { '<replaceable class="PARAMETER">timezone</replaceable>' | LOCAL
<refsect1 id="R1-SQL-SET-1"> <refsect1 id="R1-SQL-SET-1">
<title>Description</title> <title>Description</title>
<para> <para>
The <command>SET</command> command changes run-time configuration The <command>SET</command> command changes run-time configuration
parameters. The following parameters can be altered: parameters. Many of the run-time parameters listed in the
<citetitle>Administrator's Guide</citetitle> can be changed on-the-fly
with <command>SET</command>. (But some require superuser privileges
to change, and others cannot be changed after server or session start.)
Note that <command>SET</command> only affects the value used by the
current session.
</para>
<variablelist> <para>
<varlistentry> If <command>SET</command> or <command>SET SESSION</command> is issued
<term>CLIENT_ENCODING</term> within a transaction that is later aborted, the effects of the
<term>NAMES</term> <command>SET</command> command disappear when the transaction is rolled
<listitem> back. (This behavior represents a change from
<para> <productname>PostgreSQL</productname> versions prior to 7.3, where
Sets the multibyte client encoding. The specified encoding the effects of <command>SET</command> would not roll back after a later
must be supported by the backend. error.) Once the surrounding transaction is committed, the effects
</para> will persist until the end of the session, unless overridden by another
<command>SET</command>.
</para>
<para> <para>
This option is only available if The effects of <command>SET LOCAL</command> last only till the end of
<productname>PostgreSQL</productname> is build with multibyte the current transaction, whether committed or not. A special case is
support. <command>SET</command> followed by <command>SET LOCAL</command> within
</para> a single transaction: the <command>SET LOCAL</command> value will be
</listitem> seen until the end of the transaction, but afterwards (if the transaction
</varlistentry> is committed) the <command>SET</command> value will take effect.
</para>
<para>
Here are additional details about a few of the parameters that can be set:
<variablelist>
<varlistentry> <varlistentry>
<term>DATESTYLE</term> <term>DATESTYLE</term>
<listitem> <listitem>
<para> <para>
Choose the date/time representation style. Two separate Choose the date/time representation style. Two separate
settings are made: the default date/time output and the settings are involved: the default date/time output and the
interpretation of ambiguous input. interpretation of ambiguous input.
</para> </para>
...@@ -159,28 +201,47 @@ SET TIME ZONE { '<replaceable class="PARAMETER">timezone</replaceable>' | LOCAL ...@@ -159,28 +201,47 @@ SET TIME ZONE { '<replaceable class="PARAMETER">timezone</replaceable>' | LOCAL
</para> </para>
<para> <para>
Date format initialization may be done by: <command>SET DATESTYLE</command> affects interpretation of
input and provides several standard output formats. For
applications needing different variations or tighter control
over input or output, consider using
the <function>to_char</function> family of
functions.
</para>
<para>
There are several now-deprecated means for setting the datestyle
in addition to the normal methods of setting it via <command>SET</> or
a configuration-file entry:
<simplelist> <simplelist>
<member> <member>
Setting the <envar>PGDATESTYLE</envar> environment variable. Setting the postmaster's <envar>PGDATESTYLE</envar> environment
If PGDATESTYLE is set in the frontend environment of a client variable. (This will be overridden by any of the other methods.)
based on libpq, libpq will automatically set DATESTYLE to the
value of PGDATESTYLE during connection start-up.
</member> </member>
<member> <member>
Running postmaster using the option <option>-o -e</option> to Running postmaster using the option <option>-o -e</option> to
set dates to the <literal>European</literal> convention. select the <literal>European</literal> conventions.
(This overrides environment variables and configuration-file
entries.)
</member>
<member>
Setting the client's <envar>PGDATESTYLE</envar> environment variable.
If PGDATESTYLE is set in the frontend environment of a client
based on libpq, libpq will automatically set DATESTYLE to the
value of PGDATESTYLE during connection start-up. This is
equivalent to a manually issued <command>SET</>.
</member> </member>
</simplelist> </simplelist>
</para> </para>
</listitem>
</varlistentry>
<varlistentry>
<term>NAMES</term>
<listitem>
<para> <para>
<command>SET DATESTYLE</command> affects interpretation of <command>SET NAMES</> is an alias for <command>SET CLIENT_ENCODING</>.
input and provides several standard output formats. For
applications needing different variations or tighter control
over input or output, consider using
the <function>to_char</function> family of
functions.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -199,23 +260,22 @@ SET TIME ZONE { '<replaceable class="PARAMETER">timezone</replaceable>' | LOCAL ...@@ -199,23 +260,22 @@ SET TIME ZONE { '<replaceable class="PARAMETER">timezone</replaceable>' | LOCAL
The value for the seed to be used by the The value for the seed to be used by the
<function>random</function> function. Allowed <function>random</function> function. Allowed
values are floating-point numbers between 0 and 1, which values are floating-point numbers between 0 and 1, which
are then multiplied by 2<superscript>31</>-1. This product will are then multiplied by 2<superscript>31</>-1.
silently overflow if a number outside the range is used.
</para>
<para>
The seed can also be set by invoking the
<function>setseed</function> SQL function:
<programlisting>
SELECT setseed(<replaceable>value</replaceable>);
</programlisting>
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>
</para> </para>
<para>
The seed can also be set by invoking the
<function>setseed</function> SQL function:
<programlisting>
SELECT setseed(<replaceable>value</replaceable>);
</programlisting>
</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -223,13 +283,9 @@ SELECT setseed(<replaceable>value</replaceable>); ...@@ -223,13 +283,9 @@ SELECT setseed(<replaceable>value</replaceable>);
<term>SERVER_ENCODING</term> <term>SERVER_ENCODING</term>
<listitem> <listitem>
<para> <para>
Sets the multibyte server encoding. Shows the server-side multibyte encoding. (At present, this
</para> parameter can be shown but not set, because the encoding is
determined at initdb time.)
<para>
This option is only available if
<productname>PostgreSQL</productname> was built with multibyte
support.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -241,18 +297,18 @@ SELECT setseed(<replaceable>value</replaceable>); ...@@ -241,18 +297,18 @@ SELECT setseed(<replaceable>value</replaceable>);
<para> <para>
Sets the default time zone for your session. Arguments can be Sets the default time zone for your session. Arguments can be
an SQL time interval constant, an integer or double precision an SQL time interval constant, an integer or double precision
constant, or a string representing a time zone supported by constant, or a string representing a time zone name recognized
the host operating system. by the host operating system.
</para> </para>
<para> <para>
The possible values for time zone depends on your operating The available time zone names depend on your operating
system. For example, on Linux system. For example, on Linux
<filename>/usr/share/zoneinfo</filename> contains the database <filename>/usr/share/zoneinfo</filename> contains the database
of time zones. of time zones.
</para> </para>
<para> <para>
Here are some valid values for time zone: Here are some typical values for time zone names:
<variablelist> <variablelist>
<varlistentry> <varlistentry>
...@@ -279,6 +335,14 @@ SELECT setseed(<replaceable>value</replaceable>); ...@@ -279,6 +335,14 @@ SELECT setseed(<replaceable>value</replaceable>);
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist>
</para>
<para>
In addition to time zone names, <productname>PostgreSQL</productname>
accepts these other methods of specifying a time zone:
<variablelist>
<varlistentry> <varlistentry>
<term>7</term> <term>7</term>
<listitem> <listitem>
...@@ -310,7 +374,7 @@ SELECT setseed(<replaceable>value</replaceable>); ...@@ -310,7 +374,7 @@ SELECT setseed(<replaceable>value</replaceable>);
</variablelist> </variablelist>
</para> </para>
<para> <para>
If an invalid time zone is specified, the time zone If an invalid time zone name is specified, the time zone
becomes GMT (on most systems anyway). becomes GMT (on most systems anyway).
</para> </para>
<para> <para>
...@@ -324,14 +388,9 @@ SELECT setseed(<replaceable>value</replaceable>); ...@@ -324,14 +388,9 @@ SELECT setseed(<replaceable>value</replaceable>);
</variablelist> </variablelist>
</para> </para>
<para>
An extended list of other run-time parameters can be found in the
<citetitle>Administrator's Guide</citetitle>.
</para>
<para> <para>
Use <xref linkend="SQL-SHOW" endterm="SQL-SHOW-title"> to show the Use <xref linkend="SQL-SHOW" endterm="SQL-SHOW-title"> to show the
current setting of a parameters. current setting of a parameter.
</para> </para>
</refsect1> </refsect1>
...@@ -363,7 +422,7 @@ SELECT setseed(<replaceable>value</replaceable>); ...@@ -363,7 +422,7 @@ SELECT setseed(<replaceable>value</replaceable>);
<term><computeroutput>ERROR: permission denied</computeroutput></term> <term><computeroutput>ERROR: permission denied</computeroutput></term>
<listitem> <listitem>
<para> <para>
You must be a superuser to have access to certain settings. You must be a superuser to alter certain settings.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -394,7 +453,7 @@ SET DATESTYLE TO PostgreSQL,European; ...@@ -394,7 +453,7 @@ SET DATESTYLE TO PostgreSQL,European;
<para> <para>
Set the time zone for Berkeley, California, using quotes to Set the time zone for Berkeley, California, using quotes to
preserve the uppercase attributes of the time zone specifier (note preserve the uppercase spelling of the time zone name (note
that the date style is <literal>PostgreSQL</literal> for this that the date style is <literal>PostgreSQL</literal> for this
example): example):
...@@ -437,8 +496,8 @@ SELECT CURRENT_TIMESTAMP AS today; ...@@ -437,8 +496,8 @@ SELECT CURRENT_TIMESTAMP AS today;
only numeric time zone offsets while only numeric time zone offsets while
<productname>PostgreSQL</productname> allows full time zone <productname>PostgreSQL</productname> allows full time zone
specifier strings as well. All other <literal>SET</literal> specifier strings as well. All other <literal>SET</literal>
features are a features are
<productname>PostgreSQL</productname> extension. <productname>PostgreSQL</productname> extensions.
</para> </para>
</refsect2> </refsect2>
</refsect1> </refsect1>
......
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/set_session_auth.sgml,v 1.5 2002/05/06 19:47:30 tgl Exp $ --> <!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/set_session_auth.sgml,v 1.6 2002/05/17 01:19:16 tgl Exp $ -->
<refentry id="SQL-SET-SESSION-AUTHORIZATION"> <refentry id="SQL-SET-SESSION-AUTHORIZATION">
<docinfo> <docinfo>
<date>2001-04-21</date> <date>2001-04-21</date>
...@@ -16,8 +16,8 @@ ...@@ -16,8 +16,8 @@
<refsynopsisdiv> <refsynopsisdiv>
<synopsis> <synopsis>
SET SESSION AUTHORIZATION <parameter>username</parameter> SET [ SESSION | LOCAL ] SESSION AUTHORIZATION <parameter>username</parameter>
SET SESSION AUTHORIZATION DEFAULT SET [ SESSION | LOCAL ] SESSION AUTHORIZATION DEFAULT
RESET SESSION AUTHORIZATION RESET SESSION AUTHORIZATION
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
...@@ -51,6 +51,12 @@ RESET SESSION AUTHORIZATION ...@@ -51,6 +51,12 @@ RESET SESSION AUTHORIZATION
specifies the authenticated username. specifies the authenticated username.
</para> </para>
<para>
The <option>SESSION</> and <option>LOCAL</> modifiers act the same
as for the regular <xref linkend="SQL-SET" endterm="SQL-SET-title">
command.
</para>
<para> <para>
The <literal>DEFAULT</> and <literal>RESET</> forms reset the session The <literal>DEFAULT</> and <literal>RESET</> forms reset the session
and current user identifiers to be the originally authenticated user and current user identifiers to be the originally authenticated user
......
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/show.sgml,v 1.16 2002/03/06 06:48:05 momjian Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/show.sgml,v 1.17 2002/05/17 01:19:16 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -54,7 +54,7 @@ SHOW ALL ...@@ -54,7 +54,7 @@ SHOW ALL
<para> <para>
<command>SHOW</command> will display the current setting of a <command>SHOW</command> will display the current setting of a
run-time parameter. These variables can be set using the run-time parameter. These variables can be set using the
<command>SET</command> statement or are determined at server start. <command>SET</command> statement or are determined at session start.
</para> </para>
</refsect1> </refsect1>
...@@ -72,25 +72,6 @@ SHOW ALL ...@@ -72,25 +72,6 @@ SHOW ALL
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><computeroutput>ERROR: permission denied</computeroutput></term>
<listitem>
<para>
You must be a superuser to be allowed to see certain settings.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><computeroutput>WARNING: Time zone is unknown</computeroutput></term>
<listitem>
<para>
If the <envar>TZ</envar> or <envar>PGTZ</envar> environment
variable is not set.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</para> </para>
</refsect1> </refsect1>
......
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.134 2002/05/03 04:11:07 tgl Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.135 2002/05/17 01:19:16 tgl Exp $
--> -->
<appendix id="release"> <appendix id="release">
...@@ -24,6 +24,9 @@ CDATA means the content is "SGML-free", so you can write without ...@@ -24,6 +24,9 @@ CDATA means the content is "SGML-free", so you can write without
worries about funny characters. worries about funny characters.
--> -->
<literallayout><![CDATA[ <literallayout><![CDATA[
Effects of SET within a transaction block now roll back if transaction aborts
New SET LOCAL syntax sets a parameter for the life of the current transaction
Datestyle, timezone, client_encoding can be set in postgresql.conf
The last vestiges of support for type names datetime and timespan are gone; use timestamp and interval instead The last vestiges of support for type names datetime and timespan are gone; use timestamp and interval instead
Rule names are now per-relation, not global; DROP RULE and COMMENT ON RULE syntax changes accordingly Rule names are now per-relation, not global; DROP RULE and COMMENT ON RULE syntax changes accordingly
Readline and Zlib are now required by default and must be turned off explicitly if their use is not desired Readline and Zlib are now required by default and must be turned off explicitly if their use is not desired
...@@ -36,8 +39,7 @@ Access privileges on functions ...@@ -36,8 +39,7 @@ Access privileges on functions
Access privileges on procedural languages Access privileges on procedural languages
CREATE DATABASE has OWNER option so superuser can create DB for someone else CREATE DATABASE has OWNER option so superuser can create DB for someone else
Kerberos 5 support now works with Heimdal Kerberos 5 support now works with Heimdal
Database and user-specific session defaults of run-time configurations variables Database and user-specific session defaults for run-time configuration variables (ALTER DATABASE ... SET and ALTER USER ... SET)
(ALTER DATABASE ... SET and ALTER USER ... SET)
]]></literallayout> ]]></literallayout>
</sect1> </sect1>
......
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.115 2002/05/09 13:30:24 petere Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.116 2002/05/17 01:19:16 tgl Exp $
--> -->
<Chapter Id="runtime"> <Chapter Id="runtime">
...@@ -488,11 +488,13 @@ psql: could not connect to server: Connection refused ...@@ -488,11 +488,13 @@ psql: could not connect to server: Connection refused
# This is a comment # This is a comment
log_connections = yes log_connections = yes
syslog = 2 syslog = 2
search_path = '$user, public'
</programlisting> </programlisting>
As you see, options are one per line. The equal sign between name As you see, options are one per line. The equal sign between name
and value is optional. Whitespace is insignificant and blank lines and value is optional. Whitespace is insignificant and blank lines
are ignored. Hash marks (<quote>#</quote>) introduce comments are ignored. Hash marks (<quote>#</quote>) introduce comments
anywhere. anywhere. Parameter values that are not simple identifiers or
numbers should be single-quoted.
</para> </para>
<para> <para>
...@@ -526,7 +528,7 @@ postmaster -c log_connections=yes -c syslog=2 ...@@ -526,7 +528,7 @@ postmaster -c log_connections=yes -c syslog=2
<programlisting> <programlisting>
env PGOPTIONS='-c geqo=off' psql env PGOPTIONS='-c geqo=off' psql
</programlisting> </programlisting>
(This works for any client application, not just (This works for any libpq-based client application, not just
<application>psql</application>.) Note that this won't work for <application>psql</application>.) Note that this won't work for
options that are fixed when the server is started, such as the port options that are fixed when the server is started, such as the port
number. number.
...@@ -539,11 +541,17 @@ env PGOPTIONS='-c geqo=off' psql ...@@ -539,11 +541,17 @@ env PGOPTIONS='-c geqo=off' psql
=&gt; <userinput>SET ENABLE_SEQSCAN TO OFF;</userinput> =&gt; <userinput>SET ENABLE_SEQSCAN TO OFF;</userinput>
</screen> </screen>
See the SQL command language reference for details on the syntax. See the SQL command language reference for details on the syntax.
</para>
<para>
Furthermore, it is possible to assign a set of option settings to Furthermore, it is possible to assign a set of option settings to
a user or a database. Whenever a session is started, the default a user or a database. Whenever a session is started, the default
settings for the user and database involved are loaded. The settings for the user and database involved are loaded. The
commands <literal>ALTER DATABASE</literal> and <literal>ALTER commands <literal>ALTER DATABASE</literal> and <literal>ALTER
USER</literal>, respectively, are used to configure these. USER</literal>, respectively, are used to configure these settings.
Such per-database settings override anything received from the postmaster
or the configuration file, and in turn are overridden by per-user
settings.
</para> </para>
<sect2 id="runtime-config-optimizer"> <sect2 id="runtime-config-optimizer">
...@@ -1091,6 +1099,34 @@ env PGOPTIONS='-c geqo=off' psql ...@@ -1091,6 +1099,34 @@ env PGOPTIONS='-c geqo=off' psql
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>CLIENT_ENCODING</varname> (<type>string</type>)</term>
<indexterm><primary>character set encoding</></>
<listitem>
<para>
Sets the client-side encoding for multibyte character sets.
The default is to use the database encoding.
</para>
<para>
This option is only available if
<productname>PostgreSQL</productname> was built with multibyte
support.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>DATESTYLE</varname> (<type>string</type>)</term>
<indexterm><primary>date style</></>
<listitem>
<para>
Sets the display format for dates, as well as the rules for
interpreting ambiguous input dates.
The default is <literal>ISO, US</>.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<indexterm> <indexterm>
<primary>deadlock</primary> <primary>deadlock</primary>
...@@ -1586,6 +1622,18 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir' ...@@ -1586,6 +1622,18 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>TIMEZONE</varname> (<type>string</type>)</term>
<indexterm><primary>time zone</></>
<listitem>
<para>
Sets the time zone for displaying and interpreting timestamps.
The default is to use whatever the system environment
specifies as the timezone.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>TRANSFORM_NULL_EQUALS</varname> (<type>boolean</type>)</term> <term><varname>TRANSFORM_NULL_EQUALS</varname> (<type>boolean</type>)</term>
<indexterm><primary>IS NULL</></> <indexterm><primary>IS NULL</></>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.120 2002/04/01 03:34:25 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.121 2002/05/17 01:19:16 tgl Exp $
* *
* NOTES * NOTES
* Transaction aborts can now occur two ways: * Transaction aborts can now occur two ways:
...@@ -173,6 +173,7 @@ ...@@ -173,6 +173,7 @@
#include "storage/proc.h" #include "storage/proc.h"
#include "storage/sinval.h" #include "storage/sinval.h"
#include "storage/smgr.h" #include "storage/smgr.h"
#include "utils/guc.h"
#include "utils/inval.h" #include "utils/inval.h"
#include "utils/memutils.h" #include "utils/memutils.h"
#include "utils/portal.h" #include "utils/portal.h"
...@@ -1002,6 +1003,7 @@ CommitTransaction(void) ...@@ -1002,6 +1003,7 @@ CommitTransaction(void)
RelationPurgeLocalRelation(true); RelationPurgeLocalRelation(true);
smgrDoPendingDeletes(true); smgrDoPendingDeletes(true);
AtEOXact_GUC(true);
AtEOXact_SPI(); AtEOXact_SPI();
AtEOXact_gist(); AtEOXact_gist();
AtEOXact_hash(); AtEOXact_hash();
...@@ -1104,6 +1106,7 @@ AbortTransaction(void) ...@@ -1104,6 +1106,7 @@ AbortTransaction(void)
RelationPurgeLocalRelation(false); RelationPurgeLocalRelation(false);
smgrDoPendingDeletes(false); smgrDoPendingDeletes(false);
AtEOXact_GUC(false);
AtEOXact_SPI(); AtEOXact_SPI();
AtEOXact_gist(); AtEOXact_gist();
AtEOXact_hash(); AtEOXact_hash();
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.94 2002/05/09 13:30:24 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.95 2002/05/17 01:19:16 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -3272,31 +3272,10 @@ xlog_outrec(char *buf, XLogRecord *record) ...@@ -3272,31 +3272,10 @@ xlog_outrec(char *buf, XLogRecord *record)
/* /*
* GUC support routines * GUC support
*/ */
const char *
bool assign_xlog_sync_method(const char *method, bool doit, bool interactive)
check_xlog_sync_method(const char *method)
{
if (strcasecmp(method, "fsync") == 0)
return true;
#ifdef HAVE_FDATASYNC
if (strcasecmp(method, "fdatasync") == 0)
return true;
#endif
#ifdef OPEN_SYNC_FLAG
if (strcasecmp(method, "open_sync") == 0)
return true;
#endif
#ifdef OPEN_DATASYNC_FLAG
if (strcasecmp(method, "open_datasync") == 0)
return true;
#endif
return false;
}
void
assign_xlog_sync_method(const char *method)
{ {
int new_sync_method; int new_sync_method;
int new_sync_bit; int new_sync_bit;
...@@ -3329,12 +3308,12 @@ assign_xlog_sync_method(const char *method) ...@@ -3329,12 +3308,12 @@ assign_xlog_sync_method(const char *method)
#endif #endif
else else
{ {
/* Can't get here unless guc.c screwed up */ return NULL;
elog(ERROR, "bogus wal_sync_method %s", method);
new_sync_method = 0; /* keep compiler quiet */
new_sync_bit = 0;
} }
if (!doit)
return method;
if (sync_method != new_sync_method || open_sync_bit != new_sync_bit) if (sync_method != new_sync_method || open_sync_bit != new_sync_bit)
{ {
/* /*
...@@ -3359,6 +3338,8 @@ assign_xlog_sync_method(const char *method) ...@@ -3359,6 +3338,8 @@ assign_xlog_sync_method(const char *method)
sync_method = new_sync_method; sync_method = new_sync_method;
open_sync_bit = new_sync_bit; open_sync_bit = new_sync_bit;
} }
return method;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.128 2002/05/05 00:03:28 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.129 2002/05/17 01:19:16 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -249,7 +249,7 @@ BootstrapMain(int argc, char *argv[]) ...@@ -249,7 +249,7 @@ BootstrapMain(int argc, char *argv[])
dbName = NULL; dbName = NULL;
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
ResetAllOptions(true); InitializeGUCOptions();
potential_DataDir = getenv("PGDATA"); /* Null if no PGDATA potential_DataDir = getenv("PGDATA"); /* Null if no PGDATA
* variable */ * variable */
} }
...@@ -263,12 +263,13 @@ BootstrapMain(int argc, char *argv[]) ...@@ -263,12 +263,13 @@ BootstrapMain(int argc, char *argv[])
break; break;
case 'd': case 'd':
{ {
/* Turn on debugging for the postmaster. */ /* Turn on debugging for the bootstrap process. */
char *debugstr = palloc(strlen("debug") + strlen(optarg) + 1); char *debugstr = palloc(strlen("debug") + strlen(optarg) + 1);
sprintf(debugstr, "debug%s", optarg); sprintf(debugstr, "debug%s", optarg);
/* We use PGC_S_SESSION because we will reset in backend */ SetConfigOption("server_min_messages", debugstr,
SetConfigOption("server_min_messages", debugstr, PGC_POSTMASTER, PGC_S_ARGV); PGC_POSTMASTER, PGC_S_ARGV);
SetConfigOption("client_min_messages", debugstr, PGC_POSTMASTER, PGC_S_ARGV); SetConfigOption("client_min_messages", debugstr,
PGC_POSTMASTER, PGC_S_ARGV);
pfree(debugstr); pfree(debugstr);
break; break;
} }
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.19 2002/05/12 20:10:01 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.20 2002/05/17 01:19:16 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1739,16 +1739,16 @@ RemoveTempRelationsCallback(void) ...@@ -1739,16 +1739,16 @@ RemoveTempRelationsCallback(void)
* Routines for handling the GUC variable 'search_path'. * Routines for handling the GUC variable 'search_path'.
*/ */
/* parse_hook: is proposed value valid? */ /* assign_hook: validate new search_path, do extra actions as needed */
bool const char *
check_search_path(const char *proposed) assign_search_path(const char *newval, bool doit, bool interactive)
{ {
char *rawname; char *rawname;
List *namelist; List *namelist;
List *l; List *l;
/* Need a modifiable copy of string */ /* Need a modifiable copy of string */
rawname = pstrdup(proposed); rawname = pstrdup(newval);
/* Parse string into list of identifiers */ /* Parse string into list of identifiers */
if (!SplitIdentifierString(rawname, ',', &namelist)) if (!SplitIdentifierString(rawname, ',', &namelist))
...@@ -1756,59 +1756,45 @@ check_search_path(const char *proposed) ...@@ -1756,59 +1756,45 @@ check_search_path(const char *proposed)
/* syntax error in name list */ /* syntax error in name list */
pfree(rawname); pfree(rawname);
freeList(namelist); freeList(namelist);
return false; return NULL;
} }
/* /*
* If we aren't inside a transaction, we cannot do database access so * If we aren't inside a transaction, we cannot do database access so
* cannot verify the individual names. Must accept the list on faith. * cannot verify the individual names. Must accept the list on faith.
* (This case can happen, for example, when the postmaster reads a
* search_path setting from postgresql.conf.)
*/
if (!IsTransactionState())
{
pfree(rawname);
freeList(namelist);
return true;
}
/*
* Verify that all the names are either valid namespace names or "$user".
* We do not require $user to correspond to a valid namespace.
* We do not check for USAGE rights, either; should we?
*/ */
foreach(l, namelist) if (interactive && IsTransactionState())
{ {
char *curname = (char *) lfirst(l); /*
* Verify that all the names are either valid namespace names or
if (strcmp(curname, "$user") == 0) * "$user". We do not require $user to correspond to a valid
continue; * namespace. We do not check for USAGE rights, either; should we?
if (!SearchSysCacheExists(NAMESPACENAME, */
CStringGetDatum(curname), foreach(l, namelist)
0, 0, 0))
{ {
pfree(rawname); char *curname = (char *) lfirst(l);
freeList(namelist);
return false; if (strcmp(curname, "$user") == 0)
continue;
if (!SearchSysCacheExists(NAMESPACENAME,
CStringGetDatum(curname),
0, 0, 0))
elog(ERROR, "Namespace \"%s\" does not exist", curname);
} }
} }
pfree(rawname); pfree(rawname);
freeList(namelist); freeList(namelist);
return true;
}
/* assign_hook: do extra actions needed when assigning to search_path */
void
assign_search_path(const char *newval)
{
/* /*
* We mark the path as needing recomputation, but don't do anything until * We mark the path as needing recomputation, but don't do anything until
* it's needed. This avoids trying to do database access during GUC * it's needed. This avoids trying to do database access during GUC
* initialization. * initialization.
*/ */
namespaceSearchPathValid = false; if (doit)
namespaceSearchPathValid = false;
return newval;
} }
/* /*
...@@ -1844,6 +1830,8 @@ InitializeSearchPath(void) ...@@ -1844,6 +1830,8 @@ InitializeSearchPath(void)
CacheRegisterSyscacheCallback(NAMESPACEOID, CacheRegisterSyscacheCallback(NAMESPACEOID,
NamespaceCallback, NamespaceCallback,
(Datum) 0); (Datum) 0);
/* Force search path to be recomputed on next use */
namespaceSearchPathValid = false;
} }
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.88 2002/04/27 21:24:34 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.89 2002/05/17 01:19:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -458,9 +458,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt) ...@@ -458,9 +458,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
char repl_null[Natts_pg_database]; char repl_null[Natts_pg_database];
char repl_repl[Natts_pg_database]; char repl_repl[Natts_pg_database];
valuestr = (stmt->value valuestr = flatten_set_variable_args(stmt->variable, stmt->value);
? ((A_Const *) lfirst(stmt->value))->val.val.str
: NULL);
rel = heap_openr(DatabaseRelationName, RowExclusiveLock); rel = heap_openr(DatabaseRelationName, RowExclusiveLock);
ScanKeyEntryInitialize(&scankey, 0, Anum_pg_database_datname, ScanKeyEntryInitialize(&scankey, 0, Anum_pg_database_datname,
...@@ -477,7 +475,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt) ...@@ -477,7 +475,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
MemSet(repl_repl, ' ', sizeof(repl_repl)); MemSet(repl_repl, ' ', sizeof(repl_repl));
repl_repl[Anum_pg_database_datconfig-1] = 'r'; repl_repl[Anum_pg_database_datconfig-1] = 'r';
if (strcmp(stmt->variable, "all")==0 && stmt->value == NULL) if (strcmp(stmt->variable, "all")==0 && valuestr == NULL)
{ {
/* RESET ALL */ /* RESET ALL */
repl_null[Anum_pg_database_datconfig-1] = 'n'; repl_null[Anum_pg_database_datconfig-1] = 'n';
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.100 2002/04/28 00:36:38 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.101 2002/05/17 01:19:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -851,9 +851,7 @@ AlterUserSet(AlterUserSetStmt *stmt) ...@@ -851,9 +851,7 @@ AlterUserSet(AlterUserSetStmt *stmt)
char repl_repl[Natts_pg_shadow]; char repl_repl[Natts_pg_shadow];
int i; int i;
valuestr = (stmt->value valuestr = flatten_set_variable_args(stmt->variable, stmt->value);
? ((A_Const *) lfirst(stmt->value))->val.val.str
: NULL);
/* /*
* RowExclusiveLock is sufficient, because we don't need to update * RowExclusiveLock is sufficient, because we don't need to update
...@@ -874,7 +872,7 @@ AlterUserSet(AlterUserSetStmt *stmt) ...@@ -874,7 +872,7 @@ AlterUserSet(AlterUserSetStmt *stmt)
repl_repl[i] = ' '; repl_repl[i] = ' ';
repl_repl[Anum_pg_shadow_useconfig-1] = 'r'; repl_repl[Anum_pg_shadow_useconfig-1] = 'r';
if (strcmp(stmt->variable, "all")==0 && stmt->value == NULL) if (strcmp(stmt->variable, "all")==0 && valuestr == NULL)
/* RESET ALL */ /* RESET ALL */
repl_null[Anum_pg_shadow_useconfig-1] = 'n'; repl_null[Anum_pg_shadow_useconfig-1] = 'n';
else else
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* variable.c * variable.c
* Routines for handling of 'SET var TO', * Routines for handling specialized SET variables.
* 'SHOW var' and 'RESET var' statements. *
* *
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.66 2002/05/06 19:47:30 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.67 2002/05/17 01:19:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -21,15 +21,11 @@ ...@@ -21,15 +21,11 @@
#include "access/xact.h" #include "access/xact.h"
#include "catalog/pg_shadow.h" #include "catalog/pg_shadow.h"
#include "catalog/pg_type.h"
#include "commands/variable.h" #include "commands/variable.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "optimizer/cost.h"
#include "optimizer/paths.h"
#include "parser/parse_type.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/date.h"
#include "utils/guc.h" #include "utils/guc.h"
#include "utils/syscache.h"
#include "utils/tqual.h" #include "utils/tqual.h"
#ifdef MULTIBYTE #ifdef MULTIBYTE
...@@ -41,470 +37,364 @@ ...@@ -41,470 +37,364 @@
#endif #endif
static bool show_datestyle(void);
static bool reset_datestyle(void);
static bool parse_datestyle(List *);
static bool show_timezone(void);
static bool reset_timezone(void);
static bool parse_timezone(List *);
static bool show_XactIsoLevel(void);
static bool reset_XactIsoLevel(void);
static bool parse_XactIsoLevel(List *);
static bool show_random_seed(void);
static bool reset_random_seed(void);
static bool parse_random_seed(List *);
static bool show_client_encoding(void);
static bool reset_client_encoding(void);
static bool parse_client_encoding(List *);
static bool show_server_encoding(void);
static bool reset_server_encoding(void);
static bool parse_server_encoding(List *);
/* /*
* get_token * DATESTYLE
* Obtain the next item in a comma-separated list of items,
* where each item can be either "word" or "word=word".
* The "word=word" form is only accepted if 'val' is not NULL.
* Words are any sequences not containing whitespace, ',', or '='.
* Whitespace can appear between the words and punctuation.
*
* 'tok': receives a pointer to first word of item, or NULL if none.
* 'val': if not NULL, receives a pointer to second word, or NULL if none.
* 'str': start of input string.
*
* Returns NULL if input string contained no more words, else pointer
* to just past this item, which can be used as 'str' for next call.
* (If this is the last item, returned pointer will point at a null char,
* so caller can alternatively check for that instead of calling again.)
*
* NB: input string is destructively modified by placing null characters
* at ends of words!
*
* A former version of this code avoided modifying the input string by
* returning palloc'd copies of the words. However, we want to use this
* code early in backend startup to parse the PGDATESTYLE environment var,
* and palloc/pfree aren't initialized at that point. Cleanest answer
* seems to be to palloc in SetPGVariable() so that we can treat the string
* as modifiable here.
*/ */
static char *
get_token(char **tok, char **val, char *str)
{
char ch;
*tok = NULL;
if (val != NULL)
*val = NULL;
if (!str || *str == '\0')
return NULL;
/* skip leading white space */
while (isspace((unsigned char) *str))
str++;
/* end of string? then return NULL */
if (*str == '\0')
return NULL;
if (*str == ',' || *str == '=')
elog(ERROR, "Syntax error near \"%s\": empty setting", str);
/* OK, at beginning of non-empty item */
*tok = str;
/* Advance to end of word */
while (*str && !isspace((unsigned char) *str) &&
*str != ',' && *str != '=')
str++;
/* Terminate word string for caller */
ch = *str;
*str = '\0';
/* Skip any whitespace */
while (isspace((unsigned char) ch))
ch = *(++str);
/* end of string? */
if (ch == '\0')
return str;
/* delimiter? */
if (ch == ',')
return ++str;
/* Had better be '=', and caller must be expecting it */
if (val == NULL || ch != '=')
elog(ERROR, "Syntax error near \"%s\"", str);
/* '=': get the value */
str++;
/* skip whitespace after '=' */
while (isspace((unsigned char) *str))
str++;
if (*str == ',' || *str == '\0')
elog(ERROR, "Syntax error near \"=%s\"", str);
/* OK, at beginning of non-empty value */
*val = str;
/* Advance to end of word */
while (*str && !isspace((unsigned char) *str) && *str != ',')
str++;
/* Terminate word string for caller */
ch = *str;
*str = '\0';
/* Skip any whitespace */
while (isspace((unsigned char) ch))
ch = *(++str);
/* end of string? */
if (ch == '\0')
return str;
/* delimiter? */
if (ch == ',')
return ++str;
elog(ERROR, "Syntax error near \"%s\"", str);
return str;
}
/* /*
* DATESTYLE * assign_datestyle: GUC assign_hook for datestyle
*
* NOTE: set_default_datestyle() is called during backend startup to check
* if the PGDATESTYLE environment variable is set. We want the env var
* to determine the value that "RESET DateStyle" will reset to!
*/ */
const char *
/* These get initialized from the "master" values in init/globals.c */ assign_datestyle(const char *value, bool doit, bool interactive)
static int DefaultDateStyle;
static bool DefaultEuroDates;
static bool
parse_datestyle_internal(char *value)
{ {
char *tok; int newDateStyle = DateStyle;
bool newEuroDates = EuroDates;
bool ok = true;
int dcnt = 0, int dcnt = 0,
ecnt = 0; ecnt = 0;
char *rawstring;
char *result;
List *elemlist;
List *l;
if (value == NULL) /* Need a modifiable copy of string */
return reset_datestyle(); rawstring = pstrdup(value);
while ((value = get_token(&tok, NULL, value)) != 0) /* Parse string into list of identifiers */
if (!SplitIdentifierString(rawstring, ',', &elemlist))
{ {
/* syntax error in list */
pfree(rawstring);
freeList(elemlist);
if (interactive)
elog(ERROR, "SET DATESTYLE: invalid list syntax");
return NULL;
}
foreach(l, elemlist)
{
char *tok = (char *) lfirst(l);
/* Ugh. Somebody ought to write a table driven version -- mjl */ /* Ugh. Somebody ought to write a table driven version -- mjl */
if (!strcasecmp(tok, "ISO")) if (strcasecmp(tok, "ISO") == 0)
{ {
DateStyle = USE_ISO_DATES; newDateStyle = USE_ISO_DATES;
dcnt++; dcnt++;
} }
else if (!strcasecmp(tok, "SQL")) else if (strcasecmp(tok, "SQL") == 0)
{ {
DateStyle = USE_SQL_DATES; newDateStyle = USE_SQL_DATES;
dcnt++; dcnt++;
} }
else if (!strncasecmp(tok, "POSTGRESQL", 8)) else if (strncasecmp(tok, "POSTGRESQL", 8) == 0)
{ {
DateStyle = USE_POSTGRES_DATES; newDateStyle = USE_POSTGRES_DATES;
dcnt++; dcnt++;
} }
else if (!strcasecmp(tok, "GERMAN")) else if (strcasecmp(tok, "GERMAN") == 0)
{ {
DateStyle = USE_GERMAN_DATES; newDateStyle = USE_GERMAN_DATES;
dcnt++; dcnt++;
if ((ecnt > 0) && (!EuroDates)) if ((ecnt > 0) && (!newEuroDates))
ecnt++; ok = false;
EuroDates = TRUE; newEuroDates = TRUE;
} }
else if (!strncasecmp(tok, "EURO", 4)) else if (strncasecmp(tok, "EURO", 4) == 0)
{ {
EuroDates = TRUE; newEuroDates = TRUE;
if ((dcnt <= 0) || (DateStyle != USE_GERMAN_DATES)) ecnt++;
ecnt++;
} }
else if ((!strcasecmp(tok, "US")) else if (strcasecmp(tok, "US") == 0
|| (!strncasecmp(tok, "NONEURO", 7))) || strncasecmp(tok, "NONEURO", 7) == 0)
{ {
EuroDates = FALSE; newEuroDates = FALSE;
if ((dcnt <= 0) || (DateStyle == USE_GERMAN_DATES)) ecnt++;
ecnt++; if ((dcnt > 0) && (newDateStyle == USE_GERMAN_DATES))
ok = false;
} }
else if (!strcasecmp(tok, "DEFAULT")) else if (strcasecmp(tok, "DEFAULT") == 0)
{ {
DateStyle = DefaultDateStyle; /*
EuroDates = DefaultEuroDates; * Easiest way to get the current DEFAULT state is to fetch
* the DEFAULT string from guc.c and recursively parse it.
*
* We can't simply "return assign_datestyle(...)" because we
* need to handle constructs like "DEFAULT, ISO".
*/
int saveDateStyle = DateStyle;
bool saveEuroDates = EuroDates;
const char *subval;
subval = assign_datestyle(GetConfigOptionResetString("datestyle"),
true, interactive);
newDateStyle = DateStyle;
newEuroDates = EuroDates;
DateStyle = saveDateStyle;
EuroDates = saveEuroDates;
if (!subval)
{
ok = false;
break;
}
/* Here we know that our own return value is always malloc'd */
/* when doit is true */
free((char *) subval);
dcnt++;
ecnt++; ecnt++;
} }
else else
elog(ERROR, "SET DATESTYLE bad value (%s)", tok); {
if (interactive)
elog(ERROR, "SET DATESTYLE: unrecognized keyword %s", tok);
ok = false;
break;
}
} }
if (dcnt > 1 || ecnt > 1) if (dcnt > 1 || ecnt > 1)
elog(WARNING, "SET DATESTYLE specified conflicting settings"); ok = false;
return TRUE;
}
static bool
parse_datestyle(List *args)
{
int rstat = FALSE;
List *arg;
char *value;
if (args == NULL)
return reset_datestyle();
Assert(IsA(args, List)); pfree(rawstring);
freeList(elemlist);
foreach(arg, args) if (!ok)
{ {
Node *n; if (interactive)
elog(ERROR, "SET DATESTYLE: conflicting specifications");
Assert(IsA(arg, List)); return NULL;
n = lfirst(arg); }
/* Require untyped, stringy constants for arguments. */
if (IsA(n, A_Const))
{
A_Const *p = (A_Const *) n;
TypeName *type = p->typename;
Value *v = &(p->val);
if (type != NULL)
{
Value *s;
Assert(IsA(type->names, List));
s = (Value *) lfirst(type->names);
elog(ERROR, "SET DATESTYLE does not allow input of type %s"
"\n\tUse an untyped string instead", s->val.str);
}
value = v->val.str; /*
} * If we aren't going to do the assignment, just return OK indicator.
else */
{ if (!doit)
elog(ERROR, "SET DATESTYLE argument is not valid"); return value;
value = NULL;
}
rstat = parse_datestyle_internal(value); /*
* Prepare the canonical string to return. GUC wants it malloc'd.
*/
result = (char *) malloc(32);
if (!result)
return NULL;
if (rstat != TRUE) switch (newDateStyle)
return rstat; {
case USE_ISO_DATES:
strcpy(result, "ISO");
break;
case USE_SQL_DATES:
strcpy(result, "SQL");
break;
case USE_GERMAN_DATES:
strcpy(result, "GERMAN");
break;
default:
strcpy(result, "POSTGRESQL");
break;
} }
strcat(result, newEuroDates ? ", EURO" : ", US");
/*
* Finally, it's safe to assign to the global variables;
* the assignment cannot fail now.
*/
DateStyle = newDateStyle;
EuroDates = newEuroDates;
return rstat; return result;
} }
static bool /*
* show_datestyle: GUC show_hook for datestyle
*/
const char *
show_datestyle(void) show_datestyle(void)
{ {
char buf[64]; static char buf[64];
strcpy(buf, "DateStyle is ");
switch (DateStyle) switch (DateStyle)
{ {
case USE_ISO_DATES: case USE_ISO_DATES:
strcat(buf, "ISO"); strcpy(buf, "ISO");
break; break;
case USE_SQL_DATES: case USE_SQL_DATES:
strcat(buf, "SQL"); strcpy(buf, "SQL");
break; break;
case USE_GERMAN_DATES: case USE_GERMAN_DATES:
strcat(buf, "German"); strcpy(buf, "German");
break; break;
default: default:
strcat(buf, "Postgres"); strcpy(buf, "Postgres");
break; break;
}; };
strcat(buf, " with "); strcat(buf, " with ");
strcat(buf, ((EuroDates) ? "European" : "US (NonEuropean)")); strcat(buf, ((EuroDates) ? "European" : "US (NonEuropean)"));
strcat(buf, " conventions"); strcat(buf, " conventions");
elog(INFO, buf, NULL); return buf;
return TRUE;
}
static bool
reset_datestyle(void)
{
DateStyle = DefaultDateStyle;
EuroDates = DefaultEuroDates;
return TRUE;
}
void
set_default_datestyle(void)
{
char *DBDate;
/*
* Initialize from compile-time defaults in init/globals.c. NB: this
* is a necessary step; consider PGDATESTYLE="DEFAULT".
*/
DefaultDateStyle = DateStyle;
DefaultEuroDates = EuroDates;
/* If the environment var is set, override compiled-in values */
DBDate = getenv("PGDATESTYLE");
if (DBDate == NULL)
return;
/*
* Make a modifiable copy --- overwriting the env var doesn't seem
* like a good idea, even though we currently won't look at it again.
* Note that we cannot use palloc at this early stage of
* initialization.
*/
DBDate = strdup(DBDate);
/*
* Parse desired setting into DateStyle/EuroDates Use
* parse_datestyle_internal() to avoid any palloc() issues per above -
* thomas 2001-10-15
*/
parse_datestyle_internal(DBDate);
free(DBDate);
/* And make it the default for future RESETs */
DefaultDateStyle = DateStyle;
DefaultEuroDates = EuroDates;
} }
/* Timezone support /*
* Working storage for strings is allocated with an arbitrary size of 64 bytes. * TIMEZONE
*/ */
static char *defaultTZ = NULL; /*
static char TZvalue[64]; * Storage for TZ env var is allocated with an arbitrary size of 64 bytes.
*/
static char tzbuf[64]; static char tzbuf[64];
/* /*
* * assign_timezone: GUC assign_hook for timezone
* TIMEZONE
*
*/
/* parse_timezone()
* Handle SET TIME ZONE...
* Try to save existing TZ environment variable for later use in RESET TIME ZONE.
* Accept an explicit interval per SQL9x, though this is less useful than a full time zone.
* - thomas 2001-10-11
*/ */
static bool const char *
parse_timezone(List *args) assign_timezone(const char *value, bool doit, bool interactive)
{ {
List *arg; char *result;
TypeName *type; char *endptr;
double hours;
if (args == NULL) /*
return reset_timezone(); * Check for INTERVAL 'foo'
*/
Assert(IsA(args, List)); if (strncasecmp(value, "interval", 8) == 0)
foreach(arg, args)
{ {
A_Const *p; const char *valueptr = value;
char *val;
Assert(IsA(arg, List)); Interval *interval;
p = lfirst(arg);
Assert(IsA(p, A_Const)); valueptr += 8;
while (isspace((unsigned char) *valueptr))
type = p->typename; valueptr++;
if (type != NULL) if (*valueptr++ != '\'')
return NULL;
val = pstrdup(valueptr);
/* Check and remove trailing quote */
endptr = strchr(val, '\'');
if (!endptr || endptr[1] != '\0')
{ {
Oid typeOid = typenameTypeId(type); pfree(val);
return NULL;
if (typeOid == INTERVALOID) }
{ *endptr = '\0';
Interval *interval; /*
* Try to parse it. XXX an invalid interval format will result in
interval = DatumGetIntervalP(DirectFunctionCall3(interval_in, * elog, which is not desirable for GUC. We did what we could to
CStringGetDatum(p->val.val.str), * guard against this in flatten_set_variable_args, but a string
ObjectIdGetDatum(InvalidOid), * coming in from postgresql.conf might contain anything.
Int32GetDatum(type->typmod))); */
if (interval->month != 0) interval = DatumGetIntervalP(DirectFunctionCall3(interval_in,
elog(ERROR, "SET TIME ZONE illegal INTERVAL; month not allowed"); CStringGetDatum(val),
CTimeZone = interval->time; ObjectIdGetDatum(InvalidOid),
} Int32GetDatum(-1)));
else if (typeOid == FLOAT8OID) pfree(val);
if (interval->month != 0)
{
if (interactive)
elog(ERROR, "SET TIME ZONE: illegal INTERVAL; month not allowed");
pfree(interval);
return NULL;
}
if (doit)
{
CTimeZone = interval->time;
HasCTZSet = true;
}
pfree(interval);
}
else
{
/*
* Try it as a numeric number of hours (possibly fractional).
*/
hours = strtod(value, &endptr);
if (endptr != value && *endptr == '\0')
{
if (doit)
{ {
float8 time; CTimeZone = hours * 3600;
HasCTZSet = true;
time = DatumGetFloat8(DirectFunctionCall1(float8in, CStringGetDatum(p->val.val.str)));
CTimeZone = time * 3600;
} }
}
else if (strcasecmp(value, "UNKNOWN") == 0)
{
/* /*
* We do not actually generate an integer constant in gram.y * Clear any TZ value we may have established.
* so this is not used... *
* unsetenv() works fine, but is BSD, not POSIX, and is not
* available under Solaris, among others. Apparently putenv()
* called as below clears the process-specific environment
* variables. Other reasonable arguments to putenv() (e.g.
* "TZ=", "TZ", "") result in a core dump (under Linux anyway).
* - thomas 1998-01-26
*/ */
else if (typeOid == INT4OID) if (doit)
{
int32 time;
time = p->val.val.ival;
CTimeZone = time * 3600;
}
else
{ {
elog(ERROR, "Unable to process SET TIME ZONE command; internal coding error"); if (tzbuf[0] == 'T')
{
strcpy(tzbuf, "=");
if (putenv(tzbuf) != 0)
elog(ERROR, "Unable to clear TZ environment variable");
tzset();
}
HasCTZSet = false;
} }
HasCTZSet = true;
} }
else else
{ {
char *tok; /*
char *value; * Otherwise assume it is a timezone name.
*
value = p->val.val.str; * XXX unfortunately we have no reasonable way to check whether a
* timezone name is good, so we have to just assume that it is.
while ((value = get_token(&tok, NULL, value)) != 0) */
if (doit)
{ {
/* Not yet tried to save original value from environment? */
if (defaultTZ == NULL)
{
/* found something? then save it for later */
if ((defaultTZ = getenv("TZ")) != NULL)
strcpy(TZvalue, defaultTZ);
/* found nothing so mark with an invalid pointer */
else
defaultTZ = (char *) -1;
}
strcpy(tzbuf, "TZ="); strcpy(tzbuf, "TZ=");
strcat(tzbuf, tok); strncat(tzbuf, value, sizeof(tzbuf)-4);
if (putenv(tzbuf) != 0) if (putenv(tzbuf) != 0) /* shouldn't happen? */
elog(ERROR, "Unable to set TZ environment variable to %s", tok); elog(LOG, "assign_timezone: putenv failed");
tzset(); tzset();
HasCTZSet = false;
} }
HasCTZSet = false;
} }
} }
return TRUE; /*
} /* parse_timezone() */ * If we aren't going to do the assignment, just return OK indicator.
*/
if (!doit)
return value;
/*
* Prepare the canonical string to return. GUC wants it malloc'd.
*/
result = (char *) malloc(sizeof(tzbuf));
if (!result)
return NULL;
if (HasCTZSet)
{
snprintf(result, sizeof(tzbuf), "%.5f",
(double) CTimeZone / 3600.0);
}
else if (tzbuf[0] == 'T')
{
strcpy(result, tzbuf + 3);
}
else
{
strcpy(result, "UNKNOWN");
}
return result;
}
static bool /*
* show_timezone: GUC show_hook for timezone
*/
const char *
show_timezone(void) show_timezone(void)
{ {
char *tzn; char *tzn;
...@@ -516,186 +406,68 @@ show_timezone(void) ...@@ -516,186 +406,68 @@ show_timezone(void)
interval.month = 0; interval.month = 0;
interval.time = CTimeZone; interval.time = CTimeZone;
tzn = DatumGetCString(DirectFunctionCall1(interval_out, IntervalPGetDatum(&interval))); tzn = DatumGetCString(DirectFunctionCall1(interval_out,
IntervalPGetDatum(&interval)));
} }
else else
tzn = getenv("TZ"); tzn = getenv("TZ");
if (tzn != NULL) if (tzn != NULL)
elog(INFO, "Time zone is '%s'", tzn); return tzn;
else
elog(INFO, "Time zone is unset");
return TRUE;
} /* show_timezone() */
/* reset_timezone()
* Set TZ environment variable to original value.
* Note that if TZ was originally not set, TZ should be cleared.
* unsetenv() works fine, but is BSD, not POSIX, and is not available
* under Solaris, among others. Apparently putenv() called as below
* clears the process-specific environment variables.
* Other reasonable arguments to putenv() (e.g. "TZ=", "TZ", "") result
* in a core dump (under Linux anyway).
* - thomas 1998-01-26
*/
static bool
reset_timezone(void)
{
if (HasCTZSet)
HasCTZSet = false;
/* no time zone has been set in this session? */
else if (defaultTZ == NULL)
{
}
/* time zone was set and original explicit time zone available? */
else if (defaultTZ != (char *) -1)
{
strcpy(tzbuf, "TZ=");
strcat(tzbuf, TZvalue);
if (putenv(tzbuf) != 0)
elog(ERROR, "Unable to set TZ environment variable to %s", TZvalue);
tzset();
}
/*
* otherwise, time zone was set but no original explicit time zone
* available
*/
else
{
strcpy(tzbuf, "=");
if (putenv(tzbuf) != 0)
elog(ERROR, "Unable to clear TZ environment variable");
tzset();
}
return TRUE;
} /* reset_timezone() */
return "unknown";
}
/* /*
* * SET TRANSACTION ISOLATION LEVEL
* SET TRANSACTION
*
*/ */
static bool const char *
parse_XactIsoLevel(List *args) assign_XactIsoLevel(const char *value, bool doit, bool interactive)
{ {
char *value; if (doit && interactive && SerializableSnapshot != NULL)
if (args == NULL)
return reset_XactIsoLevel();
Assert(IsA(args, List));
Assert(IsA(lfirst(args), A_Const));
/* Should only get one argument from the parser */
if (lnext(args) != NIL)
elog(ERROR, "SET TRANSACTION ISOLATION LEVEL takes only one argument");
Assert(((A_Const *) lfirst(args))->val.type = T_String);
value = ((A_Const *) lfirst(args))->val.val.str;
if (SerializableSnapshot != NULL)
{
elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query"); elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query");
return TRUE;
}
if (strcmp(value, "serializable") == 0) if (strcmp(value, "serializable") == 0)
XactIsoLevel = XACT_SERIALIZABLE; { if (doit) XactIsoLevel = XACT_SERIALIZABLE; }
else if (strcmp(value, "read committed") == 0) else if (strcmp(value, "read committed") == 0)
XactIsoLevel = XACT_READ_COMMITTED; { if (doit) XactIsoLevel = XACT_READ_COMMITTED; }
else if (strcmp(value, "default") == 0)
{ if (doit) XactIsoLevel = DefaultXactIsoLevel; }
else else
elog(ERROR, "invalid transaction isolation level: %s", value); return NULL;
return TRUE; return value;
} }
static bool const char *
show_XactIsoLevel(void) show_XactIsoLevel(void)
{ {
if (XactIsoLevel == XACT_SERIALIZABLE) if (XactIsoLevel == XACT_SERIALIZABLE)
elog(INFO, "TRANSACTION ISOLATION LEVEL is SERIALIZABLE"); return "SERIALIZABLE";
else else
elog(INFO, "TRANSACTION ISOLATION LEVEL is READ COMMITTED"); return "READ COMMITTED";
return TRUE;
}
static bool
reset_XactIsoLevel(void)
{
if (SerializableSnapshot != NULL)
{
elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query");
return TRUE;
}
XactIsoLevel = DefaultXactIsoLevel;
return TRUE;
} }
/* /*
* Random number seed * Random number seed
*/ */
static bool
parse_random_seed(List *args)
{
A_Const *p;
double seed = 0;
if (args == NULL)
return reset_random_seed();
Assert(IsA(args, List));
/* Should only get one argument from the parser */
if (lnext(args) != NIL)
elog(ERROR, "SET SEED takes only one argument");
p = lfirst(args);
Assert(IsA(p, A_Const));
if ((p->val.type == T_String) bool
|| (p->val.type == T_Float)) assign_random_seed(double value, bool doit, bool interactive)
{
seed = DatumGetFloat8(DirectFunctionCall1(float8in, CStringGetDatum(p->val.val.str)));
}
else if (p->val.type == T_Integer)
{
seed = p->val.val.ival;
}
else
{
elog(ERROR, "SET SEED internal coding error");
}
DirectFunctionCall1(setseed, Float8GetDatum(seed));
return (TRUE);
}
static bool
show_random_seed(void)
{ {
elog(INFO, "Seed for random number generator is unavailable"); /* Can't really roll back on error, so ignore non-interactive setting */
return (TRUE); if (doit && interactive)
DirectFunctionCall1(setseed, Float8GetDatum(value));
return true;
} }
static bool const char *
reset_random_seed(void) show_random_seed(void)
{ {
double seed = 0.5; return "unavailable";
DirectFunctionCall1(setseed, Float8GetDatum(seed));
return (TRUE);
} }
...@@ -708,259 +480,108 @@ reset_random_seed(void) ...@@ -708,259 +480,108 @@ reset_random_seed(void)
* clients. * clients.
*/ */
static bool const char *
parse_client_encoding(List *args) assign_client_encoding(const char *value, bool doit, bool interactive)
{ {
char *value;
#ifdef MULTIBYTE #ifdef MULTIBYTE
int encoding; int encoding;
#endif int old_encoding = 0;
if (args == NULL)
return reset_client_encoding();
if (lnext(args) != NIL)
elog(ERROR, "SET CLIENT ENCODING takes only one argument");
Assert(IsA(lfirst(args), A_Const));
if (((A_Const *) lfirst(args))->val.type != T_String)
{
elog(ERROR, "SET CLIENT_ENCODING requires an encoding name");
}
value = ((A_Const *) lfirst(args))->val.val.str;
#ifdef MULTIBYTE
encoding = pg_valid_client_encoding(value); encoding = pg_valid_client_encoding(value);
if (encoding < 0) if (encoding < 0)
return NULL;
/*
* Ugly API here ... can't test validity without setting new encoding...
*/
if (!doit)
old_encoding = pg_get_client_encoding();
if (pg_set_client_encoding(encoding) < 0)
{ {
if (value) if (interactive)
elog(ERROR, "Client encoding '%s' is not supported", value);
else
elog(ERROR, "No client encoding is specified");
}
else
{
if (pg_set_client_encoding(encoding) < 0)
{
elog(ERROR, "Conversion between %s and %s is not supported", elog(ERROR, "Conversion between %s and %s is not supported",
value, GetDatabaseEncodingName()); value, GetDatabaseEncodingName());
} return NULL;
} }
if (!doit)
pg_set_client_encoding(old_encoding);
#else #else
if (value && if (strcasecmp(value, pg_get_client_encoding_name()) != 0)
strcasecmp(value, pg_get_client_encoding_name()) != 0) return NULL;
elog(ERROR, "Client encoding %s is not supported", value);
#endif
return TRUE;
}
static bool
show_client_encoding(void)
{
elog(INFO, "Current client encoding is '%s'",
pg_get_client_encoding_name());
return TRUE;
}
static bool
reset_client_encoding(void)
{
#ifdef MULTIBYTE
int encoding;
char *env = getenv("PGCLIENTENCODING");
if (env)
{
encoding = pg_char_to_encoding(env);
if (encoding < 0)
encoding = GetDatabaseEncoding();
}
else
encoding = GetDatabaseEncoding();
pg_set_client_encoding(encoding);
#endif #endif
return TRUE;
}
/* Called during MULTIBYTE backend startup ... */ return value;
void
set_default_client_encoding(void)
{
reset_client_encoding();
} }
static bool const char *
parse_server_encoding(List *args) assign_server_encoding(const char *value, bool doit, bool interactive)
{ {
elog(INFO, "SET SERVER_ENCODING is not supported"); if (interactive)
return TRUE; elog(ERROR, "SET SERVER_ENCODING is not supported");
/* Pretend never to fail in noninteractive case */
return value;
} }
static bool const char *
show_server_encoding(void) show_server_encoding(void)
{ {
elog(INFO, "Current server encoding is '%s'", GetDatabaseEncodingName()); return GetDatabaseEncodingName();
return TRUE;
}
static bool
reset_server_encoding(void)
{
elog(INFO, "RESET SERVER_ENCODING is not supported");
return TRUE;
} }
static bool /*
show_session_authorization(void) * SET SESSION AUTHORIZATION
*
* Note: when resetting session auth after an error, we can't expect to do
* catalog lookups. Hence, the stored form of the value is always a numeric
* userid that can be re-used directly.
*/
const char *
assign_session_authorization(const char *value, bool doit, bool interactive)
{ {
elog(INFO, "Current session authorization is '%s'", Oid usesysid;
GetUserName(GetSessionUserId())); char *endptr;
return TRUE; char *result;
}
usesysid = (Oid) strtoul(value, &endptr, 10);
if (endptr != value && *endptr == '\0' && OidIsValid(usesysid))
/* SetPGVariable() {
* Dispatcher for handling SET commands. /* use the numeric user ID */
* Special cases ought to be removed and handled separately by TCOP }
*/
void
SetPGVariable(const char *name, List *args)
{
if (strcasecmp(name, "datestyle") == 0)
parse_datestyle(args);
else if (strcasecmp(name, "timezone") == 0)
parse_timezone(args);
else if (strcasecmp(name, "XactIsoLevel") == 0)
parse_XactIsoLevel(args);
else if (strcasecmp(name, "client_encoding") == 0)
parse_client_encoding(args);
else if (strcasecmp(name, "server_encoding") == 0)
parse_server_encoding(args);
else if (strcasecmp(name, "seed") == 0)
parse_random_seed(args);
else else
{ {
/* HeapTuple userTup;
* For routines defined somewhere else, go ahead and extract the
* string argument to match the original interface definition.
* Later, we can change this code too...
*/
char *value;
if (args != NULL) userTup = SearchSysCache(SHADOWNAME,
PointerGetDatum(value),
0, 0, 0);
if (!HeapTupleIsValid(userTup))
{ {
A_Const *n; if (interactive)
elog(ERROR, "user \"%s\" does not exist", value);
/* Ensure one argument only... */ return NULL;
if (lnext(args) != NIL)
elog(ERROR, "SET %s takes only one argument", name);
n = (A_Const *) lfirst(args);
if ((n->val.type == T_String)
|| (n->val.type == T_Float))
{
value = n->val.val.str;
}
else if (n->val.type == T_Integer)
{
/* We should convert back to a string. */
value = DatumGetCString(DirectFunctionCall1(int4out, Int32GetDatum(n->val.val.ival)));
}
else
{
elog(ERROR, "SET %s accepts a string argument for this parameter"
"\n\tInternal coding error: report to thomas@fourpalms.org",
name);
value = NULL;
}
}
else
{
value = NULL;
} }
if (strcasecmp(name, "session_authorization") == 0) usesysid = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
SetSessionAuthorization(value);
else
SetConfigOption(name,
value,
(superuser() ? PGC_SUSET : PGC_USERSET),
PGC_S_SESSION);
}
return;
}
void ReleaseSysCache(userTup);
GetPGVariable(const char *name)
{
if (strcasecmp(name, "datestyle") == 0)
show_datestyle();
else if (strcasecmp(name, "timezone") == 0)
show_timezone();
else if (strcasecmp(name, "XactIsoLevel") == 0)
show_XactIsoLevel();
else if (strcasecmp(name, "client_encoding") == 0)
show_client_encoding();
else if (strcasecmp(name, "server_encoding") == 0)
show_server_encoding();
else if (strcasecmp(name, "seed") == 0)
show_random_seed();
else if (strcasecmp(name, "session_authorization") == 0)
show_session_authorization();
else if (strcasecmp(name, "all") == 0)
{
ShowAllGUCConfig();
show_datestyle();
show_timezone();
show_XactIsoLevel();
show_client_encoding();
show_server_encoding();
show_random_seed();
} }
else
{
const char *val = GetConfigOption(name);
elog(INFO, "%s is %s", name, val); if (doit)
} SetSessionAuthorization(usesysid);
result = (char *) malloc(32);
if (!result)
return NULL;
snprintf(result, 32, "%lu", (unsigned long) usesysid);
return result;
} }
void const char *
ResetPGVariable(const char *name) show_session_authorization(void)
{ {
if (strcasecmp(name, "datestyle") == 0) return GetUserName(GetSessionUserId());
reset_datestyle();
else if (strcasecmp(name, "timezone") == 0)
reset_timezone();
else if (strcasecmp(name, "XactIsoLevel") == 0)
reset_XactIsoLevel();
else if (strcasecmp(name, "client_encoding") == 0)
reset_client_encoding();
else if (strcasecmp(name, "server_encoding") == 0)
reset_server_encoding();
else if (strcasecmp(name, "seed") == 0)
reset_random_seed();
else if (strcasecmp(name, "session_authorization") == 0)
SetSessionAuthorization(NULL);
else if (strcasecmp(name, "all") == 0)
{
reset_random_seed();
/* reset_server_encoding(); */
reset_client_encoding();
reset_datestyle();
reset_timezone();
/* should we reset session authorization here? */
ResetAllOptions(false);
}
else
SetConfigOption(name, NULL,
superuser() ? PGC_SUSET : PGC_USERSET,
PGC_S_SESSION);
} }
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/main/main.c,v 1.50 2002/04/03 05:39:29 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/main/main.c,v 1.51 2002/05/17 01:19:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -125,7 +125,7 @@ main(int argc, char *argv[]) ...@@ -125,7 +125,7 @@ main(int argc, char *argv[])
* and COLLATE will be overridden later from pg_control if we are * and COLLATE will be overridden later from pg_control if we are
* in an already-initialized database. We set them here so that * in an already-initialized database. We set them here so that
* they will be available to fill pg_control during initdb. The * they will be available to fill pg_control during initdb. The
* other ones will get reset later in ResetAllOptions, but we set * other ones will get reset later in InitializeGUCOptions, but we set
* them here to get already localized behavior during startup * them here to get already localized behavior during startup
* (e.g., error messages). * (e.g., error messages).
*/ */
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.185 2002/05/13 20:39:43 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.186 2002/05/17 01:19:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2342,6 +2342,7 @@ _copyVariableSetStmt(VariableSetStmt *from) ...@@ -2342,6 +2342,7 @@ _copyVariableSetStmt(VariableSetStmt *from)
if (from->name) if (from->name)
newnode->name = pstrdup(from->name); newnode->name = pstrdup(from->name);
Node_Copy(from, newnode, args); Node_Copy(from, newnode, args);
newnode->is_local = from->is_local;
return newnode; return newnode;
} }
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.132 2002/05/12 23:43:02 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.133 2002/05/17 01:19:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1173,6 +1173,8 @@ _equalVariableSetStmt(VariableSetStmt *a, VariableSetStmt *b) ...@@ -1173,6 +1173,8 @@ _equalVariableSetStmt(VariableSetStmt *a, VariableSetStmt *b)
return false; return false;
if (!equal(a->args, b->args)) if (!equal(a->args, b->args))
return false; return false;
if (a->is_local != b->is_local)
return false;
return true; return true;
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.315 2002/05/13 17:45:30 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.316 2002/05/17 01:19:17 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -128,6 +128,7 @@ static void doNegateFloat(Value *v); ...@@ -128,6 +128,7 @@ static void doNegateFloat(Value *v);
PrivTarget *privtarget; PrivTarget *privtarget;
InsertStmt *istmt; InsertStmt *istmt;
VariableSetStmt *vsetstmt;
} }
%type <node> stmt, schema_stmt, %type <node> stmt, schema_stmt,
...@@ -246,6 +247,8 @@ static void doNegateFloat(Value *v); ...@@ -246,6 +247,8 @@ static void doNegateFloat(Value *v);
%type <istmt> insert_rest %type <istmt> insert_rest
%type <vsetstmt> set_rest
%type <node> OptTableElement, ConstraintElem %type <node> OptTableElement, ConstraintElem
%type <node> columnDef %type <node> columnDef
%type <defelt> def_elem %type <defelt> def_elem
...@@ -563,12 +566,12 @@ AlterUserStmt: ALTER USER UserId OptUserList ...@@ -563,12 +566,12 @@ AlterUserStmt: ALTER USER UserId OptUserList
; ;
AlterUserSetStmt: ALTER USER UserId VariableSetStmt AlterUserSetStmt: ALTER USER UserId SET set_rest
{ {
AlterUserSetStmt *n = makeNode(AlterUserSetStmt); AlterUserSetStmt *n = makeNode(AlterUserSetStmt);
n->user = $3; n->user = $3;
n->variable = ((VariableSetStmt *)$4)->name; n->variable = $5->name;
n->value = ((VariableSetStmt *)$4)->args; n->value = $5->args;
$$ = (Node *)n; $$ = (Node *)n;
} }
| ALTER USER UserId VariableResetStmt | ALTER USER UserId VariableResetStmt
...@@ -576,7 +579,7 @@ AlterUserSetStmt: ALTER USER UserId VariableSetStmt ...@@ -576,7 +579,7 @@ AlterUserSetStmt: ALTER USER UserId VariableSetStmt
AlterUserSetStmt *n = makeNode(AlterUserSetStmt); AlterUserSetStmt *n = makeNode(AlterUserSetStmt);
n->user = $3; n->user = $3;
n->variable = ((VariableResetStmt *)$4)->name; n->variable = ((VariableResetStmt *)$4)->name;
n->value = NULL; n->value = NIL;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
...@@ -834,63 +837,83 @@ schema_stmt: CreateStmt ...@@ -834,63 +837,83 @@ schema_stmt: CreateStmt
* *
*****************************************************************************/ *****************************************************************************/
VariableSetStmt: SET ColId TO var_list_or_default VariableSetStmt: SET set_rest
{ {
VariableSetStmt *n = makeNode(VariableSetStmt); VariableSetStmt *n = $2;
n->name = $2; n->is_local = false;
n->args = $4;
$$ = (Node *) n; $$ = (Node *) n;
} }
| SET ColId '=' var_list_or_default | SET LOCAL set_rest
{ {
VariableSetStmt *n = makeNode(VariableSetStmt); VariableSetStmt *n = $3;
n->name = $2; n->is_local = true;
n->args = $4;
$$ = (Node *) n; $$ = (Node *) n;
} }
| SET TIME ZONE zone_value | SET SESSION set_rest
{ {
VariableSetStmt *n = makeNode(VariableSetStmt); VariableSetStmt *n = $3;
n->name = "timezone"; n->is_local = false;
if ($4 != NULL)
n->args = makeList1($4);
$$ = (Node *) n; $$ = (Node *) n;
} }
| SET TRANSACTION ISOLATION LEVEL opt_level ;
set_rest: ColId TO var_list_or_default
{ {
VariableSetStmt *n = makeNode(VariableSetStmt); VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = "XactIsoLevel"; n->name = $1;
n->args = makeList1(makeStringConst($5, NULL)); n->args = $3;
$$ = (Node *) n; $$ = n;
} }
| SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL opt_level | ColId '=' var_list_or_default
{ {
VariableSetStmt *n = makeNode(VariableSetStmt); VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = "default_transaction_isolation"; n->name = $1;
n->args = makeList1(makeStringConst($8, NULL)); n->args = $3;
$$ = (Node *) n; $$ = n;
} }
| SET NAMES opt_encoding | TIME ZONE zone_value
{ {
VariableSetStmt *n = makeNode(VariableSetStmt); VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = "client_encoding"; n->name = "timezone";
if ($3 != NULL) if ($3 != NULL)
n->args = makeList1(makeStringConst($3, NULL)); n->args = makeList1($3);
$$ = (Node *) n; $$ = n;
} }
| SET SESSION AUTHORIZATION ColId_or_Sconst | TRANSACTION ISOLATION LEVEL opt_level
{ {
VariableSetStmt *n = makeNode(VariableSetStmt); VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = "session_authorization"; n->name = "TRANSACTION ISOLATION LEVEL";
n->args = makeList1(makeStringConst($4, NULL)); n->args = makeList1(makeStringConst($4, NULL));
$$ = (Node *) n; $$ = n;
}
| SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL opt_level
{
VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = "default_transaction_isolation";
n->args = makeList1(makeStringConst($7, NULL));
$$ = n;
}
| NAMES opt_encoding
{
VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = "client_encoding";
if ($2 != NULL)
n->args = makeList1(makeStringConst($2, NULL));
$$ = n;
}
| SESSION AUTHORIZATION ColId_or_Sconst
{
VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = "session_authorization";
n->args = makeList1(makeStringConst($3, NULL));
$$ = n;
} }
| SET SESSION AUTHORIZATION DEFAULT | SESSION AUTHORIZATION DEFAULT
{ {
VariableSetStmt *n = makeNode(VariableSetStmt); VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = "session_authorization"; n->name = "session_authorization";
n->args = NIL; n->args = NIL;
$$ = (Node *) n; $$ = n;
} }
; ;
...@@ -926,10 +949,10 @@ opt_boolean: TRUE_P { $$ = "true"; } ...@@ -926,10 +949,10 @@ opt_boolean: TRUE_P { $$ = "true"; }
/* Timezone values can be: /* Timezone values can be:
* - a string such as 'pst8pdt' * - a string such as 'pst8pdt'
* - a column identifier such as "pst8pdt" * - an identifier such as "pst8pdt"
* - an integer or floating point number * - an integer or floating point number
* - a time interval per SQL99 * - a time interval per SQL99
* ConstInterval and ColId give shift/reduce errors, * ColId gives reduce/reduce errors against ConstInterval and LOCAL,
* so use IDENT and reject anything which is a reserved word. * so use IDENT and reject anything which is a reserved word.
*/ */
zone_value: Sconst zone_value: Sconst
...@@ -988,25 +1011,31 @@ ColId_or_Sconst: ColId { $$ = $1; } ...@@ -988,25 +1011,31 @@ ColId_or_Sconst: ColId { $$ = $1; }
VariableShowStmt: SHOW ColId VariableShowStmt: SHOW ColId
{ {
VariableShowStmt *n = makeNode(VariableShowStmt); VariableShowStmt *n = makeNode(VariableShowStmt);
n->name = $2; n->name = $2;
$$ = (Node *) n; $$ = (Node *) n;
} }
| SHOW TIME ZONE | SHOW TIME ZONE
{ {
VariableShowStmt *n = makeNode(VariableShowStmt); VariableShowStmt *n = makeNode(VariableShowStmt);
n->name = "timezone"; n->name = "timezone";
$$ = (Node *) n; $$ = (Node *) n;
} }
| SHOW ALL | SHOW TRANSACTION ISOLATION LEVEL
{ {
VariableShowStmt *n = makeNode(VariableShowStmt); VariableShowStmt *n = makeNode(VariableShowStmt);
n->name = "all"; n->name = "TRANSACTION ISOLATION LEVEL";
$$ = (Node *) n; $$ = (Node *) n;
} }
| SHOW TRANSACTION ISOLATION LEVEL | SHOW SESSION AUTHORIZATION
{
VariableShowStmt *n = makeNode(VariableShowStmt);
n->name = "session_authorization";
$$ = (Node *) n;
}
| SHOW ALL
{ {
VariableShowStmt *n = makeNode(VariableShowStmt); VariableShowStmt *n = makeNode(VariableShowStmt);
n->name = "XactIsoLevel"; n->name = "all";
$$ = (Node *) n; $$ = (Node *) n;
} }
; ;
...@@ -1014,19 +1043,19 @@ VariableShowStmt: SHOW ColId ...@@ -1014,19 +1043,19 @@ VariableShowStmt: SHOW ColId
VariableResetStmt: RESET ColId VariableResetStmt: RESET ColId
{ {
VariableResetStmt *n = makeNode(VariableResetStmt); VariableResetStmt *n = makeNode(VariableResetStmt);
n->name = $2; n->name = $2;
$$ = (Node *) n; $$ = (Node *) n;
} }
| RESET TIME ZONE | RESET TIME ZONE
{ {
VariableResetStmt *n = makeNode(VariableResetStmt); VariableResetStmt *n = makeNode(VariableResetStmt);
n->name = "timezone"; n->name = "timezone";
$$ = (Node *) n; $$ = (Node *) n;
} }
| RESET TRANSACTION ISOLATION LEVEL | RESET TRANSACTION ISOLATION LEVEL
{ {
VariableResetStmt *n = makeNode(VariableResetStmt); VariableResetStmt *n = makeNode(VariableResetStmt);
n->name = "XactIsoLevel"; n->name = "TRANSACTION ISOLATION LEVEL";
$$ = (Node *) n; $$ = (Node *) n;
} }
| RESET SESSION AUTHORIZATION | RESET SESSION AUTHORIZATION
...@@ -1038,7 +1067,7 @@ VariableResetStmt: RESET ColId ...@@ -1038,7 +1067,7 @@ VariableResetStmt: RESET ColId
| RESET ALL | RESET ALL
{ {
VariableResetStmt *n = makeNode(VariableResetStmt); VariableResetStmt *n = makeNode(VariableResetStmt);
n->name = "all"; n->name = "all";
$$ = (Node *) n; $$ = (Node *) n;
} }
; ;
...@@ -3329,12 +3358,12 @@ opt_equal: '=' { $$ = TRUE; } ...@@ -3329,12 +3358,12 @@ opt_equal: '=' { $$ = TRUE; }
* *
*****************************************************************************/ *****************************************************************************/
AlterDatabaseSetStmt: ALTER DATABASE database_name VariableSetStmt AlterDatabaseSetStmt: ALTER DATABASE database_name SET set_rest
{ {
AlterDatabaseSetStmt *n = makeNode(AlterDatabaseSetStmt); AlterDatabaseSetStmt *n = makeNode(AlterDatabaseSetStmt);
n->dbname = $3; n->dbname = $3;
n->variable = ((VariableSetStmt *)$4)->name; n->variable = $5->name;
n->value = ((VariableSetStmt *)$4)->args; n->value = $5->args;
$$ = (Node *)n; $$ = (Node *)n;
} }
| ALTER DATABASE database_name VariableResetStmt | ALTER DATABASE database_name VariableResetStmt
...@@ -3342,7 +3371,7 @@ AlterDatabaseSetStmt: ALTER DATABASE database_name VariableSetStmt ...@@ -3342,7 +3371,7 @@ AlterDatabaseSetStmt: ALTER DATABASE database_name VariableSetStmt
AlterDatabaseSetStmt *n = makeNode(AlterDatabaseSetStmt); AlterDatabaseSetStmt *n = makeNode(AlterDatabaseSetStmt);
n->dbname = $3; n->dbname = $3;
n->variable = ((VariableResetStmt *)$4)->name; n->variable = ((VariableResetStmt *)$4)->name;
n->value = NULL; n->value = NIL;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.273 2002/05/05 00:03:28 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.274 2002/05/17 01:19:17 tgl Exp $
* *
* NOTES * NOTES
* *
...@@ -404,12 +404,7 @@ PostmasterMain(int argc, char *argv[]) ...@@ -404,12 +404,7 @@ PostmasterMain(int argc, char *argv[])
/* /*
* Options setup * Options setup
*/ */
ResetAllOptions(true); InitializeGUCOptions();
/* PGPORT environment variable, if set, overrides GUC setting */
if (getenv("PGPORT"))
SetConfigOption("port", getenv("PGPORT"),
PGC_POSTMASTER, PGC_S_ARGV/*sortof*/);
potential_DataDir = getenv("PGDATA"); /* default value */ potential_DataDir = getenv("PGDATA"); /* default value */
...@@ -443,8 +438,8 @@ PostmasterMain(int argc, char *argv[]) ...@@ -443,8 +438,8 @@ PostmasterMain(int argc, char *argv[])
/* Turn on debugging for the postmaster. */ /* Turn on debugging for the postmaster. */
char *debugstr = palloc(strlen("debug") + strlen(optarg) + 1); char *debugstr = palloc(strlen("debug") + strlen(optarg) + 1);
sprintf(debugstr, "debug%s", optarg); sprintf(debugstr, "debug%s", optarg);
/* We use PGC_S_SESSION because we will reset in backend */ SetConfigOption("server_min_messages", debugstr,
SetConfigOption("server_min_messages", debugstr, PGC_POSTMASTER, PGC_S_SESSION); PGC_POSTMASTER, PGC_S_ARGV);
pfree(debugstr); pfree(debugstr);
break; break;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.264 2002/05/10 20:22:13 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.265 2002/05/17 01:19:18 tgl Exp $
* *
* NOTES * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
#include "access/xlog.h" #include "access/xlog.h"
#include "commands/async.h" #include "commands/async.h"
#include "commands/trigger.h" #include "commands/trigger.h"
#include "commands/variable.h"
#include "libpq/libpq.h" #include "libpq/libpq.h"
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
#include "libpq/pqsignal.h" #include "libpq/pqsignal.h"
...@@ -1184,13 +1183,10 @@ PostgresMain(int argc, char *argv[], const char *username) ...@@ -1184,13 +1183,10 @@ PostgresMain(int argc, char *argv[], const char *username)
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
ResetAllOptions(true); InitializeGUCOptions();
potential_DataDir = getenv("PGDATA"); potential_DataDir = getenv("PGDATA");
} }
/* Check for PGDATESTYLE environment variable */
set_default_datestyle();
/* ---------------- /* ----------------
* parse command line arguments * parse command line arguments
* *
...@@ -1273,9 +1269,10 @@ PostgresMain(int argc, char *argv[], const char *username) ...@@ -1273,9 +1269,10 @@ PostgresMain(int argc, char *argv[], const char *username)
else else
/* /*
* -d 0 allows user to prevent postmaster debug from * -d 0 allows user to prevent postmaster debug from
* propogating to backend. * propagating to backend.
*/ */
SetConfigOption("server_min_messages", "notice", PGC_POSTMASTER, PGC_S_ARGV); SetConfigOption("server_min_messages", "notice",
ctx, gucsource);
} }
break; break;
...@@ -1292,7 +1289,7 @@ PostgresMain(int argc, char *argv[], const char *username) ...@@ -1292,7 +1289,7 @@ PostgresMain(int argc, char *argv[], const char *username)
/* /*
* Use european date formats. * Use european date formats.
*/ */
EuroDates = true; SetConfigOption("datestyle", "euro", ctx, gucsource);
break; break;
case 'F': case 'F':
...@@ -1691,7 +1688,7 @@ PostgresMain(int argc, char *argv[], const char *username) ...@@ -1691,7 +1688,7 @@ PostgresMain(int argc, char *argv[], const char *username)
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
puts("\nPOSTGRES backend interactive interface "); puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.264 $ $Date: 2002/05/10 20:22:13 $\n"); puts("$Revision: 1.265 $ $Date: 2002/05/17 01:19:18 $\n");
} }
/* /*
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.153 2002/04/30 01:26:26 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.154 2002/05/17 01:19:18 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -36,7 +36,6 @@ ...@@ -36,7 +36,6 @@
#include "commands/trigger.h" #include "commands/trigger.h"
#include "commands/user.h" #include "commands/user.h"
#include "commands/vacuum.h" #include "commands/vacuum.h"
#include "commands/variable.h"
#include "commands/view.h" #include "commands/view.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
...@@ -48,6 +47,7 @@ ...@@ -48,6 +47,7 @@
#include "rewrite/rewriteRemove.h" #include "rewrite/rewriteRemove.h"
#include "tcop/utility.h" #include "tcop/utility.h"
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/guc.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "access/xlog.h" #include "access/xlog.h"
...@@ -718,7 +718,7 @@ ProcessUtility(Node *parsetree, ...@@ -718,7 +718,7 @@ ProcessUtility(Node *parsetree,
{ {
VariableSetStmt *n = (VariableSetStmt *) parsetree; VariableSetStmt *n = (VariableSetStmt *) parsetree;
SetPGVariable(n->name, n->args); SetPGVariable(n->name, n->args, n->is_local);
} }
break; break;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.89 2002/04/21 19:48:12 thomas Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.90 2002/05/17 01:19:18 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -3571,11 +3571,17 @@ EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str) ...@@ -3571,11 +3571,17 @@ EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str)
} /* EncodeInterval() */ } /* EncodeInterval() */
void /* GUC assign_hook for australian_timezones */
ClearDateCache(bool dummy) bool
ClearDateCache(bool newval, bool doit, bool interactive)
{ {
int i; int i;
for (i = 0; i < MAXDATEFIELDS; i++) if (doit)
datecache[i] = NULL; {
for (i = 0; i < MAXDATEFIELDS; i++)
datecache[i] = NULL;
}
return true;
} }
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* *
* PostgreSQL locale utilities * PostgreSQL locale utilities
* *
* $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.16 2002/04/03 05:39:31 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.17 2002/05/17 01:19:18 tgl Exp $
* *
* Portions Copyright (c) 2002, PostgreSQL Global Development Group * Portions Copyright (c) 2002, PostgreSQL Global Development Group
* *
...@@ -10,89 +10,73 @@ ...@@ -10,89 +10,73 @@
*/ */
#include "postgres.h" #include "postgres.h"
#include "utils/pg_locale.h"
#include <locale.h> #include <locale.h>
#include "utils/pg_locale.h"
/* GUC storage area */ /* GUC storage area */
char * locale_messages; char *locale_messages;
char * locale_monetary; char *locale_monetary;
char * locale_numeric; char *locale_numeric;
char * locale_time; char *locale_time;
/* GUC parse hooks */
bool locale_messages_check(const char *proposed) /* GUC assign hooks */
{
#ifdef LC_MESSAGES
return chklocale(LC_MESSAGES, proposed);
#else
/* We return true here so LC_MESSAGES can be set in the
configuration file on every system. */
return true;
#endif
}
bool locale_monetary_check(const char *proposed) static const char *
locale_xxx_assign(int category, const char *value, bool doit, bool interactive)
{ {
return chklocale(LC_MONETARY, proposed); if (doit)
} {
if (!setlocale(category, value))
return NULL;
}
else
{
char *save;
bool locale_numeric_check(const char *proposed) save = setlocale(category, NULL);
{ if (!save)
return chklocale(LC_NUMERIC, proposed); return NULL;
}
bool locale_time_check(const char *proposed) if (!setlocale(category, value))
{ return NULL;
return chklocale(LC_TIME, proposed);
}
/* GUC assign hooks */ setlocale(category, save);
}
return value;
}
void locale_messages_assign(const char *value) const char *
locale_messages_assign(const char *value, bool doit, bool interactive)
{ {
/* LC_MESSAGES category does not exist everywhere, but accept it anyway */
#ifdef LC_MESSAGES #ifdef LC_MESSAGES
setlocale(LC_MESSAGES, value); return locale_xxx_assign(LC_MESSAGES, value, doit, interactive);
#else
return value;
#endif #endif
} }
void locale_monetary_assign(const char *value) const char *
{ locale_monetary_assign(const char *value, bool doit, bool interactive)
setlocale(LC_MONETARY, value);
}
void locale_numeric_assign(const char *value)
{ {
setlocale(LC_NUMERIC, value); return locale_xxx_assign(LC_MONETARY, value, doit, interactive);
} }
void locale_time_assign(const char *value) const char *
locale_numeric_assign(const char *value, bool doit, bool interactive)
{ {
setlocale(LC_TIME, value); return locale_xxx_assign(LC_NUMERIC, value, doit, interactive);
} }
const char *
/* locale_time_assign(const char *value, bool doit, bool interactive)
* Returns true if the proposed string represents a valid locale of
* the given category. This is probably pretty slow, but it's not
* called in critical places.
*/
bool
chklocale(int category, const char *proposed)
{ {
char *save; return locale_xxx_assign(LC_TIME, value, doit, interactive);
save = setlocale(category, NULL);
if (!save)
return false;
if (!setlocale(category, proposed))
return false;
setlocale(category, save);
return true;
} }
...@@ -123,7 +107,6 @@ lc_collate_is_c(void) ...@@ -123,7 +107,6 @@ lc_collate_is_c(void)
} }
/* /*
* Return the POSIX lconv struct (contains number/money formatting * Return the POSIX lconv struct (contains number/money formatting
* information) with locale information for all categories. * information) with locale information for all categories.
...@@ -131,10 +114,11 @@ lc_collate_is_c(void) ...@@ -131,10 +114,11 @@ lc_collate_is_c(void)
struct lconv * struct lconv *
PGLC_localeconv(void) PGLC_localeconv(void)
{ {
struct lconv *extlconv;
static bool CurrentLocaleConvValid = false; static bool CurrentLocaleConvValid = false;
static struct lconv CurrentLocaleConv; static struct lconv CurrentLocaleConv;
struct lconv *extlconv;
/* Did we do it already? */ /* Did we do it already? */
if (CurrentLocaleConvValid) if (CurrentLocaleConvValid)
return &CurrentLocaleConv; return &CurrentLocaleConv;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* back to source text * back to source text
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.104 2002/05/12 23:43:03 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.105 2002/05/17 01:19:18 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -2576,27 +2576,33 @@ quote_identifier(const char *ident) ...@@ -2576,27 +2576,33 @@ quote_identifier(const char *ident)
* and contains only lowercase letters, digits, and underscores, *and* is * and contains only lowercase letters, digits, and underscores, *and* is
* not any SQL keyword. Otherwise, supply quotes. * not any SQL keyword. Otherwise, supply quotes.
*/ */
int nquotes = 0;
bool safe; bool safe;
const char *ptr;
char *result; char *result;
char *optr;
/* /*
* would like to use <ctype.h> macros here, but they might yield * would like to use <ctype.h> macros here, but they might yield
* unwanted locale-specific results... * unwanted locale-specific results...
*/ */
safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_'); safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
if (safe)
for (ptr = ident; *ptr; ptr++)
{ {
const char *ptr; char ch = *ptr;
for (ptr = ident + 1; *ptr; ptr++) if ((ch >= 'a' && ch <= 'z') ||
(ch >= '0' && ch <= '9') ||
(ch == '_'))
{ {
char ch = *ptr; /* okay */
}
safe = ((ch >= 'a' && ch <= 'z') || else
(ch >= '0' && ch <= '9') || {
(ch == '_')); safe = false;
if (!safe) if (ch == '"')
break; nquotes++;
} }
} }
...@@ -2618,8 +2624,21 @@ quote_identifier(const char *ident) ...@@ -2618,8 +2624,21 @@ quote_identifier(const char *ident)
if (safe) if (safe)
return ident; /* no change needed */ return ident; /* no change needed */
result = (char *) palloc(strlen(ident) + 2 + 1); result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
sprintf(result, "\"%s\"", ident);
optr = result;
*optr++ = '"';
for (ptr = ident; *ptr; ptr++)
{
char ch = *ptr;
if (ch == '"')
*optr++ = '"';
*optr++ = ch;
}
*optr++ = '"';
*optr = '\0';
return result; return result;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.97 2002/05/05 00:03:29 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.98 2002/05/17 01:19:18 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -841,105 +841,68 @@ elog_message_prefix(int lev) ...@@ -841,105 +841,68 @@ elog_message_prefix(int lev)
/* /*
* GUC support routines * GUC support routines
*/ */
const char *
bool assign_server_min_messages(const char *newval,
check_server_min_messages(const char *lev) bool doit, bool interactive)
{
if (strcasecmp(lev, "debug") == 0 ||
strcasecmp(lev, "debug5") == 0 ||
strcasecmp(lev, "debug4") == 0 ||
strcasecmp(lev, "debug3") == 0 ||
strcasecmp(lev, "debug2") == 0 ||
strcasecmp(lev, "debug1") == 0 ||
strcasecmp(lev, "info") == 0 ||
strcasecmp(lev, "notice") == 0 ||
strcasecmp(lev, "warning") == 0 ||
strcasecmp(lev, "error") == 0 ||
strcasecmp(lev, "log") == 0 ||
strcasecmp(lev, "fatal") == 0 ||
strcasecmp(lev, "panic") == 0)
return true;
return false;
}
void
assign_server_min_messages(const char *lev)
{ {
if (strcasecmp(lev, "debug") == 0) if (strcasecmp(newval, "debug") == 0)
server_min_messages = DEBUG5; { if (doit) server_min_messages = DEBUG1; }
else if (strcasecmp(lev, "debug5") == 0) else if (strcasecmp(newval, "debug5") == 0)
server_min_messages = DEBUG5; { if (doit) server_min_messages = DEBUG5; }
else if (strcasecmp(lev, "debug4") == 0) else if (strcasecmp(newval, "debug4") == 0)
server_min_messages = DEBUG4; { if (doit) server_min_messages = DEBUG4; }
else if (strcasecmp(lev, "debug3") == 0) else if (strcasecmp(newval, "debug3") == 0)
server_min_messages = DEBUG3; { if (doit) server_min_messages = DEBUG3; }
else if (strcasecmp(lev, "debug2") == 0) else if (strcasecmp(newval, "debug2") == 0)
server_min_messages = DEBUG2; { if (doit) server_min_messages = DEBUG2; }
else if (strcasecmp(lev, "debug1") == 0) else if (strcasecmp(newval, "debug1") == 0)
server_min_messages = DEBUG1; { if (doit) server_min_messages = DEBUG1; }
else if (strcasecmp(lev, "info") == 0) else if (strcasecmp(newval, "info") == 0)
server_min_messages = INFO; { if (doit) server_min_messages = INFO; }
else if (strcasecmp(lev, "notice") == 0) else if (strcasecmp(newval, "notice") == 0)
server_min_messages = NOTICE; { if (doit) server_min_messages = NOTICE; }
else if (strcasecmp(lev, "warning") == 0) else if (strcasecmp(newval, "warning") == 0)
server_min_messages = WARNING; { if (doit) server_min_messages = WARNING; }
else if (strcasecmp(lev, "error") == 0) else if (strcasecmp(newval, "error") == 0)
server_min_messages = ERROR; { if (doit) server_min_messages = ERROR; }
else if (strcasecmp(lev, "log") == 0) else if (strcasecmp(newval, "log") == 0)
server_min_messages = LOG; { if (doit) server_min_messages = LOG; }
else if (strcasecmp(lev, "fatal") == 0) else if (strcasecmp(newval, "fatal") == 0)
server_min_messages = FATAL; { if (doit) server_min_messages = FATAL; }
else if (strcasecmp(lev, "panic") == 0) else if (strcasecmp(newval, "panic") == 0)
server_min_messages = PANIC; { if (doit) server_min_messages = PANIC; }
else else
/* Can't get here unless guc.c screwed up */ return NULL; /* fail */
elog(ERROR, "bogus server_min_messages %s", lev); return newval; /* OK */
} }
bool const char *
check_client_min_messages(const char *lev) assign_client_min_messages(const char *newval,
{ bool doit, bool interactive)
if (strcasecmp(lev, "debug") == 0 ||
strcasecmp(lev, "debug5") == 0 ||
strcasecmp(lev, "debug4") == 0 ||
strcasecmp(lev, "debug3") == 0 ||
strcasecmp(lev, "debug2") == 0 ||
strcasecmp(lev, "debug1") == 0 ||
strcasecmp(lev, "log") == 0 ||
strcasecmp(lev, "info") == 0 ||
strcasecmp(lev, "notice") == 0 ||
strcasecmp(lev, "warning") == 0 ||
strcasecmp(lev, "error") == 0)
return true;
return false;
}
void
assign_client_min_messages(const char *lev)
{ {
if (strcasecmp(lev, "debug") == 0) if (strcasecmp(newval, "debug") == 0)
client_min_messages = DEBUG5; { if (doit) client_min_messages = DEBUG1; }
else if (strcasecmp(lev, "debug5") == 0) else if (strcasecmp(newval, "debug5") == 0)
client_min_messages = DEBUG5; { if (doit) client_min_messages = DEBUG5; }
else if (strcasecmp(lev, "debug4") == 0) else if (strcasecmp(newval, "debug4") == 0)
client_min_messages = DEBUG4; { if (doit) client_min_messages = DEBUG4; }
else if (strcasecmp(lev, "debug3") == 0) else if (strcasecmp(newval, "debug3") == 0)
client_min_messages = DEBUG3; { if (doit) client_min_messages = DEBUG3; }
else if (strcasecmp(lev, "debug2") == 0) else if (strcasecmp(newval, "debug2") == 0)
client_min_messages = DEBUG2; { if (doit) client_min_messages = DEBUG2; }
else if (strcasecmp(lev, "debug1") == 0) else if (strcasecmp(newval, "debug1") == 0)
client_min_messages = DEBUG1; { if (doit) client_min_messages = DEBUG1; }
else if (strcasecmp(lev, "log") == 0) else if (strcasecmp(newval, "log") == 0)
client_min_messages = LOG; { if (doit) client_min_messages = LOG; }
else if (strcasecmp(lev, "info") == 0) else if (strcasecmp(newval, "info") == 0)
client_min_messages = INFO; { if (doit) client_min_messages = INFO; }
else if (strcasecmp(lev, "notice") == 0) else if (strcasecmp(newval, "notice") == 0)
client_min_messages = NOTICE; { if (doit) client_min_messages = NOTICE; }
else if (strcasecmp(lev, "warning") == 0) else if (strcasecmp(newval, "warning") == 0)
client_min_messages = WARNING; { if (doit) client_min_messages = WARNING; }
else if (strcasecmp(lev, "error") == 0) else if (strcasecmp(newval, "error") == 0)
client_min_messages = ERROR; { if (doit) client_min_messages = ERROR; }
else else
/* Can't get here unless guc.c screwed up */ return NULL; /* fail */
elog(ERROR, "bogus client_min_messages %s", lev); return newval; /* OK */
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.90 2002/05/06 19:47:30 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.91 2002/05/17 01:19:18 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -614,6 +614,9 @@ InitializeSessionUserId(const char *username) ...@@ -614,6 +614,9 @@ InitializeSessionUserId(const char *username)
SetSessionUserId(usesysid); /* sets CurrentUserId too */ SetSessionUserId(usesysid); /* sets CurrentUserId too */
/* Record username as a config option too */
SetConfigOption("session_authorization", username,
PGC_BACKEND, PGC_S_OVERRIDE);
/* /*
* Set up user-specific configuration variables. This is a good * Set up user-specific configuration variables. This is a good
...@@ -653,23 +656,16 @@ InitializeSessionUserIdStandalone(void) ...@@ -653,23 +656,16 @@ InitializeSessionUserIdStandalone(void)
* Change session auth ID while running * Change session auth ID while running
* *
* Only a superuser may set auth ID to something other than himself. * Only a superuser may set auth ID to something other than himself.
*
* username == NULL implies reset to default (AuthenticatedUserId).
*/ */
void void
SetSessionAuthorization(const char *username) SetSessionAuthorization(Oid userid)
{ {
Oid userid; /* Must have authenticated already, else can't make permission check */
AssertState(OidIsValid(AuthenticatedUserId));
if (username == NULL) if (userid != AuthenticatedUserId &&
userid = AuthenticatedUserId; !AuthenticatedUserIsSuperuser)
else elog(ERROR, "permission denied");
{
userid = get_usesysid(username);
if (userid != AuthenticatedUserId &&
!AuthenticatedUserIsSuperuser)
elog(ERROR, "permission denied");
}
SetSessionUserId(userid); SetSessionUserId(userid);
SetUserId(userid); SetUserId(userid);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.104 2002/05/05 00:03:29 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.105 2002/05/17 01:19:18 tgl Exp $
* *
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include "catalog/pg_database.h" #include "catalog/pg_database.h"
#include "catalog/pg_shadow.h" #include "catalog/pg_shadow.h"
#include "commands/trigger.h" #include "commands/trigger.h"
#include "commands/variable.h"
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/backendid.h" #include "storage/backendid.h"
...@@ -132,6 +131,9 @@ ReverifyMyDatabase(const char *name) ...@@ -132,6 +131,9 @@ ReverifyMyDatabase(const char *name)
*/ */
#ifdef MULTIBYTE #ifdef MULTIBYTE
SetDatabaseEncoding(dbform->encoding); SetDatabaseEncoding(dbform->encoding);
/* If we have no other source of client_encoding, use server encoding */
SetConfigOption("client_encoding", GetDatabaseEncodingName(),
PGC_BACKEND, PGC_S_DEFAULT);
#else #else
if (dbform->encoding != PG_SQL_ASCII) if (dbform->encoding != PG_SQL_ASCII)
elog(FATAL, "database was initialized with MULTIBYTE encoding %d,\n\tbut the backend was compiled without multibyte support.\n\tlooks like you need to initdb or recompile.", elog(FATAL, "database was initialized with MULTIBYTE encoding %d,\n\tbut the backend was compiled without multibyte support.\n\tlooks like you need to initdb or recompile.",
...@@ -388,11 +390,6 @@ InitPostgres(const char *dbname, const char *username) ...@@ -388,11 +390,6 @@ InitPostgres(const char *dbname, const char *username)
/* set default namespace search path */ /* set default namespace search path */
InitializeSearchPath(); InitializeSearchPath();
#ifdef MULTIBYTE
/* set default client encoding --- uses info from ReverifyMyDatabase */
set_default_client_encoding();
#endif
/* /*
* Set up process-exit callback to do pre-shutdown cleanup. This should * Set up process-exit callback to do pre-shutdown cleanup. This should
* be last because we want shmem_exit to call this routine before the exit * be last because we want shmem_exit to call this routine before the exit
......
$Header: /cvsroot/pgsql/src/backend/utils/misc/README,v 1.1 2002/05/17 01:19:18 tgl Exp $
GUC IMPLEMENTATION NOTES
The GUC (Grand Unified Configuration) module implements configuration
variables of multiple types (currently boolean, int, float, and string).
Variable settings can come from various places, with a priority ordering
determining which setting is used.
PER-VARIABLE HOOKS
Each variable known to GUC can optionally have an assign_hook and/or
a show_hook to provide customized behavior. Assign hooks are used to
perform validity checking on variable values (above and beyond what
GUC can do). They are also used to update any derived state that needs
to change when a GUC variable is set. Show hooks are used to modify
the default SHOW display for a variable.
If an assign_hook is provided, it points to a function of the signature
bool assign_hook(newvalue, bool doit, bool interactive)
where the type of 'newvalue' matches the kind of variable. This function
is called immediately before actually setting the variable's value (so it
can look at the actual variable to determine the old value). If the
function returns "true" then the assignment is completed; if it returns
"false" then newvalue is considered invalid and the assignment is not
performed. If "doit" is false then the function should simply check
validity of newvalue and not change any derived state. "interactive" is
true when we are performing a SET command; in this case it is okay for the
assign_hook to raise an error via elog(). If the function returns false
for an interactive assignment then guc.c will report a generic "invalid
value" error message. (An internal elog() in an assign_hook is only
needed if you want to generate a specialized error message.) But when
"interactive" is false we are reading a non-interactive option source,
such as postgresql.conf. In this case the assign_hook should *not* elog
but should just return false if it doesn't like the newvalue. (An
elog(LOG) call would be acceptable if you feel a need for a custom
complaint in this situation.)
For string variables, the signature for assign hooks is a bit different:
const char *assign_hook(const char *newvalue,
bool doit,
bool interactive)
The meanings of the parameters are the same as for the other types of GUC
variables, but the return value is handled differently:
NULL --- assignment fails (like returning false for other datatypes)
newvalue --- assignment succeeds, assign the newvalue as-is
malloc'd (not palloc'd!!!) string --- assign that value instead
The third choice is allowed in case the assign_hook wants to return a
"canonical" version of the new value. For example, the assign_hook for
datestyle always returns a string that includes both basic datestyle and
us/euro option, although the input might have specified only one.
If a show_hook is provided, it points to a function of the signature
const char *show_hook(void)
This hook allows variable-specific computation of the value displayed
by SHOW.
SAVING/RESTORING GUC VARIABLE VALUES
Prior values of configuration variables must be remembered in order to
deal with three special cases: RESET (a/k/a SET TO DEFAULT), rollback of
SET on transaction abort, and rollback of SET LOCAL at transaction end
(either commit or abort). RESET is defined as selecting the value that
would be effective had there never been any SET commands in the current
session.
To handle these cases we must keep track of as many as four distinct
values for each variable. They are:
* actual variable contents always the current effective value
* reset_value the value to use for RESET
* session_value the "committed" setting for the session
* tentative_value the uncommitted result of SET
During initialization we set the first three of these (actual, reset_value,
and session_value) based on whichever non-interactive source has the
highest priority. All three will have the same value.
A SET LOCAL command sets the actual variable (and nothing else). At
transaction end, the session_value is used to restore the actual variable
to its pre-transaction value.
A SET (or SET SESSION) command sets the actual variable, and if no error,
then sets the tentative_value. If the transaction commits, the
tentative_value is assigned to the session_value and the actual variable
(which could by now be different, if the SET was followed by SET LOCAL).
If the transaction aborts, the tentative_value is discarded and the
actual variable is restored from the session_value.
RESET is executed like a SET, but using the reset_value as the desired new
value. (We do not provide a RESET LOCAL command, but SET LOCAL TO DEFAULT
has the same behavior that RESET LOCAL would.) The source associated with
the reset_value also becomes associated with the actual and session values.
If SIGHUP is received, the GUC code rereads the postgresql.conf
configuration file (this does not happen in the signal handler, but at
next return to main loop; note that it can be executed while within a
transaction). New values from postgresql.conf are assigned to actual
variable, reset_value, and session_value, but only if each of these has a
current source priority <= PGC_S_FILE. (It is thus possible for
reset_value to track the config-file setting even if there is currently
a different interactive value of the actual variable.)
Note that tentative_value is unused and undefined except between a SET
command and the end of the transaction. Also notice that we must track
the source associated with each of the four values.
The assign_hook and show_hook routines work only with the actual variable,
and are not directly aware of the additional values maintained by GUC.
This is not a problem for normal usage, since we can assign first to the
actual variable and then (if that succeeds) to the additional values as
needed. However, for SIGHUP rereads we may not want to assign to the
actual variable. Our procedure in that case is to call the assign_hook
with doit = false so that the value is validated, but no derived state is
changed.
STRING MEMORY HANDLING
String option values are allocated with strdup, not with the
pstrdup/palloc mechanisms. We would need to keep them in a permanent
context anyway, and strdup gives us more control over handling
out-of-memory failures.
We allow a variable's actual value, reset_val, session_val, and
tentative_val to point at the same storage. This makes it slightly harder
to free space (must test that the value to be freed isn't equal to any of
the other three pointers). The main advantage is that we never need to
strdup during transaction commit/abort, so cannot cause an out-of-memory
failure there.
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* *
* Copyright 2000 by PostgreSQL Global Development Group * Copyright 2000 by PostgreSQL Global Development Group
* *
* $Header: /cvsroot/pgsql/src/backend/utils/misc/guc-file.l,v 1.11 2002/03/02 21:39:33 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc-file.l,v 1.12 2002/05/17 01:19:18 tgl Exp $
*/ */
%{ %{
...@@ -168,7 +168,7 @@ ProcessConfigFile(GucContext context) ...@@ -168,7 +168,7 @@ ProcessConfigFile(GucContext context)
head = tail = NULL; head = tail = NULL;
opt_name = opt_value = NULL; opt_name = opt_value = NULL;
while((token = yylex())) while ((token = yylex()))
switch(parse_state) switch(parse_state)
{ {
case 0: /* no previous input */ case 0: /* no previous input */
...@@ -188,23 +188,22 @@ ProcessConfigFile(GucContext context) ...@@ -188,23 +188,22 @@ ProcessConfigFile(GucContext context)
token = yylex(); token = yylex();
if (token != GUC_ID && token != GUC_STRING && if (token != GUC_ID && token != GUC_STRING &&
token != GUC_INTEGER && token != GUC_REAL && token != GUC_INTEGER && token != GUC_REAL &&
token != GUC_UNQUOTED_STRING) token != GUC_UNQUOTED_STRING)
goto parse_error; goto parse_error;
opt_value = strdup(yytext); opt_value = strdup(yytext);
if (opt_value == NULL) if (opt_value == NULL)
goto out_of_memory; goto out_of_memory;
if (token == GUC_STRING) if (token == GUC_STRING)
{ {
/* remove the beginning and ending quote/apostrophe */ /* remove the beginning and ending quote/apostrophe */
/* first: shift the whole shooting match down one /* first: shift the whole thing down one character */
character */ memmove(opt_value,opt_value+1,strlen(opt_value)-1);
memmove(opt_value,opt_value+1,strlen(opt_value)-1); /* second: null out the 2 characters we shifted */
/* second: null out the 2 characters we shifted */ opt_value[strlen(opt_value)-2]='\0';
opt_value[strlen(opt_value)-2]='\0'; /* do the escape thing. free()'s the strdup above */
/* do the escape thing. free()'s the strdup above */ opt_value=GUC_scanstr(opt_value);
opt_value=GUC_scanstr(opt_value); }
}
parse_state = 2; parse_state = 2;
break; break;
...@@ -241,14 +240,14 @@ ProcessConfigFile(GucContext context) ...@@ -241,14 +240,14 @@ ProcessConfigFile(GucContext context)
for(item = head; item; item=item->next) for(item = head; item; item=item->next)
{ {
if (!set_config_option(item->name, item->value, context, if (!set_config_option(item->name, item->value, context,
false, PGC_S_INFINITY)) PGC_S_FILE, false, false))
goto cleanup_exit; goto cleanup_exit;
} }
/* If we got here all the options parsed okay. */ /* If we got here all the options parsed okay. */
for(item = head; item; item=item->next) for(item = head; item; item=item->next)
set_config_option(item->name, item->value, context, set_config_option(item->name, item->value, context,
true, PGC_S_FILE); PGC_S_FILE, false, true);
cleanup_exit: cleanup_exit:
free_name_value_list(head); free_name_value_list(head);
......
...@@ -3,8 +3,9 @@ ...@@ -3,8 +3,9 @@
* *
* Support for grand unified configuration scheme, including SET * Support for grand unified configuration scheme, including SET
* command, configuration file, and command line options. * command, configuration file, and command line options.
* See src/backend/utils/misc/README for more information.
* *
* $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.67 2002/05/14 13:05:43 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.68 2002/05/17 01:19:18 tgl Exp $
* *
* Copyright 2000 by PostgreSQL Global Development Group * Copyright 2000 by PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>. * Written by Peter Eisentraut <peter_e@gmx.net>.
...@@ -23,6 +24,7 @@ ...@@ -23,6 +24,7 @@
#include "access/xlog.h" #include "access/xlog.h"
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "commands/async.h" #include "commands/async.h"
#include "commands/variable.h"
#include "fmgr.h" #include "fmgr.h"
#include "libpq/auth.h" #include "libpq/auth.h"
#include "libpq/pqcomm.h" #include "libpq/pqcomm.h"
...@@ -57,13 +59,10 @@ extern bool FixBTree; ...@@ -57,13 +59,10 @@ extern bool FixBTree;
#ifdef HAVE_SYSLOG #ifdef HAVE_SYSLOG
extern char *Syslog_facility; extern char *Syslog_facility;
extern char *Syslog_ident; extern char *Syslog_ident;
static bool check_facility(const char *facility);
#endif
static char *default_iso_level_string;
static bool check_defaultxactisolevel(const char *value); static const char *assign_facility(const char *facility,
static void assign_defaultxactisolevel(const char *value); bool doit, bool interactive);
#endif
/* /*
* Debugging options * Debugging options
...@@ -96,87 +95,167 @@ bool Password_encryption = false; ...@@ -96,87 +95,167 @@ bool Password_encryption = false;
#define PG_KRB_SRVTAB "" #define PG_KRB_SRVTAB ""
#endif #endif
static bool guc_session_init = false; /* XXX mildly bogus */ /*
* These variables are all dummies that don't do anything, except in some
* cases provide the value for SHOW to display. The real state is elsewhere
* and is kept in sync by assign_hooks.
*/
static double phony_random_seed;
static char *client_encoding_string;
static char *datestyle_string;
static char *default_iso_level_string;
static char *server_encoding_string;
static char *session_authorization_string;
static char *timezone_string;
static char *XactIsoLevel_string;
static const char *assign_defaultxactisolevel(const char *newval,
bool doit, bool interactive);
/* /*
* Declarations for GUC tables * Declarations for GUC tables
*
* See src/backend/utils/misc/README for design notes.
*/ */
enum config_type enum config_type
{ {
PGC_NONE = 0,
PGC_BOOL, PGC_BOOL,
PGC_INT, PGC_INT,
PGC_REAL, PGC_REAL,
PGC_STRING PGC_STRING
}; };
/* Generic fields applicable to all types of variables */
struct config_generic struct config_generic
{ {
const char *name; /* constant fields, must be set correctly in initial value: */
GucContext context; const char *name; /* name of variable - MUST BE FIRST */
GucSource source; GucContext context; /* context required to set the variable */
void *variable; int flags; /* flag bits, see below */
/* variable fields, initialized at runtime: */
enum config_type vartype; /* type of variable (set only at startup) */
int status; /* status bits, see below */
GucSource reset_source; /* source of the reset_value */
GucSource session_source; /* source of the session_value */
GucSource tentative_source; /* source of the tentative_value */
GucSource source; /* source of the current actual value */
}; };
/* bit values in flags field */
#define GUC_LIST_INPUT 0x0001 /* input can be list format */
#define GUC_LIST_QUOTE 0x0002 /* double-quote list elements */
#define GUC_NO_SHOW_ALL 0x0004 /* exclude from SHOW ALL */
#define GUC_NO_RESET_ALL 0x0008 /* exclude from RESET ALL */
/* bit values in status field */
#define GUC_HAVE_TENTATIVE 0x0001 /* tentative value is defined */
#define GUC_HAVE_LOCAL 0x0002 /* a SET LOCAL has been executed */
/* GUC records for specific variable types */
struct config_bool struct config_bool
{ {
const char *name; struct config_generic gen;
GucContext context; /* these fields must be set correctly in initial value: */
GucSource source; /* (all but reset_val are constants) */
bool *variable; bool *variable;
bool default_val; bool reset_val;
/* No need for parse_hook ... presumably both values are legal */ bool (*assign_hook) (bool newval, bool doit, bool interactive);
void (*assign_hook) (bool newval); const char *(*show_hook) (void);
/* variable fields, initialized at runtime: */
bool session_val;
bool tentative_val;
}; };
struct config_int struct config_int
{ {
const char *name; struct config_generic gen;
GucContext context; /* these fields must be set correctly in initial value: */
GucSource source; /* (all but reset_val are constants) */
int *variable; int *variable;
int default_val; int reset_val;
int min; int min;
int max; int max;
bool (*parse_hook) (int proposed); bool (*assign_hook) (int newval, bool doit, bool interactive);
void (*assign_hook) (int newval); const char *(*show_hook) (void);
/* variable fields, initialized at runtime: */
int session_val;
int tentative_val;
}; };
struct config_real struct config_real
{ {
const char *name; struct config_generic gen;
GucContext context; /* these fields must be set correctly in initial value: */
GucSource source; /* (all but reset_val are constants) */
double *variable; double *variable;
double default_val; double reset_val;
double min; double min;
double max; double max;
bool (*parse_hook) (double proposed); bool (*assign_hook) (double newval, bool doit, bool interactive);
void (*assign_hook) (double newval); const char *(*show_hook) (void);
/* variable fields, initialized at runtime: */
double session_val;
double tentative_val;
}; };
/*
* String value options are allocated with strdup, not with the
* pstrdup/palloc mechanisms. That is because configuration settings
* are already in place before the memory subsystem is up. It would
* perhaps be an idea to change that sometime.
*/
struct config_string struct config_string
{ {
const char *name; struct config_generic gen;
GucContext context; /* these fields must be set correctly in initial value: */
GucSource source; /* (all are constants) */
char **variable; char **variable;
const char *boot_default_val; const char *boot_val;
bool (*parse_hook) (const char *proposed); const char *(*assign_hook) (const char *newval, bool doit, bool interactive);
void (*assign_hook) (const char *newval); const char *(*show_hook) (void);
char *default_val; /* variable fields, initialized at runtime: */
char *reset_val;
char *session_val;
char *tentative_val;
}; };
/* Macros for freeing malloc'd pointers only if appropriate to do so */
/* Some of these tests are probably redundant, but be safe ... */
#define SET_STRING_VARIABLE(rec, newval) \
do { \
if (*(rec)->variable && \
*(rec)->variable != (rec)->reset_val && \
*(rec)->variable != (rec)->session_val && \
*(rec)->variable != (rec)->tentative_val) \
free(*(rec)->variable); \
*(rec)->variable = (newval); \
} while (0)
#define SET_STRING_RESET_VAL(rec, newval) \
do { \
if ((rec)->reset_val && \
(rec)->reset_val != *(rec)->variable && \
(rec)->reset_val != (rec)->session_val && \
(rec)->reset_val != (rec)->tentative_val) \
free((rec)->reset_val); \
(rec)->reset_val = (newval); \
} while (0)
#define SET_STRING_SESSION_VAL(rec, newval) \
do { \
if ((rec)->session_val && \
(rec)->session_val != *(rec)->variable && \
(rec)->session_val != (rec)->reset_val && \
(rec)->session_val != (rec)->tentative_val) \
free((rec)->session_val); \
(rec)->session_val = (newval); \
} while (0)
#define SET_STRING_TENTATIVE_VAL(rec, newval) \
do { \
if ((rec)->tentative_val && \
(rec)->tentative_val != *(rec)->variable && \
(rec)->tentative_val != (rec)->reset_val && \
(rec)->tentative_val != (rec)->session_val) \
free((rec)->tentative_val); \
(rec)->tentative_val = (newval); \
} while (0)
/* /*
* TO ADD AN OPTION: * TO ADD AN OPTION:
...@@ -200,167 +279,212 @@ struct config_string ...@@ -200,167 +279,212 @@ struct config_string
*/ */
/******** option names follow ********/ /******** option records follow ********/
static struct config_bool static struct config_bool
ConfigureNamesBool[] = ConfigureNamesBool[] =
{ {
{ {
"enable_seqscan", PGC_USERSET, PGC_S_DEFAULT, &enable_seqscan, true, NULL { "enable_seqscan", PGC_USERSET }, &enable_seqscan,
true, NULL, NULL
}, },
{ {
"enable_indexscan", PGC_USERSET, PGC_S_DEFAULT, &enable_indexscan, true, NULL { "enable_indexscan", PGC_USERSET }, &enable_indexscan,
true, NULL, NULL
}, },
{ {
"enable_tidscan", PGC_USERSET, PGC_S_DEFAULT, &enable_tidscan, true, NULL { "enable_tidscan", PGC_USERSET }, &enable_tidscan,
true, NULL, NULL
}, },
{ {
"enable_sort", PGC_USERSET, PGC_S_DEFAULT, &enable_sort, true, NULL { "enable_sort", PGC_USERSET }, &enable_sort,
true, NULL, NULL
}, },
{ {
"enable_nestloop", PGC_USERSET, PGC_S_DEFAULT, &enable_nestloop, true, NULL { "enable_nestloop", PGC_USERSET }, &enable_nestloop,
true, NULL, NULL
}, },
{ {
"enable_mergejoin", PGC_USERSET, PGC_S_DEFAULT, &enable_mergejoin, true, NULL { "enable_mergejoin", PGC_USERSET }, &enable_mergejoin,
true, NULL, NULL
}, },
{ {
"enable_hashjoin", PGC_USERSET, PGC_S_DEFAULT, &enable_hashjoin, true, NULL { "enable_hashjoin", PGC_USERSET }, &enable_hashjoin,
true, NULL, NULL
}, },
{ {
"ksqo", PGC_USERSET, PGC_S_DEFAULT, &_use_keyset_query_optimizer, false, NULL { "ksqo", PGC_USERSET }, &_use_keyset_query_optimizer,
false, NULL, NULL
}, },
{ {
"geqo", PGC_USERSET, PGC_S_DEFAULT, &enable_geqo, true, NULL { "geqo", PGC_USERSET }, &enable_geqo,
true, NULL, NULL
}, },
{ {
"tcpip_socket", PGC_POSTMASTER, PGC_S_DEFAULT, &NetServer, false, NULL { "tcpip_socket", PGC_POSTMASTER }, &NetServer,
false, NULL, NULL
}, },
{ {
"ssl", PGC_POSTMASTER, PGC_S_DEFAULT, &EnableSSL, false, NULL { "ssl", PGC_POSTMASTER }, &EnableSSL,
false, NULL, NULL
}, },
{ {
"fsync", PGC_SIGHUP, PGC_S_DEFAULT, &enableFsync, true, NULL { "fsync", PGC_SIGHUP }, &enableFsync,
true, NULL, NULL
}, },
{ {
"silent_mode", PGC_POSTMASTER, PGC_S_DEFAULT, &SilentMode, false, NULL { "silent_mode", PGC_POSTMASTER }, &SilentMode,
false, NULL, NULL
}, },
{ {
"log_connections", PGC_BACKEND, PGC_S_DEFAULT, &Log_connections, false, NULL { "log_connections", PGC_BACKEND }, &Log_connections,
false, NULL, NULL
}, },
{ {
"log_timestamp", PGC_SIGHUP, PGC_S_DEFAULT, &Log_timestamp, false, NULL { "log_timestamp", PGC_SIGHUP }, &Log_timestamp,
false, NULL, NULL
}, },
{ {
"log_pid", PGC_SIGHUP, PGC_S_DEFAULT, &Log_pid, false, NULL { "log_pid", PGC_SIGHUP }, &Log_pid,
false, NULL, NULL
}, },
#ifdef USE_ASSERT_CHECKING #ifdef USE_ASSERT_CHECKING
{ {
"debug_assertions", PGC_USERSET, PGC_S_DEFAULT, &assert_enabled, true, NULL { "debug_assertions", PGC_USERSET }, &assert_enabled,
true, NULL, NULL
}, },
#endif #endif
{ {
"debug_print_query", PGC_USERSET, PGC_S_DEFAULT, &Debug_print_query, false, NULL { "debug_print_query", PGC_USERSET }, &Debug_print_query,
false, NULL, NULL
}, },
{ {
"debug_print_parse", PGC_USERSET, PGC_S_DEFAULT, &Debug_print_parse, false, NULL { "debug_print_parse", PGC_USERSET }, &Debug_print_parse,
false, NULL, NULL
}, },
{ {
"debug_print_rewritten", PGC_USERSET, PGC_S_DEFAULT, &Debug_print_rewritten, false, NULL { "debug_print_rewritten", PGC_USERSET }, &Debug_print_rewritten,
false, NULL, NULL
}, },
{ {
"debug_print_plan", PGC_USERSET, PGC_S_DEFAULT, &Debug_print_plan, false, NULL { "debug_print_plan", PGC_USERSET }, &Debug_print_plan,
false, NULL, NULL
}, },
{ {
"debug_pretty_print", PGC_USERSET, PGC_S_DEFAULT, &Debug_pretty_print, false, NULL { "debug_pretty_print", PGC_USERSET }, &Debug_pretty_print,
false, NULL, NULL
}, },
{ {
"show_parser_stats", PGC_USERSET, PGC_S_DEFAULT, &Show_parser_stats, false, NULL { "show_parser_stats", PGC_USERSET }, &Show_parser_stats,
false, NULL, NULL
}, },
{ {
"show_planner_stats", PGC_USERSET, PGC_S_DEFAULT, &Show_planner_stats, false, NULL { "show_planner_stats", PGC_USERSET }, &Show_planner_stats,
false, NULL, NULL
}, },
{ {
"show_executor_stats", PGC_USERSET, PGC_S_DEFAULT, &Show_executor_stats, false, NULL { "show_executor_stats", PGC_USERSET }, &Show_executor_stats,
false, NULL, NULL
}, },
{ {
"show_query_stats", PGC_USERSET, PGC_S_DEFAULT, &Show_query_stats, false, NULL { "show_query_stats", PGC_USERSET }, &Show_query_stats,
false, NULL, NULL
}, },
#ifdef BTREE_BUILD_STATS #ifdef BTREE_BUILD_STATS
{ {
"show_btree_build_stats", PGC_SUSET, PGC_S_DEFAULT, &Show_btree_build_stats, false, NULL { "show_btree_build_stats", PGC_SUSET }, &Show_btree_build_stats,
false, NULL, NULL
}, },
#endif #endif
{ {
"explain_pretty_print", PGC_USERSET, PGC_S_DEFAULT, &Explain_pretty_print, true, NULL { "explain_pretty_print", PGC_USERSET }, &Explain_pretty_print,
true, NULL, NULL
}, },
{ {
"stats_start_collector", PGC_POSTMASTER, PGC_S_DEFAULT, &pgstat_collect_startcollector, true, NULL { "stats_start_collector", PGC_POSTMASTER }, &pgstat_collect_startcollector,
true, NULL, NULL
}, },
{ {
"stats_reset_on_server_start", PGC_POSTMASTER, PGC_S_DEFAULT, &pgstat_collect_resetonpmstart, true, NULL { "stats_reset_on_server_start", PGC_POSTMASTER }, &pgstat_collect_resetonpmstart,
true, NULL, NULL
}, },
{ {
"stats_command_string", PGC_SUSET, PGC_S_DEFAULT, &pgstat_collect_querystring, false, NULL { "stats_command_string", PGC_SUSET }, &pgstat_collect_querystring,
false, NULL, NULL
}, },
{ {
"stats_row_level", PGC_SUSET, PGC_S_DEFAULT, &pgstat_collect_tuplelevel, false, NULL { "stats_row_level", PGC_SUSET }, &pgstat_collect_tuplelevel,
false, NULL, NULL
}, },
{ {
"stats_block_level", PGC_SUSET, PGC_S_DEFAULT, &pgstat_collect_blocklevel, false, NULL { "stats_block_level", PGC_SUSET }, &pgstat_collect_blocklevel,
false, NULL, NULL
}, },
{ {
"trace_notify", PGC_USERSET, PGC_S_DEFAULT, &Trace_notify, false, NULL { "trace_notify", PGC_USERSET }, &Trace_notify,
false, NULL, NULL
}, },
#ifdef LOCK_DEBUG #ifdef LOCK_DEBUG
{ {
"trace_locks", PGC_SUSET, PGC_S_DEFAULT, &Trace_locks, false, NULL { "trace_locks", PGC_SUSET }, &Trace_locks,
false, NULL, NULL
}, },
{ {
"trace_userlocks", PGC_SUSET, PGC_S_DEFAULT, &Trace_userlocks, false, NULL { "trace_userlocks", PGC_SUSET }, &Trace_userlocks,
false, NULL, NULL
}, },
{ {
"trace_lwlocks", PGC_SUSET, PGC_S_DEFAULT, &Trace_lwlocks, false, NULL { "trace_lwlocks", PGC_SUSET }, &Trace_lwlocks,
false, NULL, NULL
}, },
{ {
"debug_deadlocks", PGC_SUSET, PGC_S_DEFAULT, &Debug_deadlocks, false, NULL { "debug_deadlocks", PGC_SUSET }, &Debug_deadlocks,
false, NULL, NULL
}, },
#endif #endif
{ {
"hostname_lookup", PGC_SIGHUP, PGC_S_DEFAULT, &HostnameLookup, false, NULL { "hostname_lookup", PGC_SIGHUP }, &HostnameLookup,
false, NULL, NULL
}, },
{ {
"show_source_port", PGC_SIGHUP, PGC_S_DEFAULT, &ShowPortNumber, false, NULL { "show_source_port", PGC_SIGHUP }, &ShowPortNumber,
false, NULL, NULL
}, },
{ {
"sql_inheritance", PGC_USERSET, PGC_S_DEFAULT, &SQL_inheritance, true, NULL { "sql_inheritance", PGC_USERSET }, &SQL_inheritance,
true, NULL, NULL
}, },
{ {
"australian_timezones", PGC_USERSET, PGC_S_DEFAULT, &Australian_timezones, false, ClearDateCache { "australian_timezones", PGC_USERSET }, &Australian_timezones,
false, ClearDateCache, NULL
}, },
{ {
"fixbtree", PGC_POSTMASTER, PGC_S_DEFAULT, &FixBTree, true, NULL { "fixbtree", PGC_POSTMASTER }, &FixBTree,
true, NULL, NULL
}, },
{ {
"password_encryption", PGC_USERSET, PGC_S_DEFAULT, &Password_encryption, false, NULL { "password_encryption", PGC_USERSET }, &Password_encryption,
false, NULL, NULL
}, },
{ {
"transform_null_equals", PGC_USERSET, PGC_S_DEFAULT, &Transform_null_equals, false, NULL { "transform_null_equals", PGC_USERSET }, &Transform_null_equals,
false, NULL, NULL
}, },
{ {
NULL, 0, 0, NULL, false, NULL { NULL, 0 }, NULL, false, NULL, NULL
} }
}; };
...@@ -369,34 +493,34 @@ static struct config_int ...@@ -369,34 +493,34 @@ static struct config_int
ConfigureNamesInt[] = ConfigureNamesInt[] =
{ {
{ {
"geqo_threshold", PGC_USERSET, PGC_S_DEFAULT, &geqo_rels, { "geqo_threshold", PGC_USERSET }, &geqo_rels,
DEFAULT_GEQO_RELS, 2, INT_MAX, NULL, NULL DEFAULT_GEQO_RELS, 2, INT_MAX, NULL, NULL
}, },
{ {
"geqo_pool_size", PGC_USERSET, PGC_S_DEFAULT, &Geqo_pool_size, { "geqo_pool_size", PGC_USERSET }, &Geqo_pool_size,
DEFAULT_GEQO_POOL_SIZE, 0, MAX_GEQO_POOL_SIZE, NULL, NULL DEFAULT_GEQO_POOL_SIZE, 0, MAX_GEQO_POOL_SIZE, NULL, NULL
}, },
{ {
"geqo_effort", PGC_USERSET, PGC_S_DEFAULT, &Geqo_effort, { "geqo_effort", PGC_USERSET }, &Geqo_effort,
1, 1, INT_MAX, NULL, NULL 1, 1, INT_MAX, NULL, NULL
}, },
{ {
"geqo_generations", PGC_USERSET, PGC_S_DEFAULT, &Geqo_generations, { "geqo_generations", PGC_USERSET }, &Geqo_generations,
0, 0, INT_MAX, NULL, NULL 0, 0, INT_MAX, NULL, NULL
}, },
{ {
"geqo_random_seed", PGC_USERSET, PGC_S_DEFAULT, &Geqo_random_seed, { "geqo_random_seed", PGC_USERSET }, &Geqo_random_seed,
-1, INT_MIN, INT_MAX, NULL, NULL -1, INT_MIN, INT_MAX, NULL, NULL
}, },
{ {
"deadlock_timeout", PGC_POSTMASTER, PGC_S_DEFAULT, &DeadlockTimeout, { "deadlock_timeout", PGC_POSTMASTER }, &DeadlockTimeout,
1000, 0, INT_MAX, NULL, NULL 1000, 0, INT_MAX, NULL, NULL
}, },
#ifdef HAVE_SYSLOG #ifdef HAVE_SYSLOG
{ {
"syslog", PGC_SIGHUP, PGC_S_DEFAULT, &Use_syslog, { "syslog", PGC_SIGHUP }, &Use_syslog,
0, 0, 2, NULL, NULL 0, 0, 2, NULL, NULL
}, },
#endif #endif
...@@ -407,116 +531,116 @@ static struct config_int ...@@ -407,116 +531,116 @@ static struct config_int
* constraints here are partially unused. * constraints here are partially unused.
*/ */
{ {
"max_connections", PGC_POSTMASTER, PGC_S_DEFAULT, &MaxBackends, { "max_connections", PGC_POSTMASTER }, &MaxBackends,
DEF_MAXBACKENDS, 1, INT_MAX, NULL, NULL DEF_MAXBACKENDS, 1, INT_MAX, NULL, NULL
}, },
{ {
"shared_buffers", PGC_POSTMASTER, PGC_S_DEFAULT, &NBuffers, { "shared_buffers", PGC_POSTMASTER }, &NBuffers,
DEF_NBUFFERS, 16, INT_MAX, NULL, NULL DEF_NBUFFERS, 16, INT_MAX, NULL, NULL
}, },
{ {
"port", PGC_POSTMASTER, PGC_S_DEFAULT, &PostPortNumber, { "port", PGC_POSTMASTER }, &PostPortNumber,
DEF_PGPORT, 1, 65535, NULL, NULL DEF_PGPORT, 1, 65535, NULL, NULL
}, },
{ {
"unix_socket_permissions", PGC_POSTMASTER, PGC_S_DEFAULT, &Unix_socket_permissions, { "unix_socket_permissions", PGC_POSTMASTER }, &Unix_socket_permissions,
0777, 0000, 0777, NULL, NULL 0777, 0000, 0777, NULL, NULL
}, },
{ {
"sort_mem", PGC_USERSET, PGC_S_DEFAULT, &SortMem, { "sort_mem", PGC_USERSET }, &SortMem,
512, 4 * BLCKSZ / 1024, INT_MAX, NULL, NULL 512, 4 * BLCKSZ / 1024, INT_MAX, NULL, NULL
}, },
{ {
"vacuum_mem", PGC_USERSET, PGC_S_DEFAULT, &VacuumMem, { "vacuum_mem", PGC_USERSET }, &VacuumMem,
8192, 1024, INT_MAX, NULL, NULL 8192, 1024, INT_MAX, NULL, NULL
}, },
{ {
"max_files_per_process", PGC_BACKEND, PGC_S_DEFAULT, &max_files_per_process, { "max_files_per_process", PGC_BACKEND }, &max_files_per_process,
1000, 25, INT_MAX, NULL, NULL 1000, 25, INT_MAX, NULL, NULL
}, },
#ifdef LOCK_DEBUG #ifdef LOCK_DEBUG
{ {
"trace_lock_oidmin", PGC_SUSET, PGC_S_DEFAULT, &Trace_lock_oidmin, { "trace_lock_oidmin", PGC_SUSET }, &Trace_lock_oidmin,
BootstrapObjectIdData, 1, INT_MAX, NULL, NULL BootstrapObjectIdData, 1, INT_MAX, NULL, NULL
}, },
{ {
"trace_lock_table", PGC_SUSET, PGC_S_DEFAULT, &Trace_lock_table, { "trace_lock_table", PGC_SUSET }, &Trace_lock_table,
0, 0, INT_MAX, NULL, NULL 0, 0, INT_MAX, NULL, NULL
}, },
#endif #endif
{ {
"max_expr_depth", PGC_USERSET, PGC_S_DEFAULT, &max_expr_depth, { "max_expr_depth", PGC_USERSET }, &max_expr_depth,
DEFAULT_MAX_EXPR_DEPTH, 10, INT_MAX, NULL, NULL DEFAULT_MAX_EXPR_DEPTH, 10, INT_MAX, NULL, NULL
}, },
{ {
"max_fsm_relations", PGC_POSTMASTER, PGC_S_DEFAULT, &MaxFSMRelations, { "max_fsm_relations", PGC_POSTMASTER }, &MaxFSMRelations,
100, 10, INT_MAX, NULL, NULL 100, 10, INT_MAX, NULL, NULL
}, },
{ {
"max_fsm_pages", PGC_POSTMASTER, PGC_S_DEFAULT, &MaxFSMPages, { "max_fsm_pages", PGC_POSTMASTER }, &MaxFSMPages,
10000, 1000, INT_MAX, NULL, NULL 10000, 1000, INT_MAX, NULL, NULL
}, },
{ {
"max_locks_per_transaction", PGC_POSTMASTER, PGC_S_DEFAULT, &max_locks_per_xact, { "max_locks_per_transaction", PGC_POSTMASTER }, &max_locks_per_xact,
64, 10, INT_MAX, NULL, NULL 64, 10, INT_MAX, NULL, NULL
}, },
{ {
"authentication_timeout", PGC_SIGHUP, PGC_S_DEFAULT, &AuthenticationTimeout, { "authentication_timeout", PGC_SIGHUP }, &AuthenticationTimeout,
60, 1, 600, NULL, NULL 60, 1, 600, NULL, NULL
}, },
{ {
"pre_auth_delay", PGC_SIGHUP, PGC_S_DEFAULT, &PreAuthDelay, { "pre_auth_delay", PGC_SIGHUP }, &PreAuthDelay,
0, 0, 60, NULL, NULL 0, 0, 60, NULL, NULL
}, },
{ {
"checkpoint_segments", PGC_SIGHUP, PGC_S_DEFAULT, &CheckPointSegments, { "checkpoint_segments", PGC_SIGHUP }, &CheckPointSegments,
3, 1, INT_MAX, NULL, NULL 3, 1, INT_MAX, NULL, NULL
}, },
{ {
"checkpoint_timeout", PGC_SIGHUP, PGC_S_DEFAULT, &CheckPointTimeout, { "checkpoint_timeout", PGC_SIGHUP }, &CheckPointTimeout,
300, 30, 3600, NULL, NULL 300, 30, 3600, NULL, NULL
}, },
{ {
"wal_buffers", PGC_POSTMASTER, PGC_S_DEFAULT, &XLOGbuffers, { "wal_buffers", PGC_POSTMASTER }, &XLOGbuffers,
8, 4, INT_MAX, NULL, NULL 8, 4, INT_MAX, NULL, NULL
}, },
{ {
"wal_files", PGC_SIGHUP, PGC_S_DEFAULT, &XLOGfiles, { "wal_files", PGC_SIGHUP }, &XLOGfiles,
0, 0, 64, NULL, NULL 0, 0, 64, NULL, NULL
}, },
{ {
"wal_debug", PGC_SUSET, PGC_S_DEFAULT, &XLOG_DEBUG, { "wal_debug", PGC_SUSET }, &XLOG_DEBUG,
0, 0, 16, NULL, NULL 0, 0, 16, NULL, NULL
}, },
{ {
"commit_delay", PGC_USERSET, PGC_S_DEFAULT, &CommitDelay, { "commit_delay", PGC_USERSET }, &CommitDelay,
0, 0, 100000, NULL, NULL 0, 0, 100000, NULL, NULL
}, },
{ {
"commit_siblings", PGC_USERSET, PGC_S_DEFAULT, &CommitSiblings, { "commit_siblings", PGC_USERSET }, &CommitSiblings,
5, 1, 1000, NULL, NULL 5, 1, 1000, NULL, NULL
}, },
{ {
NULL, 0, 0, NULL, 0, 0, 0, NULL, NULL { NULL, 0 }, NULL, 0, 0, 0, NULL, NULL
} }
}; };
...@@ -525,34 +649,40 @@ static struct config_real ...@@ -525,34 +649,40 @@ static struct config_real
ConfigureNamesReal[] = ConfigureNamesReal[] =
{ {
{ {
"effective_cache_size", PGC_USERSET, PGC_S_DEFAULT, &effective_cache_size, { "effective_cache_size", PGC_USERSET }, &effective_cache_size,
DEFAULT_EFFECTIVE_CACHE_SIZE, 0, DBL_MAX, NULL, NULL DEFAULT_EFFECTIVE_CACHE_SIZE, 0, DBL_MAX, NULL, NULL
}, },
{ {
"random_page_cost", PGC_USERSET, PGC_S_DEFAULT, &random_page_cost, { "random_page_cost", PGC_USERSET }, &random_page_cost,
DEFAULT_RANDOM_PAGE_COST, 0, DBL_MAX, NULL, NULL DEFAULT_RANDOM_PAGE_COST, 0, DBL_MAX, NULL, NULL
}, },
{ {
"cpu_tuple_cost", PGC_USERSET, PGC_S_DEFAULT, &cpu_tuple_cost, { "cpu_tuple_cost", PGC_USERSET }, &cpu_tuple_cost,
DEFAULT_CPU_TUPLE_COST, 0, DBL_MAX, NULL, NULL DEFAULT_CPU_TUPLE_COST, 0, DBL_MAX, NULL, NULL
}, },
{ {
"cpu_index_tuple_cost", PGC_USERSET, PGC_S_DEFAULT, &cpu_index_tuple_cost, { "cpu_index_tuple_cost", PGC_USERSET }, &cpu_index_tuple_cost,
DEFAULT_CPU_INDEX_TUPLE_COST, 0, DBL_MAX, NULL, NULL DEFAULT_CPU_INDEX_TUPLE_COST, 0, DBL_MAX, NULL, NULL
}, },
{ {
"cpu_operator_cost", PGC_USERSET, PGC_S_DEFAULT, &cpu_operator_cost, { "cpu_operator_cost", PGC_USERSET }, &cpu_operator_cost,
DEFAULT_CPU_OPERATOR_COST, 0, DBL_MAX, NULL, NULL DEFAULT_CPU_OPERATOR_COST, 0, DBL_MAX, NULL, NULL
}, },
{ {
"geqo_selection_bias", PGC_USERSET, PGC_S_DEFAULT, &Geqo_selection_bias, { "geqo_selection_bias", PGC_USERSET }, &Geqo_selection_bias,
DEFAULT_GEQO_SELECTION_BIAS, MIN_GEQO_SELECTION_BIAS, DEFAULT_GEQO_SELECTION_BIAS, MIN_GEQO_SELECTION_BIAS,
MAX_GEQO_SELECTION_BIAS, NULL, NULL MAX_GEQO_SELECTION_BIAS, NULL, NULL
}, },
{ {
NULL, 0, 0, NULL, 0.0, 0.0, 0.0, NULL, NULL { "seed", PGC_USERSET, GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL },
&phony_random_seed,
0.5, 0.0, 1.0, assign_random_seed, show_random_seed
},
{
{ NULL, 0 }, NULL, 0.0, 0.0, 0.0, NULL, NULL
} }
}; };
...@@ -561,477 +691,1020 @@ static struct config_string ...@@ -561,477 +691,1020 @@ static struct config_string
ConfigureNamesString[] = ConfigureNamesString[] =
{ {
{ {
"client_min_messages", PGC_USERSET, PGC_S_DEFAULT, &client_min_messages_str, { "client_encoding", PGC_USERSET }, &client_encoding_string,
client_min_messages_str_default, check_client_min_messages, "SQL_ASCII", assign_client_encoding, NULL
assign_client_min_messages
}, },
{ {
"default_transaction_isolation", PGC_USERSET, PGC_S_DEFAULT, &default_iso_level_string, { "client_min_messages", PGC_USERSET }, &client_min_messages_str,
"read committed", check_defaultxactisolevel, assign_defaultxactisolevel client_min_messages_str_default, assign_client_min_messages, NULL
}, },
{ {
"dynamic_library_path", PGC_SUSET, PGC_S_DEFAULT, &Dynamic_library_path, { "DateStyle", PGC_USERSET, GUC_LIST_INPUT }, &datestyle_string,
"$libdir", NULL, NULL "ISO, US", assign_datestyle, show_datestyle
}, },
{ {
"search_path", PGC_USERSET, PGC_S_DEFAULT, &namespace_search_path, { "default_transaction_isolation", PGC_USERSET }, &default_iso_level_string,
"$user,public", check_search_path, assign_search_path "read committed", assign_defaultxactisolevel, NULL
}, },
{ {
"krb_server_keyfile", PGC_POSTMASTER, PGC_S_DEFAULT, &pg_krb_server_keyfile, { "dynamic_library_path", PGC_SUSET }, &Dynamic_library_path,
"$libdir", NULL, NULL
},
{
{ "krb_server_keyfile", PGC_POSTMASTER }, &pg_krb_server_keyfile,
PG_KRB_SRVTAB, NULL, NULL PG_KRB_SRVTAB, NULL, NULL
}, },
{ {
"lc_messages", PGC_SUSET, PGC_S_DEFAULT, &locale_messages, { "lc_messages", PGC_SUSET }, &locale_messages,
"", locale_messages_check, locale_messages_assign "", locale_messages_assign, NULL
},
{
{ "lc_monetary", PGC_USERSET }, &locale_monetary,
"", locale_monetary_assign, NULL
},
{
{ "lc_numeric", PGC_USERSET }, &locale_numeric,
"", locale_numeric_assign, NULL
},
{
{ "lc_time", PGC_USERSET }, &locale_time,
"", locale_time_assign, NULL
}, },
{ {
"lc_monetary", PGC_USERSET, PGC_S_DEFAULT, &locale_monetary, { "search_path", PGC_USERSET, GUC_LIST_INPUT | GUC_LIST_QUOTE },
"", locale_monetary_check, locale_monetary_assign &namespace_search_path,
"$user,public", assign_search_path, NULL
}, },
{ {
"lc_numeric", PGC_USERSET, PGC_S_DEFAULT, &locale_numeric, { "server_encoding", PGC_USERSET }, &server_encoding_string,
"", locale_numeric_check, locale_numeric_assign "SQL_ASCII", assign_server_encoding, show_server_encoding
}, },
{ {
"lc_time", PGC_USERSET, PGC_S_DEFAULT, &locale_time, { "server_min_messages", PGC_USERSET }, &server_min_messages_str,
"", locale_time_check, locale_time_assign server_min_messages_str_default, assign_server_min_messages, NULL
}, },
{ {
"server_min_messages", PGC_USERSET, PGC_S_DEFAULT, &server_min_messages_str, { "session_authorization", PGC_USERSET, GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL },
server_min_messages_str_default, check_server_min_messages, &session_authorization_string,
assign_server_min_messages NULL, assign_session_authorization, show_session_authorization
}, },
#ifdef HAVE_SYSLOG #ifdef HAVE_SYSLOG
{ {
"syslog_facility", PGC_POSTMASTER, PGC_S_DEFAULT, &Syslog_facility, { "syslog_facility", PGC_POSTMASTER }, &Syslog_facility,
"LOCAL0", check_facility, NULL "LOCAL0", assign_facility, NULL
}, },
{ {
"syslog_ident", PGC_POSTMASTER, PGC_S_DEFAULT, &Syslog_ident, { "syslog_ident", PGC_POSTMASTER }, &Syslog_ident,
"postgres", NULL, NULL "postgres", NULL, NULL
}, },
#endif #endif
{ {
"unix_socket_group", PGC_POSTMASTER, PGC_S_DEFAULT, &Unix_socket_group, { "TimeZone", PGC_USERSET }, &timezone_string,
"UNKNOWN", assign_timezone, show_timezone
},
{
{ "TRANSACTION ISOLATION LEVEL", PGC_USERSET, GUC_NO_RESET_ALL },
&XactIsoLevel_string,
NULL, assign_XactIsoLevel, show_XactIsoLevel
},
{
{ "unix_socket_group", PGC_POSTMASTER }, &Unix_socket_group,
"", NULL, NULL "", NULL, NULL
}, },
{ {
"unix_socket_directory", PGC_POSTMASTER, PGC_S_DEFAULT, &UnixSocketDir, { "unix_socket_directory", PGC_POSTMASTER }, &UnixSocketDir,
"", NULL, NULL "", NULL, NULL
}, },
{ {
"virtual_host", PGC_POSTMASTER, PGC_S_DEFAULT, &VirtualHost, { "virtual_host", PGC_POSTMASTER }, &VirtualHost,
"", NULL, NULL "", NULL, NULL
}, },
{ {
"wal_sync_method", PGC_SIGHUP, PGC_S_DEFAULT, &XLOG_sync_method, { "wal_sync_method", PGC_SIGHUP }, &XLOG_sync_method,
XLOG_sync_method_default, check_xlog_sync_method, XLOG_sync_method_default, assign_xlog_sync_method, NULL
assign_xlog_sync_method
}, },
{ {
NULL, 0, 0, NULL, NULL, NULL, NULL { NULL, 0 }, NULL, NULL, NULL, NULL
} }
}; };
/******** end of options list ********/ /******** end of options list ********/
/* /*
* Look up option NAME. If it exists, return it's data type, else * Actual lookup of variables is done through this single, sorted array.
* PGC_NONE (zero). If record is not NULL, store the description of
* the option there.
*/ */
static enum config_type static struct config_generic **guc_variables;
find_option(const char *name, struct config_generic ** record) static int num_guc_variables;
{
int i;
Assert(name);
for (i = 0; ConfigureNamesBool[i].name; i++) static bool guc_dirty; /* TRUE if need to do commit/abort work */
if (strcasecmp(ConfigureNamesBool[i].name, name) == 0)
{
if (record)
*record = (struct config_generic *) & ConfigureNamesBool[i];
return PGC_BOOL;
}
for (i = 0; ConfigureNamesInt[i].name; i++)
if (strcasecmp(ConfigureNamesInt[i].name, name) == 0)
{
if (record)
*record = (struct config_generic *) & ConfigureNamesInt[i];
return PGC_INT;
}
for (i = 0; ConfigureNamesReal[i].name; i++)
if (strcasecmp(ConfigureNamesReal[i].name, name) == 0)
{
if (record)
*record = (struct config_generic *) & ConfigureNamesReal[i];
return PGC_REAL;
}
for (i = 0; ConfigureNamesString[i].name; i++) static char *guc_string_workspace; /* for avoiding memory leaks */
if (strcasecmp(ConfigureNamesString[i].name, name) == 0)
{
if (record)
*record = (struct config_generic *) & ConfigureNamesString[i];
return PGC_STRING;
}
return PGC_NONE;
}
static int guc_var_compare(const void *a, const void *b);
static void _ShowOption(struct config_generic *record);
/* /*
* Reset all options to their specified default values. Must be called * Build the sorted array. This is split out so that it could be
* with isStartup = true at program startup. May be called later with * re-executed after startup (eg, we could allow loadable modules to
* isStartup = false to reset all resettable options. * add vars, and then we'd need to re-sort).
*/ */
void static void
ResetAllOptions(bool isStartup) build_guc_variables(void)
{ {
int num_vars = 0;
struct config_generic **guc_vars;
int i; int i;
for (i = 0; ConfigureNamesBool[i].name; i++) for (i = 0; ConfigureNamesBool[i].gen.name; i++)
{ {
struct config_bool *conf = &ConfigureNamesBool[i]; struct config_bool *conf = &ConfigureNamesBool[i];
if (isStartup || /* Rather than requiring vartype to be filled in by hand, do this: */
conf->context == PGC_SUSET || conf->context == PGC_USERSET) conf->gen.vartype = PGC_BOOL;
{ num_vars++;
if (conf->assign_hook)
(conf->assign_hook) (conf->default_val);
*conf->variable = conf->default_val;
}
} }
for (i = 0; ConfigureNamesInt[i].name; i++) for (i = 0; ConfigureNamesInt[i].gen.name; i++)
{ {
struct config_int *conf = &ConfigureNamesInt[i]; struct config_int *conf = &ConfigureNamesInt[i];
if (isStartup || conf->gen.vartype = PGC_INT;
conf->context == PGC_SUSET || conf->context == PGC_USERSET) num_vars++;
{
if (conf->assign_hook)
(conf->assign_hook) (conf->default_val);
*conf->variable = conf->default_val;
}
} }
for (i = 0; ConfigureNamesReal[i].name; i++) for (i = 0; ConfigureNamesReal[i].gen.name; i++)
{ {
struct config_real *conf = &ConfigureNamesReal[i]; struct config_real *conf = &ConfigureNamesReal[i];
if (isStartup || conf->gen.vartype = PGC_REAL;
conf->context == PGC_SUSET || conf->context == PGC_USERSET) num_vars++;
{
if (conf->assign_hook)
(conf->assign_hook) (conf->default_val);
*conf->variable = conf->default_val;
}
} }
for (i = 0; ConfigureNamesString[i].name; i++) for (i = 0; ConfigureNamesString[i].gen.name; i++)
{ {
struct config_string *conf = &ConfigureNamesString[i]; struct config_string *conf = &ConfigureNamesString[i];
if (isStartup || conf->gen.vartype = PGC_STRING;
conf->context == PGC_SUSET || conf->context == PGC_USERSET) num_vars++;
{
char *str = NULL;
if (conf->default_val == NULL &&
conf->boot_default_val)
{
str = strdup(conf->boot_default_val);
if (str == NULL)
elog(ERROR, "out of memory");
conf->default_val = str;
}
if (conf->default_val)
{
str = strdup(conf->default_val);
if (str == NULL)
elog(ERROR, "out of memory");
}
if (conf->assign_hook)
(conf->assign_hook) (str);
if (*conf->variable)
free(*conf->variable);
*conf->variable = str;
}
} }
}
guc_vars = (struct config_generic **)
malloc(num_vars * sizeof(struct config_generic *));
if (!guc_vars)
elog(PANIC, "out of memory");
num_vars = 0;
/* for (i = 0; ConfigureNamesBool[i].gen.name; i++)
* Try to interpret value as boolean value. Valid values are: true, guc_vars[num_vars++] = & ConfigureNamesBool[i].gen;
* false, yes, no, on, off, 1, 0. If the string parses okay, return
* true, else false. If result is not NULL, return the parsing result
* there.
*/
static bool
parse_bool(const char *value, bool *result)
{
size_t len = strlen(value);
if (strncasecmp(value, "true", len) == 0) for (i = 0; ConfigureNamesInt[i].gen.name; i++)
{ guc_vars[num_vars++] = & ConfigureNamesInt[i].gen;
if (result)
*result = true;
}
else if (strncasecmp(value, "false", len) == 0)
{
if (result)
*result = false;
}
else if (strncasecmp(value, "yes", len) == 0) for (i = 0; ConfigureNamesReal[i].gen.name; i++)
{ guc_vars[num_vars++] = & ConfigureNamesReal[i].gen;
if (result)
*result = true;
}
else if (strncasecmp(value, "no", len) == 0)
{
if (result)
*result = false;
}
else if (strcasecmp(value, "on") == 0) for (i = 0; ConfigureNamesString[i].gen.name; i++)
{ guc_vars[num_vars++] = & ConfigureNamesString[i].gen;
if (result)
*result = true;
}
else if (strcasecmp(value, "off") == 0)
{
if (result)
*result = false;
}
else if (strcasecmp(value, "1") == 0) qsort((void *) guc_vars, num_vars, sizeof(struct config_generic *),
{ guc_var_compare);
if (result)
*result = true;
}
else if (strcasecmp(value, "0") == 0)
{
if (result)
*result = false;
}
else if (guc_variables)
return false; free(guc_variables);
return true; guc_variables = guc_vars;
num_guc_variables = num_vars;
} }
/* /*
* Try to parse value as an integer. The accepted formats are the * Look up option NAME. If it exists, return a pointer to its record,
* usual decimal, octal, or hexadecimal formats. If the string parses * else return NULL.
* okay, return true, else false. If result is not NULL, return the
* value there.
*/ */
static bool static struct config_generic *
parse_int(const char *value, int *result) find_option(const char *name)
{ {
long val; const char **key = &name;
char *endptr; struct config_generic **res;
errno = 0; Assert(name);
val = strtol(value, &endptr, 0);
if (endptr == value || *endptr != '\0' || errno == ERANGE
#ifdef HAVE_LONG_INT_64
/* if long > 32 bits, check for overflow of int4 */
|| val != (long) ((int32) val)
#endif
)
return false;
if (result)
*result = (int) val;
return true;
}
/*
* by equating const char ** with struct config_generic *, we are
* assuming the name field is first in config_generic.
*/
res = (struct config_generic**) bsearch((void *) &key,
(void *) guc_variables,
num_guc_variables,
sizeof(struct config_generic *),
guc_var_compare);
if (res)
return *res;
return NULL;
}
/* /*
* Try to parse value as a floating point constant in the usual * comparator for qsorting and bsearching guc_variables array
* format. If the value parsed okay return true, else false. If
* result is not NULL, return the semantic value there.
*/ */
static bool static int
parse_real(const char *value, double *result) guc_var_compare(const void *a, const void *b)
{ {
double val; struct config_generic *confa = *(struct config_generic **) a;
char *endptr; struct config_generic *confb = *(struct config_generic **) b;
char namea[NAMEDATALEN];
char nameb[NAMEDATALEN];
int len,
i;
errno = 0; /*
val = strtod(value, &endptr); * The temptation to use strcasecmp() here must be resisted, because
if (endptr == value || *endptr != '\0' || errno == ERANGE) * the array ordering has to remain stable across setlocale() calls.
return false; * So, apply an ASCII-only downcasing to both names and use strcmp().
if (result) */
*result = val; len = strlen(confa->name);
return true; if (len >= NAMEDATALEN)
} len = NAMEDATALEN-1;
for (i = 0; i < len; i++)
{
char ch = confa->name[i];
if (ch >= 'A' && ch <= 'Z')
ch += 'a' - 'A';
namea[i] = ch;
}
namea[len] = '\0';
len = strlen(confb->name);
if (len >= NAMEDATALEN)
len = NAMEDATALEN-1;
for (i = 0; i < len; i++)
{
char ch = confb->name[i];
if (ch >= 'A' && ch <= 'Z')
ch += 'a' - 'A';
nameb[i] = ch;
}
nameb[len] = '\0';
return strcmp(namea, nameb);
}
/* /*
* Sets option `name' to given value. The value should be a string * Initialize GUC options during program startup.
* which is going to be parsed and converted to the appropriate data
* type. Parameter context should indicate in which context this
* function is being called so it can apply the access restrictions
* properly.
*
* If value is NULL, set the option to its default value. If the
* parameter DoIt is false then don't really set the option but do all
* the checks to see if it would work.
*
* If there is an error (non-existing option, invalid value) then an
* elog(ERROR) is thrown *unless* this is called as part of the
* configuration file re-read in the SIGHUP handler, in which case we
* simply write the error message via elog(DEBUG) and return false. In
* all other cases the function returns true. This is working around
* the deficiencies in the elog mechanism, so don't blame me.
*
* See also SetConfigOption for an external interface.
*/ */
bool void
set_config_option(const char *name, const char *value, InitializeGUCOptions(void)
GucContext context, bool DoIt, GucSource source)
{ {
struct config_generic *record; int i;
enum config_type type; char *env;
int elevel;
bool makeDefault;
if (context == PGC_SIGHUP || source == PGC_S_DEFAULT)
elevel = DEBUG1;
else if (guc_session_init)
elevel = INFO;
else
elevel = ERROR;
type = find_option(name, &record);
if (type == PGC_NONE)
{
elog(elevel, "'%s' is not a valid option name", name);
return false;
}
if (record->source > source) /*
{ * Build sorted array of all GUC variables.
elog(DEBUG2, "setting %s refused because previous source is higher", */
name); build_guc_variables();
return false;
}
makeDefault = source < PGC_S_SESSION;
/* /*
* Check if the option can be set at this time. See guc.h for the * Load all variables with their compiled-in defaults, and initialize
* precise rules. Note that we don't want to throw errors if we're in * status fields as needed.
* the SIGHUP context. In that case we just ignore the attempt. *
* Note: any errors here are reported with plain ol' printf, since we
* shouldn't assume that elog will work before we've initialized its
* config variables. An error here would be unexpected anyway...
*/ */
switch (record->context) for (i = 0; i < num_guc_variables; i++)
{ {
case PGC_POSTMASTER: struct config_generic *gconf = guc_variables[i];
if (context == PGC_SIGHUP)
return true;
if (context != PGC_POSTMASTER)
elog(ERROR, "'%s' cannot be changed after server start", name);
break;
case PGC_SIGHUP:
if (context != PGC_SIGHUP && context != PGC_POSTMASTER)
elog(ERROR, "'%s' cannot be changed now", name);
/* gconf->status = 0;
* Hmm, the idea of the SIGHUP context is "ought to be global, gconf->reset_source = PGC_S_DEFAULT;
* but can be changed after postmaster start". But there's gconf->session_source = PGC_S_DEFAULT;
* nothing that prevents a crafty administrator from sending gconf->tentative_source = PGC_S_DEFAULT;
* SIGHUP signals to individual backends only. gconf->source = PGC_S_DEFAULT;
*/
break; switch (gconf->vartype)
case PGC_BACKEND: {
if (context == PGC_SIGHUP) case PGC_BOOL:
{ {
/* struct config_bool *conf = (struct config_bool *) gconf;
* If a PGC_BACKEND parameter is changed in the config
* file, we want to accept the new value in the postmaster if (conf->assign_hook)
* (whence it will propagate to subsequently-started if (!(*conf->assign_hook) (conf->reset_val, true, false))
* backends), but ignore it in existing backends. This is fprintf(stderr, "Failed to initialize %s",
* a tad klugy, but necessary because we don't re-read the conf->gen.name);
* config file during backend start. *conf->variable = conf->reset_val;
*/ conf->session_val = conf->reset_val;
if (IsUnderPostmaster) break;
return true; }
case PGC_INT:
{
struct config_int *conf = (struct config_int *) gconf;
Assert(conf->reset_val >= conf->min);
Assert(conf->reset_val <= conf->max);
if (conf->assign_hook)
if (!(*conf->assign_hook) (conf->reset_val, true, false))
fprintf(stderr, "Failed to initialize %s",
conf->gen.name);
*conf->variable = conf->reset_val;
conf->session_val = conf->reset_val;
break;
}
case PGC_REAL:
{
struct config_real *conf = (struct config_real *) gconf;
Assert(conf->reset_val >= conf->min);
Assert(conf->reset_val <= conf->max);
if (conf->assign_hook)
if (!(*conf->assign_hook) (conf->reset_val, true, false))
fprintf(stderr, "Failed to initialize %s",
conf->gen.name);
*conf->variable = conf->reset_val;
conf->session_val = conf->reset_val;
break;
}
case PGC_STRING:
{
struct config_string *conf = (struct config_string *) gconf;
char *str;
*conf->variable = NULL;
conf->reset_val = NULL;
conf->session_val = NULL;
conf->tentative_val = NULL;
if (conf->boot_val == NULL)
{
/* Cannot set value yet */
break;
}
str = strdup(conf->boot_val);
if (str == NULL)
elog(PANIC, "out of memory");
conf->reset_val = str;
if (conf->assign_hook)
{
const char *newstr;
newstr = (*conf->assign_hook) (str, true, false);
if (newstr == NULL)
{
fprintf(stderr, "Failed to initialize %s",
conf->gen.name);
}
else if (newstr != str)
{
free(str);
/* See notes in set_config_option about casting */
str = (char *) newstr;
conf->reset_val = str;
}
}
*conf->variable = str;
conf->session_val = str;
break;
}
}
}
guc_dirty = false;
guc_string_workspace = NULL;
/*
* Prevent any attempt to override TRANSACTION ISOLATION LEVEL from
* non-interactive sources.
*/
SetConfigOption("TRANSACTION ISOLATION LEVEL", "default",
PGC_POSTMASTER, PGC_S_OVERRIDE);
/*
* For historical reasons, some GUC parameters can receive defaults
* from environment variables. Process those settings.
*/
env = getenv("PGPORT");
if (env != NULL)
SetConfigOption("port", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
env = getenv("PGDATESTYLE");
if (env != NULL)
SetConfigOption("datestyle", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
env = getenv("TZ");
if (env != NULL)
SetConfigOption("timezone", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
#ifdef MULTIBYTE
env = getenv("PGCLIENTENCODING");
if (env != NULL)
SetConfigOption("client_encoding", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
#endif
}
/*
* Reset all options to their saved default values (implements RESET ALL)
*/
void
ResetAllOptions(void)
{
int i;
for (i = 0; i < num_guc_variables; i++)
{
struct config_generic *gconf = guc_variables[i];
/* Don't reset non-SET-able values */
if (gconf->context != PGC_SUSET && gconf->context != PGC_USERSET)
continue;
/* Don't reset if special exclusion from RESET ALL */
if (gconf->flags & GUC_NO_RESET_ALL)
continue;
/* No need to reset if wasn't SET */
if (gconf->source <= PGC_S_OVERRIDE)
continue;
switch (gconf->vartype)
{
case PGC_BOOL:
{
struct config_bool *conf = (struct config_bool *) gconf;
if (conf->assign_hook)
if (!(*conf->assign_hook) (conf->reset_val, true, true))
elog(ERROR, "Failed to reset %s", conf->gen.name);
*conf->variable = conf->reset_val;
conf->tentative_val = conf->reset_val;
conf->gen.source = conf->gen.reset_source;
conf->gen.tentative_source = conf->gen.reset_source;
conf->gen.status |= GUC_HAVE_TENTATIVE;
guc_dirty = true;
break;
}
case PGC_INT:
{
struct config_int *conf = (struct config_int *) gconf;
if (conf->assign_hook)
if (!(*conf->assign_hook) (conf->reset_val, true, true))
elog(ERROR, "Failed to reset %s", conf->gen.name);
*conf->variable = conf->reset_val;
conf->tentative_val = conf->reset_val;
conf->gen.source = conf->gen.reset_source;
conf->gen.tentative_source = conf->gen.reset_source;
conf->gen.status |= GUC_HAVE_TENTATIVE;
guc_dirty = true;
break;
}
case PGC_REAL:
{
struct config_real *conf = (struct config_real *) gconf;
if (conf->assign_hook)
if (!(*conf->assign_hook) (conf->reset_val, true, true))
elog(ERROR, "Failed to reset %s", conf->gen.name);
*conf->variable = conf->reset_val;
conf->tentative_val = conf->reset_val;
conf->gen.source = conf->gen.reset_source;
conf->gen.tentative_source = conf->gen.reset_source;
conf->gen.status |= GUC_HAVE_TENTATIVE;
guc_dirty = true;
break;
}
case PGC_STRING:
{
struct config_string *conf = (struct config_string *) gconf;
char *str;
if (conf->reset_val == NULL)
{
/* Nothing to reset to, as yet; so do nothing */
break;
}
str = strdup(conf->reset_val);
if (str == NULL)
elog(ERROR, "out of memory");
/*
* Remember string in workspace, so that we can free it
* and avoid a permanent memory leak if hook elogs.
*/
if (guc_string_workspace)
free(guc_string_workspace);
guc_string_workspace = str;
if (conf->assign_hook)
{
const char *newstr;
newstr = (*conf->assign_hook) (str, true, true);
if (newstr == NULL)
elog(ERROR, "Failed to reset %s", conf->gen.name);
else if (newstr != str)
{
free(str);
/* See notes in set_config_option about casting */
str = (char *) newstr;
}
}
guc_string_workspace = NULL;
SET_STRING_VARIABLE(conf, str);
SET_STRING_TENTATIVE_VAL(conf, str);
conf->gen.source = conf->gen.reset_source;
conf->gen.tentative_source = conf->gen.reset_source;
conf->gen.status |= GUC_HAVE_TENTATIVE;
guc_dirty = true;
break;
}
}
}
}
/*
* Do GUC processing at transaction commit or abort.
*/
void
AtEOXact_GUC(bool isCommit)
{
int i;
/* Quick exit if nothing's changed in this transaction */
if (!guc_dirty)
return;
/* Prevent memory leak if elog during an assign_hook */
if (guc_string_workspace)
{
free(guc_string_workspace);
guc_string_workspace = NULL;
}
for (i = 0; i < num_guc_variables; i++)
{
struct config_generic *gconf = guc_variables[i];
/* Skip if nothing's happened to this var in this transaction */
if (gconf->status == 0)
continue;
switch (gconf->vartype)
{
case PGC_BOOL:
{
struct config_bool *conf = (struct config_bool *) gconf;
if (isCommit && (conf->gen.status & GUC_HAVE_TENTATIVE))
{
conf->session_val = conf->tentative_val;
conf->gen.session_source = conf->gen.tentative_source;
}
if (*conf->variable != conf->session_val)
{
if (conf->assign_hook)
if (!(*conf->assign_hook) (conf->session_val,
true, false))
elog(LOG, "Failed to commit %s", conf->gen.name);
*conf->variable = conf->session_val;
}
conf->gen.source = conf->gen.session_source;
conf->gen.status = 0;
break;
}
case PGC_INT:
{
struct config_int *conf = (struct config_int *) gconf;
if (isCommit && (conf->gen.status & GUC_HAVE_TENTATIVE))
{
conf->session_val = conf->tentative_val;
conf->gen.session_source = conf->gen.tentative_source;
}
if (*conf->variable != conf->session_val)
{
if (conf->assign_hook)
if (!(*conf->assign_hook) (conf->session_val,
true, false))
elog(LOG, "Failed to commit %s", conf->gen.name);
*conf->variable = conf->session_val;
}
conf->gen.source = conf->gen.session_source;
conf->gen.status = 0;
break;
}
case PGC_REAL:
{
struct config_real *conf = (struct config_real *) gconf;
if (isCommit && (conf->gen.status & GUC_HAVE_TENTATIVE))
{
conf->session_val = conf->tentative_val;
conf->gen.session_source = conf->gen.tentative_source;
}
if (*conf->variable != conf->session_val)
{
if (conf->assign_hook)
if (!(*conf->assign_hook) (conf->session_val,
true, false))
elog(LOG, "Failed to commit %s", conf->gen.name);
*conf->variable = conf->session_val;
}
conf->gen.source = conf->gen.session_source;
conf->gen.status = 0;
break;
}
case PGC_STRING:
{
struct config_string *conf = (struct config_string *) gconf;
if (isCommit && (conf->gen.status & GUC_HAVE_TENTATIVE))
{
SET_STRING_SESSION_VAL(conf, conf->tentative_val);
conf->gen.session_source = conf->gen.tentative_source;
conf->tentative_val = NULL; /* transfer ownership */
}
else
{
SET_STRING_TENTATIVE_VAL(conf, NULL);
}
if (*conf->variable != conf->session_val)
{
char *str = conf->session_val;
if (conf->assign_hook)
{
const char *newstr;
newstr = (*conf->assign_hook) (str, true, false);
if (newstr == NULL)
elog(LOG, "Failed to commit %s", conf->gen.name);
else if (newstr != str)
{
/* See notes in set_config_option about casting */
str = (char *) newstr;
SET_STRING_SESSION_VAL(conf, str);
}
}
SET_STRING_VARIABLE(conf, str);
}
conf->gen.source = conf->gen.session_source;
conf->gen.status = 0;
break;
}
}
}
guc_dirty = false;
}
/*
* Try to interpret value as boolean value. Valid values are: true,
* false, yes, no, on, off, 1, 0. If the string parses okay, return
* true, else false. If result is not NULL, return the parsing result
* there.
*/
static bool
parse_bool(const char *value, bool *result)
{
size_t len = strlen(value);
if (strncasecmp(value, "true", len) == 0)
{
if (result)
*result = true;
}
else if (strncasecmp(value, "false", len) == 0)
{
if (result)
*result = false;
}
else if (strncasecmp(value, "yes", len) == 0)
{
if (result)
*result = true;
}
else if (strncasecmp(value, "no", len) == 0)
{
if (result)
*result = false;
}
else if (strcasecmp(value, "on") == 0)
{
if (result)
*result = true;
}
else if (strcasecmp(value, "off") == 0)
{
if (result)
*result = false;
}
else if (strcasecmp(value, "1") == 0)
{
if (result)
*result = true;
}
else if (strcasecmp(value, "0") == 0)
{
if (result)
*result = false;
}
else
return false;
return true;
}
/*
* Try to parse value as an integer. The accepted formats are the
* usual decimal, octal, or hexadecimal formats. If the string parses
* okay, return true, else false. If result is not NULL, return the
* value there.
*/
static bool
parse_int(const char *value, int *result)
{
long val;
char *endptr;
errno = 0;
val = strtol(value, &endptr, 0);
if (endptr == value || *endptr != '\0' || errno == ERANGE
#ifdef HAVE_LONG_INT_64
/* if long > 32 bits, check for overflow of int4 */
|| val != (long) ((int32) val)
#endif
)
return false;
if (result)
*result = (int) val;
return true;
}
/*
* Try to parse value as a floating point constant in the usual
* format. If the value parsed okay return true, else false. If
* result is not NULL, return the semantic value there.
*/
static bool
parse_real(const char *value, double *result)
{
double val;
char *endptr;
errno = 0;
val = strtod(value, &endptr);
if (endptr == value || *endptr != '\0' || errno == ERANGE)
return false;
if (result)
*result = val;
return true;
}
/*
* Sets option `name' to given value. The value should be a string
* which is going to be parsed and converted to the appropriate data
* type. The context and source parameters indicate in which context this
* function is being called so it can apply the access restrictions
* properly.
*
* If value is NULL, set the option to its default value. If the
* parameter DoIt is false then don't really set the option but do all
* the checks to see if it would work.
*
* If there is an error (non-existing option, invalid value) then an
* elog(ERROR) is thrown *unless* this is called in a context where we
* don't want to elog (currently, startup or SIGHUP config file reread).
* In that case we write a suitable error message via elog(DEBUG) and
* return false. This is working around the deficiencies in the elog
* mechanism, so don't blame me. In all other cases, the function
* returns true, including cases where the input is valid but we chose
* not to apply it because of context or source-priority considerations.
*
* See also SetConfigOption for an external interface.
*/
bool
set_config_option(const char *name, const char *value,
GucContext context, GucSource source,
bool isLocal, bool DoIt)
{
struct config_generic *record;
int elevel;
bool interactive;
bool makeDefault;
if (context == PGC_SIGHUP || source == PGC_S_DEFAULT)
elevel = DEBUG1;
else if (source == PGC_S_DATABASE || source == PGC_S_USER)
elevel = INFO;
else
elevel = ERROR;
record = find_option(name);
if (record == NULL)
{
elog(elevel, "'%s' is not a valid option name", name);
return false;
}
/*
* Check if the option can be set at this time. See guc.h for the
* precise rules. Note that we don't want to throw errors if we're in
* the SIGHUP context. In that case we just ignore the attempt and
* return true.
*/
switch (record->context)
{
case PGC_POSTMASTER:
if (context == PGC_SIGHUP)
return true;
if (context != PGC_POSTMASTER)
{
elog(elevel, "'%s' cannot be changed after server start",
name);
return false;
}
break;
case PGC_SIGHUP:
if (context != PGC_SIGHUP && context != PGC_POSTMASTER)
{
elog(elevel, "'%s' cannot be changed now", name);
return false;
}
/*
* Hmm, the idea of the SIGHUP context is "ought to be global,
* but can be changed after postmaster start". But there's
* nothing that prevents a crafty administrator from sending
* SIGHUP signals to individual backends only.
*/
break;
case PGC_BACKEND:
if (context == PGC_SIGHUP)
{
/*
* If a PGC_BACKEND parameter is changed in the config
* file, we want to accept the new value in the postmaster
* (whence it will propagate to subsequently-started
* backends), but ignore it in existing backends. This is
* a tad klugy, but necessary because we don't re-read the
* config file during backend start.
*/
if (IsUnderPostmaster)
return true;
}
else if (context != PGC_BACKEND && context != PGC_POSTMASTER)
{
elog(elevel, "'%s' cannot be set after connection start",
name);
return false;
}
break;
case PGC_SUSET:
if (context == PGC_USERSET || context == PGC_BACKEND)
{
elog(elevel, "'%s': permission denied", name);
return false;
} }
else if (context != PGC_BACKEND && context != PGC_POSTMASTER)
elog(ERROR, "'%s' cannot be set after connection start", name);
break;
case PGC_SUSET:
if (context == PGC_USERSET || context == PGC_BACKEND)
elog(ERROR, "permission denied");
break; break;
case PGC_USERSET: case PGC_USERSET:
/* always okay */ /* always okay */
break; break;
} }
interactive = (source >= PGC_S_SESSION);
makeDefault = (source <= PGC_S_OVERRIDE) && (value != NULL);
/*
* Ignore attempted set if overridden by previously processed setting.
* However, if DoIt is false then plow ahead anyway since we are trying
* to find out if the value is potentially good, not actually use it.
* Also keep going if makeDefault is true, since we may want to set
* the reset/session values even if we can't set the variable itself.
*/
if (record->source > source)
{
if (DoIt && !makeDefault)
{
elog(DEBUG2, "setting %s ignored because previous source is higher",
name);
return true;
}
DoIt = false; /* we won't change the variable itself */
}
/* /*
* Evaluate value and set variable * Evaluate value and set variable
*/ */
switch (type) switch (record->vartype)
{ {
case PGC_BOOL: case PGC_BOOL:
{ {
struct config_bool *conf = (struct config_bool *) record; struct config_bool *conf = (struct config_bool *) record;
bool newval;
if (value) if (value)
{ {
bool boolval; if (!parse_bool(value, &newval))
{
elog(elevel, "option '%s' requires a boolean value",
name);
return false;
}
}
else
{
newval = conf->reset_val;
source = conf->gen.reset_source;
}
if (!parse_bool(value, &boolval)) if (conf->assign_hook)
if (!(*conf->assign_hook) (newval, DoIt, interactive))
{ {
elog(elevel, "option '%s' requires a boolean value", name); elog(elevel, "invalid value for option '%s': %d",
name, (int) newval);
return false; return false;
} }
/* no parse_hook needed for booleans */
if (DoIt || makeDefault)
{
if (DoIt) if (DoIt)
{ {
if (conf->assign_hook) *conf->variable = newval;
(conf->assign_hook) (boolval); conf->gen.source = source;
*conf->variable = boolval; }
if (makeDefault) if (makeDefault)
conf->default_val = boolval; {
conf->source = source; if (conf->gen.reset_source <= source)
{
conf->reset_val = newval;
conf->gen.reset_source = source;
}
if (conf->gen.session_source <= source)
{
conf->session_val = newval;
conf->gen.session_source = source;
}
}
else if (isLocal)
{
conf->gen.status |= GUC_HAVE_LOCAL;
guc_dirty = true;
}
else
{
conf->tentative_val = newval;
conf->gen.tentative_source = source;
conf->gen.status |= GUC_HAVE_TENTATIVE;
guc_dirty = true;
} }
}
else if (DoIt)
{
if (conf->assign_hook)
(conf->assign_hook) (conf->default_val);
*conf->variable = conf->default_val;
} }
break; break;
} }
...@@ -1039,44 +1712,70 @@ set_config_option(const char *name, const char *value, ...@@ -1039,44 +1712,70 @@ set_config_option(const char *name, const char *value,
case PGC_INT: case PGC_INT:
{ {
struct config_int *conf = (struct config_int *) record; struct config_int *conf = (struct config_int *) record;
int newval;
if (value) if (value)
{ {
int intval; if (!parse_int(value, &newval))
if (!parse_int(value, &intval))
{ {
elog(elevel, "option '%s' expects an integer value", name); elog(elevel, "option '%s' expects an integer value",
name);
return false; return false;
} }
if (intval < conf->min || intval > conf->max) if (newval < conf->min || newval > conf->max)
{ {
elog(elevel, "option '%s' value %d is outside" elog(elevel, "option '%s' value %d is outside"
" of permissible range [%d .. %d]", " of permissible range [%d .. %d]",
name, intval, conf->min, conf->max); name, newval, conf->min, conf->max);
return false; return false;
} }
if (conf->parse_hook && !(conf->parse_hook) (intval)) }
else
{
newval = conf->reset_val;
source = conf->gen.reset_source;
}
if (conf->assign_hook)
if (!(*conf->assign_hook) (newval, DoIt, interactive))
{ {
elog(elevel, "invalid value for option '%s': %d", elog(elevel, "invalid value for option '%s': %d",
name, intval); name, newval);
return false; return false;
} }
if (DoIt || makeDefault)
{
if (DoIt) if (DoIt)
{ {
if (conf->assign_hook) *conf->variable = newval;
(conf->assign_hook) (intval); conf->gen.source = source;
*conf->variable = intval; }
if (makeDefault) if (makeDefault)
conf->default_val = intval; {
conf->source = source; if (conf->gen.reset_source <= source)
{
conf->reset_val = newval;
conf->gen.reset_source = source;
}
if (conf->gen.session_source <= source)
{
conf->session_val = newval;
conf->gen.session_source = source;
}
}
else if (isLocal)
{
conf->gen.status |= GUC_HAVE_LOCAL;
guc_dirty = true;
}
else
{
conf->tentative_val = newval;
conf->gen.tentative_source = source;
conf->gen.status |= GUC_HAVE_TENTATIVE;
guc_dirty = true;
} }
}
else if (DoIt)
{
if (conf->assign_hook)
(conf->assign_hook) (conf->default_val);
*conf->variable = conf->default_val;
} }
break; break;
} }
...@@ -1084,44 +1783,70 @@ set_config_option(const char *name, const char *value, ...@@ -1084,44 +1783,70 @@ set_config_option(const char *name, const char *value,
case PGC_REAL: case PGC_REAL:
{ {
struct config_real *conf = (struct config_real *) record; struct config_real *conf = (struct config_real *) record;
double newval;
if (value) if (value)
{ {
double dval; if (!parse_real(value, &newval))
if (!parse_real(value, &dval))
{ {
elog(elevel, "option '%s' expects a real number", name); elog(elevel, "option '%s' expects a real number",
name);
return false; return false;
} }
if (dval < conf->min || dval > conf->max) if (newval < conf->min || newval > conf->max)
{ {
elog(elevel, "option '%s' value %g is outside" elog(elevel, "option '%s' value %g is outside"
" of permissible range [%g .. %g]", " of permissible range [%g .. %g]",
name, dval, conf->min, conf->max); name, newval, conf->min, conf->max);
return false; return false;
} }
if (conf->parse_hook && !(conf->parse_hook) (dval)) }
else
{
newval = conf->reset_val;
source = conf->gen.reset_source;
}
if (conf->assign_hook)
if (!(*conf->assign_hook) (newval, DoIt, interactive))
{ {
elog(elevel, "invalid value for option '%s': %g", elog(elevel, "invalid value for option '%s': %g",
name, dval); name, newval);
return false; return false;
} }
if (DoIt || makeDefault)
{
if (DoIt) if (DoIt)
{ {
if (conf->assign_hook) *conf->variable = newval;
(conf->assign_hook) (dval); conf->gen.source = source;
*conf->variable = dval; }
if (makeDefault) if (makeDefault)
conf->default_val = dval; {
conf->source = source; if (conf->gen.reset_source <= source)
{
conf->reset_val = newval;
conf->gen.reset_source = source;
}
if (conf->gen.session_source <= source)
{
conf->session_val = newval;
conf->gen.session_source = source;
}
}
else if (isLocal)
{
conf->gen.status |= GUC_HAVE_LOCAL;
guc_dirty = true;
}
else
{
conf->tentative_val = newval;
conf->gen.tentative_source = source;
conf->gen.status |= GUC_HAVE_TENTATIVE;
guc_dirty = true;
} }
}
else if (DoIt)
{
if (conf->assign_hook)
(conf->assign_hook) (conf->default_val);
*conf->variable = conf->default_val;
} }
break; break;
} }
...@@ -1129,76 +1854,118 @@ set_config_option(const char *name, const char *value, ...@@ -1129,76 +1854,118 @@ set_config_option(const char *name, const char *value,
case PGC_STRING: case PGC_STRING:
{ {
struct config_string *conf = (struct config_string *) record; struct config_string *conf = (struct config_string *) record;
char *newval;
if (value) if (value)
{ {
if (conf->parse_hook && !(conf->parse_hook) (value)) newval = strdup(value);
if (newval == NULL)
{
elog(elevel, "out of memory");
return false;
}
}
else if (conf->reset_val)
{
newval = strdup(conf->reset_val);
if (newval == NULL)
{
elog(elevel, "out of memory");
return false;
}
source = conf->gen.reset_source;
}
else
{
/* Nothing to reset to, as yet; so do nothing */
break;
}
/*
* Remember string in workspace, so that we can free it
* and avoid a permanent memory leak if hook elogs.
*/
if (guc_string_workspace)
free(guc_string_workspace);
guc_string_workspace = newval;
if (conf->assign_hook)
{
const char *hookresult;
hookresult = (*conf->assign_hook) (newval,
DoIt, interactive);
guc_string_workspace = NULL;
if (hookresult == NULL)
{ {
free(newval);
elog(elevel, "invalid value for option '%s': '%s'", elog(elevel, "invalid value for option '%s': '%s'",
name, value); name, value ? value : "");
return false; return false;
} }
if (DoIt) else if (hookresult != newval)
{ {
char *str; free(newval);
/*
* Having to cast away const here is annoying, but the
* alternative is to declare assign_hooks as returning
* char*, which would mean they'd have to cast away
* const, or as both taking and returning char*, which
* doesn't seem attractive either --- we don't want
* them to scribble on the passed str.
*/
newval = (char *) hookresult;
}
}
guc_string_workspace = NULL;
str = strdup(value); if (DoIt || makeDefault)
if (str == NULL) {
if (DoIt)
{
SET_STRING_VARIABLE(conf, newval);
conf->gen.source = source;
}
if (makeDefault)
{
if (conf->gen.reset_source <= source)
{ {
elog(elevel, "out of memory"); SET_STRING_RESET_VAL(conf, newval);
return false; conf->gen.reset_source = source;
} }
if (conf->assign_hook) if (conf->gen.session_source <= source)
(conf->assign_hook) (str);
if (*conf->variable)
free(*conf->variable);
*conf->variable = str;
if (makeDefault)
{ {
str = strdup(value); SET_STRING_SESSION_VAL(conf, newval);
if (str == NULL) conf->gen.session_source = source;
{
elog(elevel, "out of memory");
return false;
}
if (conf->default_val)
free(conf->default_val);
conf->default_val = str;
} }
conf->source = source; /* Perhaps we didn't install newval anywhere */
if (newval != *conf->variable &&
newval != conf->session_val &&
newval != conf->reset_val)
free(newval);
} }
} else if (isLocal)
else if (DoIt)
{
char *str;
if (!conf->default_val && conf->boot_default_val)
{ {
str = strdup(conf->boot_default_val); conf->gen.status |= GUC_HAVE_LOCAL;
if (str == NULL) guc_dirty = true;
{
elog(elevel, "out of memory");
return false;
}
conf->default_val = str;
} }
str = strdup(conf->default_val); else
if (str == NULL)
{ {
elog(elevel, "out of memory"); SET_STRING_TENTATIVE_VAL(conf, newval);
return false; conf->gen.tentative_source = source;
conf->gen.status |= GUC_HAVE_TENTATIVE;
guc_dirty = true;
} }
if (conf->assign_hook) }
(conf->assign_hook) (str); else
if (*conf->variable) {
free(*conf->variable); free(newval);
*conf->variable = str;
} }
break; break;
} }
default:;
} }
return true; return true;
} }
...@@ -1206,21 +1973,21 @@ set_config_option(const char *name, const char *value, ...@@ -1206,21 +1973,21 @@ set_config_option(const char *name, const char *value,
/* /*
* Set a config option to the given value. See also set_config_option, * Set a config option to the given value. See also set_config_option,
* this is just the wrapper to be called from the outside. * this is just the wrapper to be called from outside GUC. NB: this
* is used only for non-transactional operations.
*/ */
void void
SetConfigOption(const char *name, const char *value, SetConfigOption(const char *name, const char *value,
GucContext context, GucSource source) GucContext context, GucSource source)
{ {
(void) set_config_option(name, value, context, true, source); (void) set_config_option(name, value, context, source, false, true);
} }
/* /*
* This is more or less the SHOW command. It returns a string with the * Fetch the current value of the option `name'. If the option doesn't exist,
* value of the option `name'. If the option doesn't exist, throw an * throw an elog and don't return.
* elog and don't return.
* *
* The string is *not* allocated for modification and is really only * The string is *not* allocated for modification and is really only
* valid until the next call to configuration related functions. * valid until the next call to configuration related functions.
...@@ -1230,13 +1997,12 @@ GetConfigOption(const char *name) ...@@ -1230,13 +1997,12 @@ GetConfigOption(const char *name)
{ {
struct config_generic *record; struct config_generic *record;
static char buffer[256]; static char buffer[256];
enum config_type opttype;
opttype = find_option(name, &record); record = find_option(name);
if (opttype == PGC_NONE) if (record == NULL)
elog(ERROR, "Option '%s' is not recognized", name); elog(ERROR, "Option '%s' is not recognized", name);
switch (opttype) switch (record->vartype)
{ {
case PGC_BOOL: case PGC_BOOL:
return *((struct config_bool *) record)->variable ? "on" : "off"; return *((struct config_bool *) record)->variable ? "on" : "off";
...@@ -1253,68 +2019,298 @@ GetConfigOption(const char *name) ...@@ -1253,68 +2019,298 @@ GetConfigOption(const char *name)
case PGC_STRING: case PGC_STRING:
return *((struct config_string *) record)->variable; return *((struct config_string *) record)->variable;
default:
;
} }
return NULL; return NULL;
} }
static void /*
_ShowOption(enum config_type opttype, struct config_generic * record) * Get the RESET value associated with the given option.
*/
const char *
GetConfigOptionResetString(const char *name)
{ {
char buffer[256]; struct config_generic *record;
char *val; static char buffer[256];
switch (opttype) record = find_option(name);
if (record == NULL)
elog(ERROR, "Option '%s' is not recognized", name);
switch (record->vartype)
{ {
case PGC_BOOL: case PGC_BOOL:
val = *((struct config_bool *) record)->variable ? "on" : "off"; return ((struct config_bool *) record)->reset_val ? "on" : "off";
break;
case PGC_INT: case PGC_INT:
snprintf(buffer, sizeof(buffer), "%d", snprintf(buffer, sizeof(buffer), "%d",
*((struct config_int *) record)->variable); ((struct config_int *) record)->reset_val);
val = buffer; return buffer;
break;
case PGC_REAL: case PGC_REAL:
snprintf(buffer, sizeof(buffer), "%g", snprintf(buffer, sizeof(buffer), "%g",
*((struct config_real *) record)->variable); ((struct config_real *) record)->reset_val);
val = buffer; return buffer;
break;
case PGC_STRING: case PGC_STRING:
val = strlen(*((struct config_string *) record)->variable) != 0 ? return ((struct config_string *) record)->reset_val;
*((struct config_string *) record)->variable : "unset"; }
break; return NULL;
}
default:
val = "???";
/*
* flatten_set_variable_args
* Given a parsenode List as emitted by the grammar for SET,
* convert to the flat string representation used by GUC.
*
* We need to be told the name of the variable the args are for, because
* the flattening rules vary (ugh).
*
* The result is NULL if input is NIL (ie, SET ... TO DEFAULT), otherwise
* a palloc'd string.
*/
char *
flatten_set_variable_args(const char *name, List *args)
{
struct config_generic *record;
int flags;
StringInfoData buf;
List *l;
/* Fast path if just DEFAULT */
if (args == NIL)
return NULL;
record = find_option(name);
if (record == NULL)
flags = 0; /* default assumptions */
else
flags = record->flags;
/* Complain if list input and non-list variable */
if ((flags & GUC_LIST_INPUT) == 0 &&
lnext(args) != NIL)
elog(ERROR, "SET %s takes only one argument", name);
initStringInfo(&buf);
foreach(l, args)
{
A_Const *arg = (A_Const *) lfirst(l);
char *val;
if (l != args)
appendStringInfo(&buf, ", ");
if (!IsA(arg, A_Const))
elog(ERROR, "flatten_set_variable_args: unexpected input");
switch (nodeTag(&arg->val))
{
case T_Integer:
appendStringInfo(&buf, "%ld", intVal(&arg->val));
break;
case T_Float:
/* represented as a string, so just copy it */
appendStringInfo(&buf, "%s", strVal(&arg->val));
break;
case T_String:
val = strVal(&arg->val);
if (arg->typename != NULL)
{
/*
* Must be a ConstInterval argument for TIME ZONE.
* Coerce to interval and back to normalize the value
* and account for any typmod.
*/
Datum interval;
char *intervalout;
interval =
DirectFunctionCall3(interval_in,
CStringGetDatum(val),
ObjectIdGetDatum(InvalidOid),
Int32GetDatum(arg->typename->typmod));
intervalout =
DatumGetCString(DirectFunctionCall3(interval_out,
interval,
ObjectIdGetDatum(InvalidOid),
Int32GetDatum(-1)));
appendStringInfo(&buf, "INTERVAL '%s'", intervalout);
}
else
{
/*
* Plain string literal or identifier. For quote mode,
* quote it if it's not a vanilla identifier.
*/
if (flags & GUC_LIST_QUOTE)
appendStringInfo(&buf, "%s", quote_identifier(val));
else
appendStringInfo(&buf, "%s", val);
}
break;
default:
elog(ERROR, "flatten_set_variable_args: unexpected input");
break;
}
} }
elog(INFO, "%s is %s", record->name, val);
return buf.data;
}
/*
* SET command
*/
void
SetPGVariable(const char *name, List *args, bool is_local)
{
char *argstring = flatten_set_variable_args(name, args);
/* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
set_config_option(name,
argstring,
(superuser() ? PGC_SUSET : PGC_USERSET),
PGC_S_SESSION,
is_local,
true);
}
/*
* SHOW command
*/
void
GetPGVariable(const char *name)
{
if (strcasecmp(name, "all") == 0)
ShowAllGUCConfig();
else
ShowGUCConfigOption(name);
}
/*
* RESET command
*/
void
ResetPGVariable(const char *name)
{
if (strcasecmp(name, "all") == 0)
ResetAllOptions();
else
set_config_option(name,
NULL,
(superuser() ? PGC_SUSET : PGC_USERSET),
PGC_S_SESSION,
false,
true);
}
/*
* SHOW command
*/
void
ShowGUCConfigOption(const char *name)
{
struct config_generic *record;
record = find_option(name);
if (record == NULL)
elog(ERROR, "Option '%s' is not recognized", name);
_ShowOption(record);
} }
/*
* SHOW ALL command
*/
void void
ShowAllGUCConfig(void) ShowAllGUCConfig(void)
{ {
int i; int i;
for (i = 0; ConfigureNamesBool[i].name; i++) for (i = 0; i < num_guc_variables; i++)
_ShowOption(PGC_BOOL, (struct config_generic *) & ConfigureNamesBool[i]); {
struct config_generic *conf = guc_variables[i];
if ((conf->flags & GUC_NO_SHOW_ALL) == 0)
_ShowOption(conf);
}
}
for (i = 0; ConfigureNamesInt[i].name; i++) static void
_ShowOption(PGC_INT, (struct config_generic *) & ConfigureNamesInt[i]); _ShowOption(struct config_generic *record)
{
char buffer[256];
const char *val;
for (i = 0; ConfigureNamesReal[i].name; i++) switch (record->vartype)
_ShowOption(PGC_REAL, (struct config_generic *) & ConfigureNamesReal[i]); {
case PGC_BOOL:
{
struct config_bool *conf = (struct config_bool *) record;
for (i = 0; ConfigureNamesString[i].name; i++) if (conf->show_hook)
_ShowOption(PGC_STRING, (struct config_generic *) & ConfigureNamesString[i]); val = (*conf->show_hook) ();
} else
val = *conf->variable ? "on" : "off";
}
break;
case PGC_INT:
{
struct config_int *conf = (struct config_int *) record;
if (conf->show_hook)
val = (*conf->show_hook) ();
else
{
snprintf(buffer, sizeof(buffer), "%d",
*conf->variable);
val = buffer;
}
}
break;
case PGC_REAL:
{
struct config_real *conf = (struct config_real *) record;
if (conf->show_hook)
val = (*conf->show_hook) ();
else
{
snprintf(buffer, sizeof(buffer), "%g",
*conf->variable);
val = buffer;
}
}
break;
case PGC_STRING:
{
struct config_string *conf = (struct config_string *) record;
if (conf->show_hook)
val = (*conf->show_hook) ();
else if (*conf->variable && **conf->variable)
val = *conf->variable;
else
val = "unset";
}
break;
default:
/* just to keep compiler quiet */
val = "???";
break;
}
elog(INFO, "%s is %s", record->name, val);
}
/* /*
...@@ -1366,59 +2362,54 @@ ParseLongOption(const char *string, char **name, char **value) ...@@ -1366,59 +2362,54 @@ ParseLongOption(const char *string, char **name, char **value)
#ifdef HAVE_SYSLOG #ifdef HAVE_SYSLOG
static bool static const char *
check_facility(const char *facility) assign_facility(const char *facility, bool doit, bool interactive)
{ {
if (strcasecmp(facility, "LOCAL0") == 0) if (strcasecmp(facility, "LOCAL0") == 0)
return true; return facility;
if (strcasecmp(facility, "LOCAL1") == 0) if (strcasecmp(facility, "LOCAL1") == 0)
return true; return facility;
if (strcasecmp(facility, "LOCAL2") == 0) if (strcasecmp(facility, "LOCAL2") == 0)
return true; return facility;
if (strcasecmp(facility, "LOCAL3") == 0) if (strcasecmp(facility, "LOCAL3") == 0)
return true; return facility;
if (strcasecmp(facility, "LOCAL4") == 0) if (strcasecmp(facility, "LOCAL4") == 0)
return true; return facility;
if (strcasecmp(facility, "LOCAL5") == 0) if (strcasecmp(facility, "LOCAL5") == 0)
return true; return facility;
if (strcasecmp(facility, "LOCAL6") == 0) if (strcasecmp(facility, "LOCAL6") == 0)
return true; return facility;
if (strcasecmp(facility, "LOCAL7") == 0) if (strcasecmp(facility, "LOCAL7") == 0)
return true; return facility;
return false; return NULL;
} }
#endif
#endif
static bool
check_defaultxactisolevel(const char *value)
{
return (strcasecmp(value, "read committed") == 0
|| strcasecmp(value, "serializable") == 0)
? true : false;
}
static void static const char *
assign_defaultxactisolevel(const char *value) assign_defaultxactisolevel(const char *newval, bool doit, bool interactive)
{ {
if (strcasecmp(value, "serializable") == 0) if (strcasecmp(newval, "serializable") == 0)
DefaultXactIsoLevel = XACT_SERIALIZABLE; { if (doit) DefaultXactIsoLevel = XACT_SERIALIZABLE; }
else if (strcasecmp(value, "read committed") == 0) else if (strcasecmp(newval, "read committed") == 0)
DefaultXactIsoLevel = XACT_READ_COMMITTED; { if (doit) DefaultXactIsoLevel = XACT_READ_COMMITTED; }
else else
elog(ERROR, "bogus transaction isolation level"); return NULL;
return newval;
} }
/*
* Handle options fetched from pg_database.datconfig or pg_shadow.useconfig.
*/
void void
ProcessGUCArray(ArrayType *array, GucSource source) ProcessGUCArray(ArrayType *array, GucSource source)
{ {
int i; int i;
Assert(array); Assert(array != NULL);
Assert(source == PGC_S_DATABASE || source == PGC_S_USER);
for (i = 1; i <= ARR_DIMS(array)[0]; i++) for (i = 1; i <= ARR_DIMS(array)[0]; i++)
{ {
...@@ -1445,12 +2436,12 @@ ProcessGUCArray(ArrayType *array, GucSource source) ...@@ -1445,12 +2436,12 @@ ProcessGUCArray(ArrayType *array, GucSource source)
continue; continue;
} }
/* prevent errors from incorrect options */ /*
guc_session_init = true; * We process all these options at SUSET level. We assume that the
* right to insert an option into pg_database or pg_shadow was
* checked when it was inserted.
*/
SetConfigOption(name, value, PGC_SUSET, source); SetConfigOption(name, value, PGC_SUSET, source);
guc_session_init = false;
} }
} }
...@@ -1469,7 +2460,7 @@ GUCArrayAdd(ArrayType *array, const char *name, const char *value) ...@@ -1469,7 +2460,7 @@ GUCArrayAdd(ArrayType *array, const char *name, const char *value)
/* test if the option is valid */ /* test if the option is valid */
set_config_option(name, value, set_config_option(name, value,
superuser() ? PGC_SUSET : PGC_USERSET, superuser() ? PGC_SUSET : PGC_USERSET,
false, PGC_S_INFINITY); PGC_S_SESSION, false, false);
newval = palloc(strlen(name) + 1 + strlen(value) + 1); newval = palloc(strlen(name) + 1 + strlen(value) + 1);
sprintf(newval, "%s=%s", name, value); sprintf(newval, "%s=%s", name, value);
...@@ -1525,7 +2516,7 @@ GUCArrayDelete(ArrayType *array, const char *name) ...@@ -1525,7 +2516,7 @@ GUCArrayDelete(ArrayType *array, const char *name)
/* test if the option is valid */ /* test if the option is valid */
set_config_option(name, NULL, set_config_option(name, NULL,
superuser() ? PGC_SUSET : PGC_USERSET, superuser() ? PGC_SUSET : PGC_USERSET,
false, PGC_S_INFINITY); PGC_S_SESSION, false, false);
newarray = construct_array(NULL, 0, false, -1, 'i'); newarray = construct_array(NULL, 0, false, -1, 'i');
index = 1; index = 1;
......
...@@ -192,7 +192,10 @@ ...@@ -192,7 +192,10 @@
# #
#dynamic_library_path = '$libdir' #dynamic_library_path = '$libdir'
#search_path = '$user,public' #search_path = '$user,public'
#datestyle = 'iso, us'
#timezone = unknown # actually, defaults to TZ environment setting
#australian_timezones = false #australian_timezones = false
#client_encoding = sql_ascii # actually, defaults to database encoding
#authentication_timeout = 60 # min 1, max 600 #authentication_timeout = 60 # min 1, max 600
#deadlock_timeout = 1000 #deadlock_timeout = 1000
#default_transaction_isolation = 'read committed' #default_transaction_isolation = 'read committed'
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: xlog.h,v 1.29 2002/03/15 19:20:36 tgl Exp $ * $Id: xlog.h,v 1.30 2002/05/17 01:19:19 tgl Exp $
*/ */
#ifndef XLOG_H #ifndef XLOG_H
#define XLOG_H #define XLOG_H
...@@ -216,7 +216,7 @@ extern XLogRecPtr GetRedoRecPtr(void); ...@@ -216,7 +216,7 @@ extern XLogRecPtr GetRedoRecPtr(void);
*/ */
extern XLogRecPtr GetUndoRecPtr(void); extern XLogRecPtr GetUndoRecPtr(void);
extern bool check_xlog_sync_method(const char *method); extern const char *assign_xlog_sync_method(const char *method,
extern void assign_xlog_sync_method(const char *method); bool doit, bool interactive);
#endif /* XLOG_H */ #endif /* XLOG_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: namespace.h,v 1.12 2002/05/01 23:06:41 tgl Exp $ * $Id: namespace.h,v 1.13 2002/05/17 01:19:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -75,8 +75,8 @@ extern bool isTempNamespace(Oid namespaceId); ...@@ -75,8 +75,8 @@ extern bool isTempNamespace(Oid namespaceId);
/* stuff for search_path GUC variable */ /* stuff for search_path GUC variable */
extern char *namespace_search_path; extern char *namespace_search_path;
extern bool check_search_path(const char *proposed); extern const char *assign_search_path(const char *newval,
extern void assign_search_path(const char *newval); bool doit, bool interactive);
extern void InitializeSearchPath(void); extern void InitializeSearchPath(void);
extern List *fetch_search_path(void); extern List *fetch_search_path(void);
......
/* /*
* Headers for handling of 'SET var TO', 'SHOW var' and 'RESET var' * variable.h
* statements * Routines for handling specialized SET variables.
* *
* $Id: variable.h,v 1.17 2001/11/05 17:46:33 momjian Exp $ * $Id: variable.h,v 1.18 2002/05/17 01:19:19 tgl Exp $
* *
*/ */
#ifndef VARIABLE_H #ifndef VARIABLE_H
#define VARIABLE_H #define VARIABLE_H
extern void SetPGVariable(const char *name, List *args); extern const char *assign_datestyle(const char *value,
extern void GetPGVariable(const char *name); bool doit, bool interactive);
extern void ResetPGVariable(const char *name); extern const char *show_datestyle(void);
extern const char *assign_timezone(const char *value,
extern void set_default_datestyle(void); bool doit, bool interactive);
extern void set_default_client_encoding(void); extern const char *show_timezone(void);
extern const char *assign_XactIsoLevel(const char *value,
bool doit, bool interactive);
extern const char *show_XactIsoLevel(void);
extern bool assign_random_seed(double value,
bool doit, bool interactive);
extern const char *show_random_seed(void);
extern const char *assign_client_encoding(const char *value,
bool doit, bool interactive);
extern const char *assign_server_encoding(const char *value,
bool doit, bool interactive);
extern const char *show_server_encoding(void);
extern const char *assign_session_authorization(const char *value,
bool doit, bool interactive);
extern const char *show_session_authorization(void);
#endif /* VARIABLE_H */ #endif /* VARIABLE_H */
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: miscadmin.h,v 1.103 2002/05/05 00:03:29 tgl Exp $ * $Id: miscadmin.h,v 1.104 2002/05/17 01:19:19 tgl Exp $
* *
* NOTES * NOTES
* some of the information in this file should be moved to * some of the information in this file should be moved to
...@@ -211,7 +211,7 @@ extern Oid GetSessionUserId(void); ...@@ -211,7 +211,7 @@ extern Oid GetSessionUserId(void);
extern void SetSessionUserId(Oid userid); extern void SetSessionUserId(Oid userid);
extern void InitializeSessionUserId(const char *username); extern void InitializeSessionUserId(const char *username);
extern void InitializeSessionUserIdStandalone(void); extern void InitializeSessionUserIdStandalone(void);
extern void SetSessionAuthorization(const char *username); extern void SetSessionAuthorization(Oid userid);
extern void SetDataDir(const char *dir); extern void SetDataDir(const char *dir);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: parsenodes.h,v 1.176 2002/05/12 20:10:04 tgl Exp $ * $Id: parsenodes.h,v 1.177 2002/05/17 01:19:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1439,6 +1439,7 @@ typedef struct VariableSetStmt ...@@ -1439,6 +1439,7 @@ typedef struct VariableSetStmt
NodeTag type; NodeTag type;
char *name; char *name;
List *args; List *args;
bool is_local; /* SET LOCAL */
} VariableSetStmt; } VariableSetStmt;
/* ---------------------- /* ----------------------
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: datetime.h,v 1.29 2002/04/21 19:48:31 thomas Exp $ * $Id: datetime.h,v 1.30 2002/05/17 01:19:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -289,7 +289,7 @@ extern int EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str); ...@@ -289,7 +289,7 @@ extern int EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str);
extern int DecodeSpecial(int field, char *lowtoken, int *val); extern int DecodeSpecial(int field, char *lowtoken, int *val);
extern int DecodeUnits(int field, char *lowtoken, int *val); extern int DecodeUnits(int field, char *lowtoken, int *val);
extern void ClearDateCache(bool); extern bool ClearDateCache(bool, bool, bool);
extern int j2day(int jd); extern int j2day(int jd);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: elog.h,v 1.36 2002/04/21 00:22:52 ishii Exp $ * $Id: elog.h,v 1.37 2002/05/17 01:19:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -60,9 +60,9 @@ __attribute__((format(printf, 2, 3))); ...@@ -60,9 +60,9 @@ __attribute__((format(printf, 2, 3)));
extern int DebugFileOpen(void); extern int DebugFileOpen(void);
extern bool check_server_min_messages(const char *lev); extern const char *assign_server_min_messages(const char *newval,
extern void assign_server_min_messages(const char *lev); bool doit, bool interactive);
extern bool check_client_min_messages(const char *lev); extern const char *assign_client_min_messages(const char *newval,
extern void assign_client_min_messages(const char *lev); bool doit, bool interactive);
#endif /* ELOG_H */ #endif /* ELOG_H */
...@@ -4,13 +4,15 @@ ...@@ -4,13 +4,15 @@
* External declarations pertaining to backend/utils/misc/guc.c and * External declarations pertaining to backend/utils/misc/guc.c and
* backend/utils/misc/guc-file.l * backend/utils/misc/guc-file.l
* *
* $Id: guc.h,v 1.16 2002/03/24 04:31:09 tgl Exp $ * $Id: guc.h,v 1.17 2002/05/17 01:19:19 tgl Exp $
*/ */
#ifndef GUC_H #ifndef GUC_H
#define GUC_H #define GUC_H
#include "nodes/pg_list.h"
#include "utils/array.h" #include "utils/array.h"
/* /*
* Certain options can only be set at certain times. The rules are * Certain options can only be set at certain times. The rules are
* like this: * like this:
...@@ -52,30 +54,45 @@ typedef enum ...@@ -52,30 +54,45 @@ typedef enum
* The following type records the source of the current setting. A * The following type records the source of the current setting. A
* new setting can only take effect if the previous setting had the * new setting can only take effect if the previous setting had the
* same or lower level. (E.g, changing the config file doesn't * same or lower level. (E.g, changing the config file doesn't
* override the postmaster command line.) * override the postmaster command line.) Tracking the source allows us
* to process sources in any convenient order without affecting results.
* Sources <= PGC_S_OVERRIDE will set the default used by RESET, as well
* as the current value.
*/ */
typedef enum typedef enum
{ {
PGC_S_DEFAULT = 0, /* wired-in default */ PGC_S_DEFAULT = 0, /* wired-in default */
PGC_S_FILE = 1, /* postgresql.conf */ PGC_S_ENV_VAR = 1, /* postmaster environment variable */
PGC_S_ARGV = 2, /* postmaster command line */ PGC_S_FILE = 2, /* postgresql.conf */
PGC_S_DATABASE = 3, /* per-database setting */ PGC_S_ARGV = 3, /* postmaster command line */
PGC_S_USER = 4, /* per-user setting */ PGC_S_DATABASE = 4, /* per-database setting */
PGC_S_CLIENT = 5, /* from client (PGOPTIONS) */ PGC_S_USER = 5, /* per-user setting */
PGC_S_SESSION = 6, /* SET command */ PGC_S_CLIENT = 6, /* from client (PGOPTIONS) */
PGC_S_INFINITY = 100 /* can be used to avoid checks */ PGC_S_OVERRIDE = 7, /* special case to forcibly set default */
PGC_S_SESSION = 8 /* SET command */
} GucSource; } GucSource;
extern void SetConfigOption(const char *name, const char *value, extern void SetConfigOption(const char *name, const char *value,
GucContext context, GucSource source); GucContext context, GucSource source);
extern const char *GetConfigOption(const char *name); extern const char *GetConfigOption(const char *name);
extern const char *GetConfigOptionResetString(const char *name);
extern void ProcessConfigFile(GucContext context); extern void ProcessConfigFile(GucContext context);
extern void ResetAllOptions(bool isStartup); extern void InitializeGUCOptions(void);
extern void ResetAllOptions(void);
extern void AtEOXact_GUC(bool isCommit);
extern void ParseLongOption(const char *string, char **name, char **value); extern void ParseLongOption(const char *string, char **name, char **value);
extern bool set_config_option(const char *name, const char *value, extern bool set_config_option(const char *name, const char *value,
GucContext context, bool DoIt, GucSource source); GucContext context, GucSource source,
bool isLocal, bool DoIt);
extern void ShowGUCConfigOption(const char *name);
extern void ShowAllGUCConfig(void); extern void ShowAllGUCConfig(void);
extern void SetPGVariable(const char *name, List *args, bool is_local);
extern void GetPGVariable(const char *name);
extern void ResetPGVariable(const char *name);
extern char *flatten_set_variable_args(const char *name, List *args);
extern void ProcessGUCArray(ArrayType *array, GucSource source); extern void ProcessGUCArray(ArrayType *array, GucSource source);
extern ArrayType *GUCArrayAdd(ArrayType *array, const char *name, const char *value); extern ArrayType *GUCArrayAdd(ArrayType *array, const char *name, const char *value);
extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name); extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* *
* PostgreSQL locale utilities * PostgreSQL locale utilities
* *
* $Header: /cvsroot/pgsql/src/include/utils/pg_locale.h,v 1.12 2002/04/03 05:39:33 petere Exp $ * $Id: pg_locale.h,v 1.13 2002/05/17 01:19:19 tgl Exp $
* *
* Copyright (c) 2002, PostgreSQL Global Development Group * Copyright (c) 2002, PostgreSQL Global Development Group
* *
...@@ -12,26 +12,23 @@ ...@@ -12,26 +12,23 @@
#ifndef _PG_LOCALE_ #ifndef _PG_LOCALE_
#define _PG_LOCALE_ #define _PG_LOCALE_
#include "postgres.h"
#include <locale.h> #include <locale.h>
extern char * locale_messages; extern char *locale_messages;
extern char * locale_monetary; extern char *locale_monetary;
extern char * locale_numeric; extern char *locale_numeric;
extern char * locale_time; extern char *locale_time;
bool locale_messages_check(const char *proposed); extern const char *locale_messages_assign(const char *value,
bool locale_monetary_check(const char *proposed); bool doit, bool interactive);
bool locale_numeric_check(const char *proposed); extern const char *locale_monetary_assign(const char *value,
bool locale_time_check(const char *proposed); bool doit, bool interactive);
extern const char *locale_numeric_assign(const char *value,
void locale_messages_assign(const char *value); bool doit, bool interactive);
void locale_monetary_assign(const char *value); extern const char *locale_time_assign(const char *value,
void locale_numeric_assign(const char *value); bool doit, bool interactive);
void locale_time_assign(const char *value);
extern bool lc_collate_is_c(void);
bool chklocale(int category, const char *proposed);
bool lc_collate_is_c(void);
/* /*
* Return the POSIX lconv struct (contains number/money formatting * Return the POSIX lconv struct (contains number/money formatting
......
...@@ -12,7 +12,7 @@ import org.postgresql.util.*; ...@@ -12,7 +12,7 @@ import org.postgresql.util.*;
import org.postgresql.core.*; import org.postgresql.core.*;
/* /*
* $Id: Connection.java,v 1.46 2002/05/14 03:00:35 barry Exp $ * $Id: Connection.java,v 1.47 2002/05/17 01:19:19 tgl Exp $
* *
* This abstract class is used by org.postgresql.Driver to open either the JDBC1 or * This abstract class is used by org.postgresql.Driver to open either the JDBC1 or
* JDBC2 versions of the Connection class. * JDBC2 versions of the Connection class.
...@@ -951,7 +951,7 @@ public abstract class Connection ...@@ -951,7 +951,7 @@ public abstract class Connection
public int getTransactionIsolation() throws SQLException public int getTransactionIsolation() throws SQLException
{ {
clearWarnings(); clearWarnings();
ExecSQL("show xactisolevel"); ExecSQL("show transaction isolation level");
SQLWarning warning = getWarnings(); SQLWarning warning = getWarnings();
if (warning != null) if (warning != null)
......
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