Re: ALTER SESSION

Поиск
Список
Период
Сортировка
От Kyotaro HORIGUCHI
Тема Re: ALTER SESSION
Дата
Msg-id 20190201.173012.144395457.horiguchi.kyotaro@lab.ntt.co.jp
обсуждение исходный текст
Ответ на RE: ALTER SESSION  ("Tsunakawa, Takayuki" <tsunakawa.takay@jp.fujitsu.com>)
Список pgsql-hackers
Hello.

At Fri, 1 Feb 2019 06:31:40 +0000, "Tsunakawa, Takayuki" <tsunakawa.takay@jp.fujitsu.com> wrote in
<0A3221C70F24FB45833433255569204D1FB927B1@G01JPEXMBYT05>
> Thanks for a cool feature with nice UI.  Can I expect it to work for background processes?  For troubleshooting, I
wantedto investigate how autovacuum launcher/worker behaves by having them emit DEBUG messages.
 
> 
> (My comments follow)

I haven't did actually, but it doesn't reject background
workers. But background worker seems to assume that no change in
variablres while working. I should consider that.

> From: Kyotaro HORIGUCHI [mailto:horiguchi.kyotaro@lab.ntt.co.jp]
> > .auto.conf is already a kind of such.. My first version signals the change
> > via shared memory (in a largely-improvable way) and add the GUC system the
> > complex "nontransactional SET" feature, which lets a change persists beyond
> > transaction end if any. Holding changes until the session becomes idle seems
> > also complex.
> > 
> > https://www.postgresql.org/message-id/20181127.193622.252197705.horigu
> > chi.kyotaro@lab.ntt.co.jp
> > 
> > The most significant reason for passing-by-file is the affinity with the
> > current GUC system.
> 
> Regarding the target session specification, do we want to use pid or a session ID like the following?
> 
> https://www.postgresql.org/docs/devel/runtime-config-logging.html
> --------------------------------------------------
> The %c escape prints a quasi-unique session identifier, consisting of two 4-byte hexadecimal numbers (without leading
zeros)separated by a dot. The numbers are the process start time and the process ID, so %c can also be used as a space
savingway of printing those items. For example, to generate the session identifier from pg_stat_activity, use this
query:
> 
> SELECT to_hex(trunc(EXTRACT(EPOCH FROM backend_start))::integer) || '.' ||
>        to_hex(pid)
> FROM pg_stat_activity;
> 
> pid is easier to type.  However, the session startup needs to try to delete the leftover file.  Is the file system
accessnegligible compared with the total heavy session startup processing?
 
> 
> If we choose session ID, the session startup doesn't have to care about the leftover file.  However, the background
processcrash could leave the file for a long time, since the crash may not lead to postmaster restart.  Also, we will
getinclined to add sessionid column in pg_stat_activity (the concept of session ID can be useful for other uses.)
 

Sounds reasonbale. 

The attached version happens to add backend startup time in
PGPROC and I added session id as a usable key. (Heavily WIP)

ALTER SESSION WITH (id '5c540141.b7f') SET work_mem to '128kB';

> I'm OK about passing parameter changes via a file.  But I'm not sure whether using DSM (DSA) is easier with less
code.

Perhaps DSA is not required. Currently it uses rather a large
area but I think we can do the same thing with smaller memory by
sending long strings part by part.

> And considering the multi-threaded server Konstantin is proposing, would it better to take pass-by-memory approach?
Iimagine that if the server gets multi-threaded, the parameter change would be handled like:
 
> 
> 1. Allocate memory for one parameter change.
> 2. Write the change to that memory.
> 3. Link the memory to a session-specific list.
> 4. The target session removes the entry from the list, applies the change, and frees the memory.
> 
> The code modification may be minimal when we migrate to the multi-threaded server -- only memory allocation and free
functions.

The attached is a WIP patch that:

 - Using the non-transactional SET (for my convenience).

 - based on not file, but static shared memory.
   Using a new signal 

 - It adds PGC_S_REMOTE with the same precedence with PGC_S_SESSION.
   (This causes arguable behavior..)

 - ALTER SESSION syntax. (key can be pid or session id)


(Sorry for the inconsistent name of the patch files..)

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
From 82970b92d406d487f1bc88a64fb9e89dc9a6b039 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Fri, 1 Feb 2019 09:45:48 +0900
Subject: [PATCH 1/2] Add start timestamp to PGPROC

A ProcArray element may be allocated to another session while
investigating. Pid is not fully relialble for cheking that because of
the possibility of reusing. Add start timestamp to resolve the issue.
---
 src/backend/storage/lmgr/proc.c | 2 ++
 src/include/storage/proc.h      | 1 +
 2 files changed, 3 insertions(+)

diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 89c80fb687..a63309a432 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -373,6 +373,8 @@ InitProcess(void)
     MyProc->fpLocalTransactionId = InvalidLocalTransactionId;
     MyPgXact->xid = InvalidTransactionId;
     MyPgXact->xmin = InvalidTransactionId;
+    /* set this before pid to get rid of wrong pair with pid */
+    MyProc->starttimestamp = MyStartTimestamp;
     MyProc->pid = MyProcPid;
     /* backendId, databaseId and roleId will be filled in later */
     MyProc->backendId = InvalidBackendId;
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index d203acbb30..2cebdd2646 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -108,6 +108,7 @@ struct PGPROC
                                  * else InvalidLocalTransactionId */
     int            pid;            /* Backend's process ID; 0 if prepared xact */
     int            pgprocno;
+    uint64        starttimestamp;    /* Backend's start timestamp */
 
     /* These fields are zero while a backend is still starting up: */
     BackendId    backendId;        /* This backend's backend ID (if assigned) */
-- 
2.16.3

From 2e1fdd603948167aba0886036d9a2461bb051107 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Fri, 1 Feb 2019 17:23:09 +0900
Subject: [PATCH 2/2] Remote GUC (via shmem, ALTER SESSION, NoXact SET version)

---
 doc/src/sgml/config.sgml             |  26 +-
 doc/src/sgml/func.sgml               |  30 ++
 doc/src/sgml/ref/allfiles.sgml       |   1 +
 doc/src/sgml/ref/alter_session.sgml  | 160 +++++++
 doc/src/sgml/reference.sgml          |   1 +
 src/backend/catalog/system_views.sql |   7 +-
 src/backend/commands/discard.c       |   2 +-
 src/backend/nodes/copyfuncs.c        |  14 +
 src/backend/nodes/equalfuncs.c       |  12 +
 src/backend/parser/gram.y            |  44 +-
 src/backend/postmaster/pgstat.c      |   3 +
 src/backend/storage/ipc/ipci.c       |   2 +
 src/backend/storage/ipc/procsignal.c |   4 +
 src/backend/tcop/postgres.c          |   4 +
 src/backend/tcop/utility.c           |  13 +
 src/backend/utils/misc/README        |  26 +-
 src/backend/utils/misc/guc.c         | 869 ++++++++++++++++++++++++++++++-----
 src/include/catalog/pg_proc.dat      |  10 +-
 src/include/nodes/nodes.h            |   1 +
 src/include/nodes/parsenodes.h       |  12 +
 src/include/pgstat.h                 |   3 +-
 src/include/storage/procsignal.h     |   3 +
 src/include/utils/guc.h              |  21 +-
 src/include/utils/guc_tables.h       |   5 +-
 src/test/regress/expected/guc.out    | 223 +++++++++
 src/test/regress/sql/guc.sql         |  88 ++++
 26 files changed, 1439 insertions(+), 145 deletions(-)
 create mode 100644 doc/src/sgml/ref/alter_session.sgml

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index b6f5822b84..a52989342a 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -175,6 +175,14 @@ shared_buffers = 128MB
      read whenever <filename>postgresql.conf</filename> is, and its settings take
      effect in the same way.  Settings in <filename>postgresql.auto.conf</filename>
      override those in <filename>postgresql.conf</filename>.
+
+    </para>
+    <para>
+     Furthermore a directory <filename>pg_session_conf</filename> in the
+     PostgreSQL data directory contains per-session configuration files. Every
+     file holds settings provided through the
+     <xref linkend="sql-altersession"/> command. This is read by reloading
+     after the two above files and removed at the session-end.
     </para>
 
     <para>
@@ -195,8 +203,8 @@ shared_buffers = 128MB
       The already-mentioned <xref linkend="sql-altersystem"/> command
       provides a SQL-accessible means of changing global defaults; it is
       functionally equivalent to editing <filename>postgresql.conf</filename>.
-      In addition, there are two commands that allow setting of defaults
-      on a per-database or per-role basis:
+      In addition, there are three commands that allow setting of defaults
+      on a per-database, per-role or per-session basis:
      </para>
 
      <itemizedlist>
@@ -213,6 +221,13 @@ shared_buffers = 128MB
        per-database settings to be overridden with user-specific values.
       </para>
      </listitem>
+
+     <listitem>
+      <para>
+       The <xref linkend="sql-altersession"/> command allows other sessions to
+        override session-local settings with user-specific values.
+      </para>
+     </listitem>
     </itemizedlist>
 
      <para>
@@ -223,6 +238,13 @@ shared_buffers = 128MB
       Note that some settings cannot be changed after server start, and
       so cannot be set with these commands (or the ones listed below).
     </para>
+     <para>
+      Values set with <command>ALTER SESSION</command> are applied only when
+      reloading.  They override values obtained from the configuration files
+      or server command line, and constitute defaults for the rest of the
+      session.  Note that it can change only settings that are changeable
+      on-session.
+    </para>
 
      <para>
       Once a client is connected to the database, <productname>PostgreSQL</productname>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 4930ec17f6..075e959786 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -18687,6 +18687,20 @@ SELECT collation for ('foo' COLLATE "de_DE");
        <entry><type>text</type></entry>
        <entry>set parameter and return new value</entry>
       </row>
+      <row>
+       <entry>
+        <indexterm>
+         <primary>pg_set_backend_config</primary>
+        </indexterm>
+        <literal><function>pg_set_backend_config(
+                            <parameter>process_id</parameter>,
+                            <parameter>setting_name</parameter>,
+                            <parameter>new_value</parameter>)
+                            </function></literal>
+       </entry>
+       <entry><type>bool</type></entry>
+       <entry>set parameter on another session</entry>
+      </row>
      </tbody>
     </tgroup>
    </table>
@@ -18741,6 +18755,22 @@ SELECT set_config('log_statement_stats', 'off', false);
 ------------
  off
 (1 row)
+</programlisting>
+   </para>
+
+   <para>
+    <function>pg_set_backend_config</function> sets the parameter
+    <parameter>setting_name</parameter> to
+    <parameter>new_value</parameter> on the other session with PID
+    <parameter>process_id</parameter>. The setting is always session-local and
+    returns true if succeeded.  An example:
+<programlisting>
+SELECT pg_set_backend_config(2134, 'work_mem', '16MB');
+
+pg_set_backend_config
+------------
+ t
+(1 row)
 </programlisting>
    </para>
 
diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml
index c81c87ef41..650ae49a24 100644
--- a/doc/src/sgml/ref/allfiles.sgml
+++ b/doc/src/sgml/ref/allfiles.sgml
@@ -34,6 +34,7 @@ Complete list of usable sgml source files in this directory.
 <!ENTITY alterSchema        SYSTEM "alter_schema.sgml">
 <!ENTITY alterServer        SYSTEM "alter_server.sgml">
 <!ENTITY alterSequence      SYSTEM "alter_sequence.sgml">
+<!ENTITY alterSession       SYSTEM "alter_session.sgml">
 <!ENTITY alterSubscription  SYSTEM "alter_subscription.sgml">
 <!ENTITY alterSystem        SYSTEM "alter_system.sgml">
 <!ENTITY alterStatistics    SYSTEM "alter_statistics.sgml">
diff --git a/doc/src/sgml/ref/alter_session.sgml b/doc/src/sgml/ref/alter_session.sgml
new file mode 100644
index 0000000000..803d964091
--- /dev/null
+++ b/doc/src/sgml/ref/alter_session.sgml
@@ -0,0 +1,160 @@
+<!--
+doc/src/sgml/ref/alter_session.sgml
+PostgreSQL documentation
+-->
+
+<refentry id="sql-altersession">
+ <indexterm zone="sql-altersystem">
+  <primary>ALTER SESSION</primary>
+ </indexterm>
+
+ <refmeta>
+  <refentrytitle>ALTER SESSION</refentrytitle>
+  <manvolnum>7</manvolnum>
+  <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+  <refname>ALTER SESSION</refname>
+  <refpurpose>change a server configuration parameter of a remote session</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+<synopsis>
+ALTER SESSION WITH (pid <replaceable class="parameter">session_pid</replaceable>) SET <replaceable
class="parameter">configuration_parameter</replaceable>{ TO | = } { <replaceable class="parameter">value</replaceable>
|'<replaceable class="parameter">value</replaceable>' | DEFAULT } [ [ WITH ] RELOAD ]
 
+
+ALTER SESSION WITH (pid <replaceable class="parameter">session_pid</replaceable>) RESET <replaceable
class="parameter">configuration_parameter</replaceable>[ [ WITH ] RELOAD ]
 
+ALTER SESSION WITH (pid <replaceable class="parameter">session_pid</replaceable>) RESET ALL [ [ WITH ] RELOAD ]
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+  <title>Description</title>
+
+  <para>
+   <command>ALTER SESSION</command> is used for changing server configuration
+   parameters on the specified session. 
+   <command>ALTER SESSION</command> writes the given parameter setting to the
+   file <filename>pg_session_conf/postgresql.<replaceable>beid</replaceable>.conf</filename>
+   file, which is read in addition to <filename>postgresql.conf</filename>
+   and <filename>postgresql.auto.conf</filename>.  Setting a parameter
+   to <literal>DEFAULT</literal>, or using the
+   <command>RESET</command> variant, removes that configuration entry from the
+   session config file. Use <literal>RESET ALL</literal> to remove the
+   parameter file. The session config file lasts until the end of the session.
+  </para>
+
+  <para>
+   Values set with <command>ALTER SESSION</command> will be effective after
+   the next server configuration reload.  A server configuration reload can be
+   commanded by calling the SQL
+   function <function>pg_reload_conf()</function>, running <literal>pg_ctl
+   reload</literal>, sending a <systemitem>SIGHUP</systemitem> signal to the
+   main server process, or specifying <literal>WITH RELOAD</literal>
+   in <command>ALTER SESSION</command>. As <command>ALTER SYSTEM</command>
+   does, <command>ALTER SESSION</command> doesn't override settings changed
+   in-session.
+  </para>
+
+  <para>
+   Only superusers and users who are granted the session user or
+   pg_signal_backend can use <command>ALTER SESSION</command>.  Also, since
+   this command acts directly on the file system and cannot be rolled back, it
+   is not allowed inside a transaction block or function.
+  </para>
+ </refsect1>
+
+ <refsect1>
+  <title>Parameters</title>
+
+  <variablelist>
+   <varlistentry>
+    <term><replaceable class="parameter">session_pid</replaceable></term>
+    <listitem>
+     <para>
+      Process ID of the target session.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><replaceable class="parameter">configuration_parameter</replaceable></term>
+    <listitem>
+     <para>
+      Name of a settable configuration parameter.  Available parameters are
+      documented in <xref linkend="runtime-config"/>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><replaceable class="parameter">value</replaceable></term>
+    <listitem>
+     <para>
+      New value of the parameter.  Values can be specified as string
+      constants, identifiers, numbers, or comma-separated lists of
+      these, as appropriate for the particular parameter.
+      <literal>DEFAULT</literal> can be written to specify removing the
+      parameter and its value
+      from <filename>pg_session_conf/postgresql.<replaceable>beid</replaceable>.conf</filename>.
+     </para>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+ </refsect1>
+
+ <refsect1>
+  <title>Notes</title>
+
+  <para>
+   This command can't be used to set <xref linkend="guc-data-directory"/>,
+   parameters that are not allowed in <filename>postgresql.conf</filename>
+   (e.g., <link linkend="runtime-config-preset">preset options</link>), nor
+   parameters that cannot be changed on-session. Only superuser can perform
+   <literal>RESET ALL</literal>.
+  </para>
+
+  <para>
+   See <xref linkend="config-setting"/> for other ways to set the parameters.
+  </para>
+ </refsect1>
+
+ <refsect1>
+  <title>Examples</title>
+
+  <para>
+   Set the <literal>wal_level</literal>:
+<programlisting>
+ALTER SESSION WITH (pid 27162) SET track_functions = pl IMMEDIATE;
+</programlisting>
+  </para>
+
+  <para>
+   Undo that, restoring whatever setting was effective
+   in <filename>postgresql.conf</filename>
+   and <filename>postgresql.auto.conf</filename>:
+<programlisting>
+ALTER SESSION WITH (pid 27162) RESET track_functions IMMEDIATE;
+</programlisting></para>
+ </refsect1>
+
+ <refsect1>
+  <title>Compatibility</title>
+
+  <para>
+   The <command>ALTER SESSION</command> statement is a
+   <productname>PostgreSQL</productname> extension.
+  </para>
+ </refsect1>
+
+ <refsect1>
+  <title>See Also</title>
+
+  <simplelist type="inline">
+   <member><xref linkend="sql-altersystem"/></member>
+   <member><xref linkend="sql-set"/></member>
+   <member><xref linkend="sql-show"/></member>
+  </simplelist>
+ </refsect1>
+
+</refentry>
diff --git a/doc/src/sgml/reference.sgml b/doc/src/sgml/reference.sgml
index db4f4167e3..85f515e2b2 100644
--- a/doc/src/sgml/reference.sgml
+++ b/doc/src/sgml/reference.sgml
@@ -62,6 +62,7 @@
    &alterSchema;
    &alterSequence;
    &alterServer;
+   &alterSession;
    &alterStatistics;
    &alterSubscription;
    &alterSystem;
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 3e229c693c..88ad8ded40 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -474,7 +474,7 @@ CREATE VIEW pg_settings AS
 CREATE RULE pg_settings_u AS
     ON UPDATE TO pg_settings
     WHERE new.name = old.name DO
-    SELECT set_config(old.name, new.setting, 'f');
+    SELECT set_config(old.name, new.setting, 'f', 'f');
 
 CREATE RULE pg_settings_n AS
     ON UPDATE TO pg_settings
@@ -1035,6 +1035,11 @@ CREATE OR REPLACE FUNCTION
   RETURNS boolean STRICT VOLATILE LANGUAGE INTERNAL AS 'pg_promote'
   PARALLEL SAFE;
 
+CREATE OR REPLACE FUNCTION set_config (
+        setting_name text, new_value text, is_local boolean, is_nonxact boolean DEFAULT false)
+        RETURNS text STRICT VOLATILE LANGUAGE internal AS 'set_config_by_name'
+        PARALLEL UNSAFE;
+
 -- legacy definition for compatibility with 9.3
 CREATE OR REPLACE FUNCTION
   json_populate_record(base anyelement, from_json json, use_json_as_text boolean DEFAULT false)
diff --git a/src/backend/commands/discard.c b/src/backend/commands/discard.c
index 23a14586ba..948c0a70f3 100644
--- a/src/backend/commands/discard.c
+++ b/src/backend/commands/discard.c
@@ -68,7 +68,7 @@ DiscardAll(bool isTopLevel)
     /* Closing portals might run user-defined code, so do that first. */
     PortalHashTableDeleteAll();
     SetPGVariable("session_authorization", NIL, false);
-    ResetAllOptions();
+    ResetAllOptions(PGC_S_SESSION);
     DropAllPreparedStatements();
     Async_UnlistenAll();
     LockReleaseAll(USER_LOCKMETHOD, true);
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 807393dfaa..7719b475ae 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3923,6 +3923,17 @@ _copyAlterSystemStmt(const AlterSystemStmt *from)
     return newnode;
 }
 
+static AlterSessionStmt *
+_copyAlterSessionStmt(const AlterSessionStmt *from)
+{
+    AlterSessionStmt *newnode = makeNode(AlterSessionStmt);
+
+    COPY_NODE_FIELD(sessionopt);
+    COPY_NODE_FIELD(setstmt);
+    COPY_SCALAR_FIELD(immediate);
+    return newnode;
+}
+
 static CreateSeqStmt *
 _copyCreateSeqStmt(const CreateSeqStmt *from)
 {
@@ -5341,6 +5352,9 @@ copyObjectImpl(const void *from)
         case T_AlterSystemStmt:
             retval = _copyAlterSystemStmt(from);
             break;
+        case T_AlterSessionStmt:
+            retval = _copyAlterSessionStmt(from);
+            break;
         case T_CreateSeqStmt:
             retval = _copyCreateSeqStmt(from);
             break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index a397de155e..b542d060f8 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1732,6 +1732,15 @@ _equalAlterSystemStmt(const AlterSystemStmt *a, const AlterSystemStmt *b)
     return true;
 }
 
+static bool
+_equalAlterSessionStmt(const AlterSessionStmt *a, const AlterSessionStmt *b)
+{
+    COMPARE_NODE_FIELD(sessionopt);
+    COMPARE_NODE_FIELD(setstmt);
+    COMPARE_SCALAR_FIELD(immediate);
+
+    return true;
+}
 
 static bool
 _equalCreateSeqStmt(const CreateSeqStmt *a, const CreateSeqStmt *b)
@@ -3406,6 +3415,9 @@ equal(const void *a, const void *b)
         case T_AlterSystemStmt:
             retval = _equalAlterSystemStmt(a, b);
             break;
+        case T_AlterSessionStmt:
+            retval = _equalAlterSessionStmt(a, b);
+            break;
         case T_CreateSeqStmt:
             retval = _equalCreateSeqStmt(a, b);
             break;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index c1faf4152c..55793b1185 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -248,8 +248,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
         AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt
         AlterFdwStmt AlterForeignServerStmt AlterGroupStmt
         AlterObjectDependsStmt AlterObjectSchemaStmt AlterOwnerStmt
-        AlterOperatorStmt AlterSeqStmt AlterSystemStmt AlterTableStmt
-        AlterTblSpcStmt AlterExtensionStmt AlterExtensionContentsStmt AlterForeignTableStmt
+        AlterOperatorStmt AlterSeqStmt AlterSystemStmt AlterSessionStmt
+        AlterTableStmt AlterTblSpcStmt AlterExtensionStmt
+        AlterExtensionContentsStmt AlterForeignTableStmt
         AlterCompositeTypeStmt AlterUserMappingStmt
         AlterRoleStmt AlterRoleSetStmt AlterPolicyStmt
         AlterDefaultPrivilegesStmt DefACLAction
@@ -303,6 +304,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type <defelt>    createdb_opt_item copy_opt_item
                 transaction_mode_item
                 create_extension_opt_item alter_extension_opt_item
+                altersess_option_item
 
 %type <ival>    opt_lock lock_type cast_context
 %type <ival>    vacuum_option_list vacuum_option_elem
@@ -668,7 +670,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
     QUOTE
 
     RANGE READ REAL REASSIGN RECHECK RECURSIVE REF REFERENCES REFERENCING
-    REFRESH REINDEX RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA
+    REFRESH REINDEX RELATIVE_P RELEASE RELOAD RENAME REPEATABLE REPLACE REPLICA
     RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP
     ROUTINE ROUTINES ROW ROWS RULE
 
@@ -839,6 +841,7 @@ stmt :
             | AlterPolicyStmt
             | AlterSeqStmt
             | AlterSystemStmt
+            | AlterSessionStmt
             | AlterTableStmt
             | AlterTblSpcStmt
             | AlterCompositeTypeStmt
@@ -10169,6 +10172,41 @@ AlterSystemStmt:
         ;
 
 
+/*****************************************************************************
+ *
+ *        ALTER SESSION
+ *
+ * This is used to change configuration parameters persistently.
+ *****************************************************************************/
+
+AlterSessionStmt:
+            ALTER SESSION WITH '(' altersess_option_item ')' SET generic_set
+                {
+                    AlterSessionStmt *n = makeNode(AlterSessionStmt);
+                    n->sessionopt = $5;
+                    n->setstmt = $8;
+                    $$ = (Node *)n;
+                }
+            | ALTER SESSION WITH '(' altersess_option_item ')' RESET generic_reset
+                {
+                    AlterSessionStmt *n = makeNode(AlterSessionStmt);
+                    n->sessionopt = $5;
+                    n->setstmt = $8;
+                    $$ = (Node *)n;
+                }
+        ;
+
+altersess_option_item:
+        ColLabel Iconst
+            {
+                $$ = makeDefElem($1, (Node *)makeInteger($2), @1);
+            }
+        | ColLabel Sconst
+            {
+                $$ = makeDefElem($1, (Node *)makeString($2), @1);
+            }
+    ;
+
 /*****************************************************************************
  *
  * Manipulate a domain
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 81c6499251..c50ce50e67 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -3683,6 +3683,9 @@ pgstat_get_wait_ipc(WaitEventIPC w)
         case WAIT_EVENT_SYNC_REP:
             event_name = "SyncRep";
             break;
+        case WAIT_EVENT_REMOTE_GUC:
+            event_name = "RemoteGUC";
+            break;
             /* no default case, so that compiler will warn */
     }
 
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 2849e47d99..044107b354 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -148,6 +148,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
         size = add_size(size, BTreeShmemSize());
         size = add_size(size, SyncScanShmemSize());
         size = add_size(size, AsyncShmemSize());
+        size = add_size(size, GucShmemSize());
 #ifdef EXEC_BACKEND
         size = add_size(size, ShmemBackendArraySize());
 #endif
@@ -267,6 +268,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
     BTreeShmemInit();
     SyncScanShmemInit();
     AsyncShmemInit();
+    GucShmemInit();
 
 #ifdef EXEC_BACKEND
 
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 7605b2c367..98c0f84378 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -27,6 +27,7 @@
 #include "storage/shmem.h"
 #include "storage/sinval.h"
 #include "tcop/tcopprot.h"
+#include "utils/guc.h"
 
 
 /*
@@ -292,6 +293,9 @@ procsignal_sigusr1_handler(SIGNAL_ARGS)
     if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN))
         RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN);
 
+    if (CheckProcSignal(PROCSIG_REMOTE_GUC))
+        HandleRemoteGucSetInterrupt();
+
     SetLatch(MyLatch);
 
     latch_sigusr1_handler();
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 36cfd507b2..363275e302 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -4228,6 +4228,10 @@ PostgresMain(int argc, char *argv[],
             ProcessConfigFile(PGC_SIGHUP);
         }
 
+        if (RemoteGucChangePending)
+            HandleGucRemoteChanges();
+
+
         /*
          * (7) process the command.  But ignore it if we're skipping till
          * Sync.
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 6ec795f1b4..e0c1e293d1 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -681,6 +681,11 @@ standard_ProcessUtility(PlannedStmt *pstmt,
             AlterSystemSetConfigFile((AlterSystemStmt *) parsetree);
             break;
 
+        case T_AlterSessionStmt:
+            PreventInTransactionBlock(isTopLevel, "ALTER SESSION");
+            AlterSessionSetRemoteConfig(pstate, (AlterSessionStmt *) parsetree);
+            break;
+
         case T_VariableSetStmt:
             ExecSetVariableStmt((VariableSetStmt *) parsetree, isTopLevel);
             break;
@@ -2605,6 +2610,10 @@ CreateCommandTag(Node *parsetree)
             tag = "ALTER SYSTEM";
             break;
 
+        case T_AlterSessionStmt:
+            tag = "ALTER SESSION";
+            break;
+
         case T_VariableSetStmt:
             switch (((VariableSetStmt *) parsetree)->kind)
             {
@@ -3235,6 +3244,10 @@ GetCommandLogLevel(Node *parsetree)
             lev = LOGSTMT_DDL;
             break;
 
+        case T_AlterSessionStmt:
+            lev = LOGSTMT_DDL;
+            break;
+
         case T_VariableSetStmt:
             lev = LOGSTMT_ALL;
             break;
diff --git a/src/backend/utils/misc/README b/src/backend/utils/misc/README
index 6e294386f7..42ae6c1a8f 100644
--- a/src/backend/utils/misc/README
+++ b/src/backend/utils/misc/README
@@ -169,10 +169,14 @@ Entry to a function with a SET option:
 Plain SET command:
 
     If no stack entry of current level:
-        Push new stack entry w/prior value and state SET
+        Push new stack entry w/prior value and state SET or
+        push new stack entry w/o value and state NONXACT.
     else if stack entry's state is SAVE, SET, or LOCAL:
         change stack state to SET, don't change saved value
         (here we are forgetting effects of prior set action)
+    else if stack entry's state is NONXACT:
+        change stack state to NONXACT_SET, set the current value to
+        prior.
     else (entry must have state SET+LOCAL):
         discard its masked value, change state to SET
         (here we are forgetting effects of prior SET and SET LOCAL)
@@ -185,13 +189,20 @@ SET LOCAL command:
     else if stack entry's state is SAVE or LOCAL or SET+LOCAL:
         no change to stack entry
         (in SAVE case, SET LOCAL will be forgotten at func exit)
+    else if stack entry's state is NONXACT:
+        set current value to both prior and masked slots. set state
+        NONXACT+LOCAL.
     else (entry must have state SET):
         put current active into its masked slot, set state SET+LOCAL
     Now set new value.
 
+Setting by NONXACT action (no command exists):
+    Always blow away existing stack then create a new NONXACT entry.    
+
 Transaction or subtransaction abort:
 
-    Pop stack entries, restoring prior value, until top < subxact depth
+    Pop stack entries, restoring prior value unless the stack entry's
+    state is NONXACT, until top < subxact depth
 
 Transaction or subtransaction commit (incl. successful function exit):
 
@@ -199,9 +210,9 @@ Transaction or subtransaction commit (incl. successful function exit):
 
         if entry's state is SAVE:
             pop, restoring prior value
-        else if level is 1 and entry's state is SET+LOCAL:
+        else if level is 1 and entry's state is SET+LOCAL or NONXACT+LOCAL:
             pop, restoring *masked* value
-        else if level is 1 and entry's state is SET:
+        else if level is 1 and entry's state is SET or NONXACT+SET:
             pop, discarding old value
         else if level is 1 and entry's state is LOCAL:
             pop, restoring prior value
@@ -210,9 +221,9 @@ Transaction or subtransaction commit (incl. successful function exit):
         else
             merge entries of level N-1 and N as specified below
 
-The merged entry will have level N-1 and prior = older prior, so easiest
-to keep older entry and free newer.  There are 12 possibilities since
-we already handled level N state = SAVE:
+The merged entry will have level N-1 and prior = older prior, so
+easiest to keep older entry and free newer.  Disregarding to NONXACT,
+here are 12 possibilities since we already handled level N state = SAVE:
 
 N-1        N
 
@@ -232,6 +243,7 @@ SET+LOCAL    SET        discard top prior and second masked, state SET
 SET+LOCAL    LOCAL        discard top prior, no change to stack entry
 SET+LOCAL    SET+LOCAL    discard top prior, copy masked, state S+L
 
+(TODO: states involving NONXACT)
 
 RESET is executed like a SET, but using the reset_val as the desired new
 value.  (We do not provide a RESET LOCAL command, but SET LOCAL TO DEFAULT
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 98d75be292..e4b00b83e2 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -36,6 +36,7 @@
 #include "catalog/namespace.h"
 #include "catalog/pg_authid.h"
 #include "commands/async.h"
+#include "commands/defrem.h"
 #include "commands/prepare.h"
 #include "commands/user.h"
 #include "commands/vacuum.h"
@@ -70,12 +71,14 @@
 #include "replication/walreceiver.h"
 #include "replication/walsender.h"
 #include "storage/bufmgr.h"
+#include "storage/condition_variable.h"
 #include "storage/dsm_impl.h"
 #include "storage/standby.h"
 #include "storage/fd.h"
 #include "storage/large_object.h"
 #include "storage/pg_shmem.h"
 #include "storage/proc.h"
+#include "storage/procarray.h"
 #include "storage/predicate.h"
 #include "tcop/tcopprot.h"
 #include "tsearch/ts_cache.h"
@@ -211,12 +214,41 @@ static bool check_recovery_target_lsn(char **newval, void **extra, GucSource sou
 static void assign_recovery_target_lsn(const char *newval, void *extra);
 static bool check_primary_slot_name(char **newval, void **extra, GucSource source);
 static bool check_default_with_oids(bool *newval, void **extra, GucSource source);
-
+static bool set_backend_config_internal(int target_pid, uint64 target_ts, char *name, char *value);
 /* Private functions in guc-file.l that need to be called from guc.c */
 static ConfigVariable *ProcessConfigFileInternal(GucContext context,
                           bool applySettings, int elevel);
 
 
+#define GUC_REMOTE_MAX_VALUE_LEN  1024        /* an arbitrary value */
+
+typedef struct GucPendingSetting
+{
+    char        name[NAMEDATALEN];
+    GucContext    context;
+    bool        reset;
+    bool        reset_all;
+    char       *value;
+    int            source_pid;
+} GucPendingSetting;
+
+typedef struct
+{
+    bool        busy;
+    slock_t        mutex;
+    ConditionVariable    busy_cv;
+    int            target_pid;
+    uint64        target_start_timestamp;
+    char        value[GUC_REMOTE_MAX_VALUE_LEN];
+    GucPendingSetting setting;
+    volatile Latch *sender_latch;
+} GucRemoteSetting;
+
+static MemoryContext RemoteConfigMemoryContext = NULL;
+static GucRemoteSetting *remote_setting = NULL;
+static HTAB *pending_setting = NULL;
+volatile bool RemoteGucChangePending = false;
+
 /*
  * Options for enum values defined in this module.
  *
@@ -605,7 +637,8 @@ const char *const GucSource_Names[] =
      /* PGC_S_OVERRIDE */ "override",
      /* PGC_S_INTERACTIVE */ "interactive",
      /* PGC_S_TEST */ "test",
-     /* PGC_S_SESSION */ "session"
+     /* PGC_S_SESSION */ "session",
+     /* PGC_S_REMOTE */ "remote session"
 };
 
 /*
@@ -4452,10 +4485,8 @@ static const char *const map_old_guc_names[] = {
  * Actual lookup of variables is done through this single, sorted array.
  */
 static struct config_generic **guc_variables;
-
 /* Current number of variables contained in the vector */
 static int    num_guc_variables;
-
 /* Vector capacity */
 static int    size_guc_variables;
 
@@ -5380,7 +5411,7 @@ SelectConfigFiles(const char *userDoption, const char *progname)
  * Reset all options to their saved default values (implements RESET ALL)
  */
 void
-ResetAllOptions(void)
+ResetAllOptions(GucSource src)
 {
     int            i;
 
@@ -5396,7 +5427,8 @@ ResetAllOptions(void)
         if (gconf->flags & GUC_NO_RESET_ALL)
             continue;
         /* No need to reset if wasn't SET */
-        if (gconf->source <= PGC_S_OVERRIDE)
+        Assert(PGC_S_OVERRIDE < src);
+        if (gconf->source != src)
             continue;
 
         /* Save old value to support transaction abort */
@@ -5490,6 +5522,22 @@ push_old_value(struct config_generic *gconf, GucAction action)
 
     /* Do we already have a stack entry of the current nest level? */
     stack = gconf->stack;
+
+    /* NONXACT action make existing stack useles */
+    if (action == GUC_ACTION_NONXACT)
+    {
+        while (stack)
+        {
+            GucStack *prev = stack->prev;
+
+            discard_stack_value(gconf, &stack->prior);
+            discard_stack_value(gconf, &stack->masked);
+            pfree(stack);
+            stack = prev;
+        }
+        stack = gconf->stack = NULL;
+    }
+
     if (stack && stack->nest_level >= GUCNestLevel)
     {
         /* Yes, so adjust its state if necessary */
@@ -5497,28 +5545,63 @@ push_old_value(struct config_generic *gconf, GucAction action)
         switch (action)
         {
             case GUC_ACTION_SET:
-                /* SET overrides any prior action at same nest level */
-                if (stack->state == GUC_SET_LOCAL)
+                if (stack->state == GUC_NONXACT)
                 {
-                    /* must discard old masked value */
-                    discard_stack_value(gconf, &stack->masked);
+                    /* NONXACT rollbacks to the current value */
+                    stack->scontext = gconf->scontext;
+                    set_stack_value(gconf, &stack->prior);
+                    stack->state = GUC_NONXACT_SET;
                 }
-                stack->state = GUC_SET;
+                else 
+                {
+                    /* SET overrides other prior actions at same nest level */
+                    if (stack->state == GUC_SET_LOCAL)
+                    {
+                        /* must discard old masked value */
+                        discard_stack_value(gconf, &stack->masked);
+                    }
+                    stack->state = GUC_SET;
+                }
+
                 break;
+
             case GUC_ACTION_LOCAL:
                 if (stack->state == GUC_SET)
                 {
-                    /* SET followed by SET LOCAL, remember SET's value */
+                    /* SET followed by SET LOCAL, remember it's value */
                     stack->masked_scontext = gconf->scontext;
                     set_stack_value(gconf, &stack->masked);
                     stack->state = GUC_SET_LOCAL;
                 }
+                else if (stack->state == GUC_NONXACT)
+                {
+                    /*
+                     * NONXACT followed by SET LOCAL, both prior and masked
+                     * are set to the current value
+                     */
+                    stack->scontext = gconf->scontext;
+                    set_stack_value(gconf, &stack->prior);
+                    stack->masked_scontext = stack->scontext;
+                    stack->masked = stack->prior;
+                    stack->state = GUC_NONXACT_LOCAL;
+                }
+                else if (stack->state == GUC_NONXACT_SET)
+                {
+                    /* NONXACT_SET followed by SET LOCAL, set masked */
+                    stack->masked_scontext = gconf->scontext;
+                    set_stack_value(gconf, &stack->masked);
+                    stack->state = GUC_NONXACT_LOCAL;
+                }
                 /* in all other cases, no change to stack entry */
                 break;
             case GUC_ACTION_SAVE:
                 /* Could only have a prior SAVE of same variable */
                 Assert(stack->state == GUC_SAVE);
                 break;
+
+            case GUC_ACTION_NONXACT:
+                Assert(false);
+                break;
         }
         Assert(guc_dirty);        /* must be set already */
         return;
@@ -5534,6 +5617,7 @@ push_old_value(struct config_generic *gconf, GucAction action)
 
     stack->prev = gconf->stack;
     stack->nest_level = GUCNestLevel;
+        
     switch (action)
     {
         case GUC_ACTION_SET:
@@ -5545,10 +5629,15 @@ push_old_value(struct config_generic *gconf, GucAction action)
         case GUC_ACTION_SAVE:
             stack->state = GUC_SAVE;
             break;
+        case GUC_ACTION_NONXACT:
+            stack->state = GUC_NONXACT;
+            break;
     }
     stack->source = gconf->source;
     stack->scontext = gconf->scontext;
-    set_stack_value(gconf, &stack->prior);
+
+    if (action != GUC_ACTION_NONXACT)
+        set_stack_value(gconf, &stack->prior);
 
     gconf->stack = stack;
 
@@ -5643,22 +5732,31 @@ AtEOXact_GUC(bool isCommit, int nestLevel)
              * stack entries to avoid leaking memory.  If we do set one of
              * those flags, unused fields will be cleaned up after restoring.
              */
-            if (!isCommit)        /* if abort, always restore prior value */
-                restorePrior = true;
+            if (!isCommit)
+            {
+                /* GUC_NONXACT does't rollback */
+                if (stack->state != GUC_NONXACT)
+                    restorePrior = true;
+            }
             else if (stack->state == GUC_SAVE)
                 restorePrior = true;
             else if (stack->nest_level == 1)
             {
                 /* transaction commit */
-                if (stack->state == GUC_SET_LOCAL)
+                if (stack->state == GUC_SET_LOCAL ||
+                    stack->state == GUC_NONXACT_LOCAL)
                     restoreMasked = true;
-                else if (stack->state == GUC_SET)
+                else if (stack->state == GUC_SET ||
+                         stack->state == GUC_NONXACT_SET)
                 {
                     /* we keep the current active value */
                     discard_stack_value(gconf, &stack->prior);
                 }
-                else            /* must be GUC_LOCAL */
+                else if (stack->state != GUC_NONXACT)
+                {
+                    /* must be GUC_LOCAL */
                     restorePrior = true;
+                }
             }
             else if (prev == NULL ||
                      prev->nest_level < stack->nest_level - 1)
@@ -5680,11 +5778,27 @@ AtEOXact_GUC(bool isCommit, int nestLevel)
                         break;
 
                     case GUC_SET:
-                        /* next level always becomes SET */
-                        discard_stack_value(gconf, &stack->prior);
-                        if (prev->state == GUC_SET_LOCAL)
+                        if (prev->state == GUC_SET ||
+                            prev->state == GUC_NONXACT_SET)
+                        {
+                            discard_stack_value(gconf, &stack->prior);
+                        }
+                        else if (prev->state == GUC_NONXACT)
+                        {
+                            prev->scontext = stack->scontext;
+                            prev->prior = stack->prior;
+                            prev->state = GUC_NONXACT_SET;
+                        }
+                        else if (prev->state == GUC_SET_LOCAL ||
+                                 prev->state == GUC_NONXACT_LOCAL)
+                        {
+                            discard_stack_value(gconf, &stack->prior);
                             discard_stack_value(gconf, &prev->masked);
-                        prev->state = GUC_SET;
+                            if (prev->state == GUC_SET_LOCAL)
+                                prev->state = GUC_SET;
+                            else
+                                prev->state = GUC_NONXACT_SET;
+                        }
                         break;
 
                     case GUC_LOCAL:
@@ -5695,6 +5809,16 @@ AtEOXact_GUC(bool isCommit, int nestLevel)
                             prev->masked = stack->prior;
                             prev->state = GUC_SET_LOCAL;
                         }
+                        else if (prev->state == GUC_NONXACT)
+                        {
+                            prev->prior = stack->masked;
+                            prev->scontext = stack->masked_scontext;
+                            prev->masked = stack->masked;
+                            prev->masked_scontext = stack->masked_scontext;
+                            discard_stack_value(gconf, &stack->prior);
+                            discard_stack_value(gconf, &stack->masked);
+                            prev->state = GUC_NONXACT_SET;
+                        }
                         else
                         {
                             /* else just forget this stack level */
@@ -5703,15 +5827,32 @@ AtEOXact_GUC(bool isCommit, int nestLevel)
                         break;
 
                     case GUC_SET_LOCAL:
-                        /* prior state at this level no longer wanted */
-                        discard_stack_value(gconf, &stack->prior);
-                        /* copy down the masked state */
-                        prev->masked_scontext = stack->masked_scontext;
-                        if (prev->state == GUC_SET_LOCAL)
-                            discard_stack_value(gconf, &prev->masked);
-                        prev->masked = stack->masked;
-                        prev->state = GUC_SET_LOCAL;
+                        if (prev->state == GUC_NONXACT)
+                        {
+                            prev->prior = stack->prior;
+                            prev->masked = stack->prior;
+                            discard_stack_value(gconf, &stack->prior);
+                            discard_stack_value(gconf, &stack->masked);
+                            prev->state = GUC_NONXACT_SET;
+                        }
+                        else if (prev->state != GUC_NONXACT_SET)
+                        {
+                            /* prior state at this level no longer wanted */
+                            discard_stack_value(gconf, &stack->prior);
+                            /* copy down the masked state */
+                            prev->masked_scontext = stack->masked_scontext;
+                            if (prev->state == GUC_SET_LOCAL)
+                                discard_stack_value(gconf, &prev->masked);
+                            prev->masked = stack->masked;
+                            prev->state = GUC_SET_LOCAL;
+                        }
                         break;
+                    case GUC_NONXACT:
+                    case GUC_NONXACT_SET:
+                    case GUC_NONXACT_LOCAL:
+                        Assert(false);
+                        break;
+                        
                 }
             }
 
@@ -6451,6 +6592,8 @@ set_config_option(const char *name, const char *value,
                  source == PGC_S_USER ||
                  source == PGC_S_DATABASE_USER)
             elevel = WARNING;
+        else if (source == PGC_S_REMOTE)
+            elevel = NOTICE;
         else
             elevel = ERROR;
     }
@@ -6654,8 +6797,9 @@ set_config_option(const char *name, const char *value,
      * 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/stacked values even if we can't set the variable itself.
+     * Interructive sources are mutually overwritable.
      */
-    if (record->source > source)
+    if (record->source > source && source < PGC_S_INTERACTIVE)
     {
         if (changeVal && !makeDefault)
         {
@@ -7598,6 +7742,110 @@ replace_auto_config_value(ConfigVariable **head_p, ConfigVariable **tail_p,
     *tail_p = item;
 }
 
+/*
+  Check and process the given set statment of ALTER SYSTEM and ALTER SESSION.
+ */
+static void
+AlterConfigProcessSetCommand(VariableSetStmt *setstmt,
+                             bool is_session, bool is_superuser,
+                             char **name, char **value, bool *resetall)
+{
+    *name = setstmt->name;
+
+    switch (setstmt->kind)
+    {
+        case VAR_SET_VALUE:
+            *value = ExtractSetVariableArgs(setstmt);
+            break;
+
+        case VAR_SET_DEFAULT:
+        case VAR_RESET:
+            *value = NULL;
+            break;
+
+        case VAR_RESET_ALL:
+            *value = NULL;
+            *resetall = true;
+            break;
+
+        default:
+            elog(ERROR, "unrecognized set type: %d",
+                 setstmt->kind);
+            break;
+    }
+
+    /*
+     * Unless it's RESET_ALL, validate the target variable and value
+     */
+    if (!*resetall)
+    {
+        struct config_generic *record;
+
+        record = find_option(*name, false, ERROR);
+        if (record == NULL)
+            ereport(ERROR,
+                    (errcode(ERRCODE_UNDEFINED_OBJECT),
+                     errmsg("unrecognized configuration parameter \"%s\"",
+                            *name)));
+
+        /*
+         * Don't allow parameters that can't be set in configuration files to
+         * be set in PG_AUTOCONF_FILENAME file.
+         */
+
+        /* PG_SUSET is changebale but only by superusers  */
+        if (is_session && !is_superuser && record->context == PGC_SUSET)
+                ereport(ERROR,
+                        (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                         errmsg("permission denied to set parameter \"%s\"",
+                                *name)));
+
+        /* ALTER SESSION allows only parameters changeabe on-session */
+        if ((is_session &&
+             (record->context != PGC_USERSET &&
+              record->context != PGC_SUSET)) ||
+            record->context == PGC_INTERNAL ||
+            (record->flags & GUC_DISALLOW_IN_FILE) ||
+            (record->flags & GUC_DISALLOW_IN_AUTO_FILE))
+            ereport(ERROR,
+                    (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
+                     errmsg("parameter \"%s\" cannot be changed",
+                            *name)));
+
+        /*
+         * If a value is specified, verify that it's sane.
+         */
+        if (*value)
+        {
+            union config_var_val newval;
+            void       *newextra = NULL;
+
+            /* Check that it's acceptable for the indicated parameter */
+            if (!parse_and_validate_value(record, *name, *value,
+                                          PGC_S_FILE, ERROR,
+                                          &newval, &newextra))
+                ereport(ERROR,
+                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                         errmsg("invalid value for parameter \"%s\": \"%s\"",
+                                *name, *value)));
+
+            if (record->vartype == PGC_STRING && newval.stringval != NULL)
+                free(newval.stringval);
+            if (newextra)
+                free(newextra);
+
+            /*
+             * We must also reject values containing newlines, because the
+             * grammar for config files doesn't support embedded newlines in
+             * string literals.
+             */
+            if (strchr(*value, '\n'))
+                ereport(ERROR,
+                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                         errmsg("parameter value for SET must not contain a newline")));
+        }
+    }
+}
 
 /*
  * Execute ALTER SYSTEM statement.
@@ -7631,89 +7879,8 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
     /*
      * Extract statement arguments
      */
-    name = altersysstmt->setstmt->name;
-
-    switch (altersysstmt->setstmt->kind)
-    {
-        case VAR_SET_VALUE:
-            value = ExtractSetVariableArgs(altersysstmt->setstmt);
-            break;
-
-        case VAR_SET_DEFAULT:
-        case VAR_RESET:
-            value = NULL;
-            break;
-
-        case VAR_RESET_ALL:
-            value = NULL;
-            resetall = true;
-            break;
-
-        default:
-            elog(ERROR, "unrecognized alter system stmt type: %d",
-                 altersysstmt->setstmt->kind);
-            break;
-    }
-
-    /*
-     * Unless it's RESET_ALL, validate the target variable and value
-     */
-    if (!resetall)
-    {
-        struct config_generic *record;
-
-        record = find_option(name, false, ERROR);
-        if (record == NULL)
-            ereport(ERROR,
-                    (errcode(ERRCODE_UNDEFINED_OBJECT),
-                     errmsg("unrecognized configuration parameter \"%s\"",
-                            name)));
-
-        /*
-         * Don't allow parameters that can't be set in configuration files to
-         * be set in PG_AUTOCONF_FILENAME file.
-         */
-        if ((record->context == PGC_INTERNAL) ||
-            (record->flags & GUC_DISALLOW_IN_FILE) ||
-            (record->flags & GUC_DISALLOW_IN_AUTO_FILE))
-            ereport(ERROR,
-                    (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
-                     errmsg("parameter \"%s\" cannot be changed",
-                            name)));
-
-        /*
-         * If a value is specified, verify that it's sane.
-         */
-        if (value)
-        {
-            union config_var_val newval;
-            void       *newextra = NULL;
-
-            /* Check that it's acceptable for the indicated parameter */
-            if (!parse_and_validate_value(record, name, value,
-                                          PGC_S_FILE, ERROR,
-                                          &newval, &newextra))
-                ereport(ERROR,
-                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                         errmsg("invalid value for parameter \"%s\": \"%s\"",
-                                name, value)));
-
-            if (record->vartype == PGC_STRING && newval.stringval != NULL)
-                free(newval.stringval);
-            if (newextra)
-                free(newextra);
-
-            /*
-             * We must also reject values containing newlines, because the
-             * grammar for config files doesn't support embedded newlines in
-             * string literals.
-             */
-            if (strchr(value, '\n'))
-                ereport(ERROR,
-                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                         errmsg("parameter value for ALTER SYSTEM must not contain a newline")));
-        }
-    }
+    AlterConfigProcessSetCommand(altersysstmt->setstmt, false, false,
+                                 &name, &value, &resetall);
 
     /*
      * PG_AUTOCONF_FILENAME and its corresponding temporary file are always in
@@ -7822,6 +7989,53 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
     LWLockRelease(AutoFileLock);
 }
 
+void
+AlterSessionSetRemoteConfig(ParseState *pstate, AlterSessionStmt *altersesstmt)
+{
+    int        target_pid;
+    char   *name;
+    char   *value;
+    bool    resetall = false;
+    DefElem       *def;
+    uint64    target_ts = 0;
+
+    def = altersesstmt->sessionopt;
+
+    /* ignoring namespace */
+    if (strcmp(def->defname, "pid") == 0)
+        target_pid = defGetInt32(def);
+    else if (strcmp(def->defname, "id") == 0)
+    {
+        /* Heavily WIP!! */
+        char *id = pstrdup(defGetString(def));
+        unsigned long     start;
+        int     n;
+
+        n = sscanf(id, "%lx.%x", &start, &target_pid);
+        if (n != 2)
+            ereport(ERROR,
+                    (errmsg ("malformed session id"),
+                     parser_errposition(pstate, def->location)));
+        target_ts = time_t_to_timestamptz(start);
+    }
+    else
+        ereport(ERROR,
+                (errmsg ("only pid or id is allowed here"),
+                 parser_errposition(pstate, def->location)));
+
+    
+    /*
+     * Extract statement arguments
+     */
+    AlterConfigProcessSetCommand(altersesstmt->setstmt, false, false,
+                                 &name, &value, &resetall);
+
+    if (resetall)
+        name = NULL;
+
+    set_backend_config_internal(target_pid, target_ts, name, value);
+}
+
 /*
  * SET command
  */
@@ -7938,7 +8152,7 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
                                      action, true, 0, false);
             break;
         case VAR_RESET_ALL:
-            ResetAllOptions();
+            ResetAllOptions(PGC_S_SESSION);
             break;
     }
 }
@@ -7992,7 +8206,8 @@ set_config_by_name(PG_FUNCTION_ARGS)
     char       *name;
     char       *value;
     char       *new_value;
-    bool        is_local;
+    int            set_action = GUC_ACTION_SET;
+
 
     if (PG_ARGISNULL(0))
         ereport(ERROR,
@@ -8012,18 +8227,27 @@ set_config_by_name(PG_FUNCTION_ARGS)
      * Get the desired state of is_local. Default to false if provided value
      * is NULL
      */
-    if (PG_ARGISNULL(2))
-        is_local = false;
-    else
-        is_local = PG_GETARG_BOOL(2);
+    if (!PG_ARGISNULL(2) && PG_GETARG_BOOL(2))
+        set_action = GUC_ACTION_LOCAL;
+
+    /*
+     * Get the desired state of is_nonxact. Default to false if provided value
+     * is NULL
+     */
+    if (!PG_ARGISNULL(3) && PG_GETARG_BOOL(3))
+    {
+        if (set_action == GUC_ACTION_LOCAL)
+            ereport(ERROR,
+                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                     errmsg("Only one of is_local and is_nonxact can be true")));
+        set_action = GUC_ACTION_NONXACT;
+    }
 
     /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
     (void) set_config_option(name,
                              value,
                              (superuser() ? PGC_SUSET : PGC_USERSET),
-                             PGC_S_SESSION,
-                             is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET,
-                             true, 0, false);
+                             PGC_S_SESSION, set_action, true, 0, false);
 
     /* get the new current value */
     new_value = GetConfigOptionByName(name, NULL, false);
@@ -8032,7 +8256,6 @@ set_config_by_name(PG_FUNCTION_ARGS)
     PG_RETURN_TEXT_P(cstring_to_text(new_value));
 }
 
-
 /*
  * Common code for DefineCustomXXXVariable subroutines: allocate the
  * new variable's config struct and fill in generic fields.
@@ -8231,6 +8454,13 @@ reapply_stacked_values(struct config_generic *variable,
                                          WARNING, false);
                 break;
 
+            case GUC_NONXACT:
+                (void) set_config_option(name, curvalue,
+                                         curscontext, cursource,
+                                         GUC_ACTION_NONXACT, true,
+                                         WARNING, false);
+                break;
+
             case GUC_LOCAL:
                 (void) set_config_option(name, curvalue,
                                          curscontext, cursource,
@@ -8250,6 +8480,33 @@ reapply_stacked_values(struct config_generic *variable,
                                          GUC_ACTION_LOCAL, true,
                                          WARNING, false);
                 break;
+
+            case GUC_NONXACT_SET:
+                /* first, apply the masked value as SET */
+                (void) set_config_option(name, stack->masked.val.stringval,
+                                         stack->masked_scontext, PGC_S_SESSION,
+                                         GUC_ACTION_NONXACT, true,
+                                         WARNING, false);
+                /* then apply the current value as LOCAL */
+                (void) set_config_option(name, curvalue,
+                                         curscontext, cursource,
+                                         GUC_ACTION_SET, true,
+                                         WARNING, false);
+                break;
+
+            case GUC_NONXACT_LOCAL:
+                /* first, apply the masked value as SET */
+                (void) set_config_option(name, stack->masked.val.stringval,
+                                         stack->masked_scontext, PGC_S_SESSION,
+                                         GUC_ACTION_NONXACT, true,
+                                         WARNING, false);
+                /* then apply the current value as LOCAL */
+                (void) set_config_option(name, curvalue,
+                                         curscontext, cursource,
+                                         GUC_ACTION_LOCAL, true,
+                                         WARNING, false);
+                break;
+
         }
 
         /* If we successfully made a stack entry, adjust its nest level */
@@ -10228,6 +10485,370 @@ GUCArrayReset(ArrayType *array)
     return newarray;
 }
 
+Size
+GucShmemSize(void)
+{
+    Size size;
+
+    size = sizeof(GucRemoteSetting);
+
+    return size;
+}
+
+void
+GucShmemInit(void)
+{
+    Size    size;
+    bool    found;
+
+    size = sizeof(GucRemoteSetting);
+    remote_setting = (GucRemoteSetting *)
+        ShmemInitStruct("GUC remote setting", size, &found);
+
+    if (!found)
+    {
+        MemSet(remote_setting, 0, size);
+        SpinLockInit(&remote_setting->mutex);
+        ConditionVariableInit(&remote_setting->busy_cv);
+    }
+}
+
+/*
+ * set_backend_config: SQL callable function to set GUC variable of remote
+ * session.
+ */
+Datum
+set_backend_config(PG_FUNCTION_ARGS)
+{
+    int        target_pid    = PG_GETARG_INT32(0);
+    char   *name;
+    char   *value = NULL;
+
+    if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
+        ereport(ERROR,
+                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                 errmsg("invalid argument")));
+    name = text_to_cstring(PG_GETARG_TEXT_P(1));
+
+    if (!PG_ARGISNULL(2))
+        value = text_to_cstring(PG_GETARG_TEXT_P(2));
+
+    PG_RETURN_BOOL(set_backend_config_internal(target_pid, 0, name, value));
+}
+
+static bool
+set_backend_config_internal(int target_pid,    uint64 target_ts, char *name, char *value)
+{
+    PGPROC *target_proc;
+    PGPROC *proc;
+    uint64    target_timestamp;
+    bool    resetall = (name == NULL);
+    struct config_generic *record;
+
+    if (!resetall)
+    {
+        if (strlen(name) >= NAMEDATALEN)
+            ereport(ERROR,
+                    (errcode(ERRCODE_NAME_TOO_LONG),
+                     errmsg("name of GUC variable is too long")));
+        if (value && strlen(value) >= GUC_REMOTE_MAX_VALUE_LEN)
+            ereport(ERROR,
+                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                     errmsg("value is too long"),
+                     errdetail("Maximum acceptable length of value is %d",
+                               GUC_REMOTE_MAX_VALUE_LEN - 1)));
+    }
+
+    target_proc = BackendPidGetProc(target_pid);
+
+    /* target pid is coorect ? */
+    if (!target_proc)
+        ereport(ERROR,
+                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                 errmsg("PID %d is not a PostgreSQL server process",
+                        target_pid)));
+
+    /* XXXXX */
+    if (target_ts > 0 &&
+        target_proc->starttimestamp / 1000000 != target_ts / 1000000)
+        ereport(ERROR,
+                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                 errmsg("not a PostgreSQL server process")));
+
+    /* save timestamp for later consistency check */
+    target_timestamp = target_proc->starttimestamp;
+
+    /* The same condition to pg_signal_backend() */
+    if ((superuser_arg(target_proc->roleId) && !superuser()) ||
+        (!has_privs_of_role(GetUserId(), target_proc->roleId) &&
+         !has_privs_of_role(GetUserId(), DEFAULT_ROLE_SIGNAL_BACKENDID)))
+        ereport(ERROR,
+                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                 errmsg("insufficient privileges for the session")));
+
+    Assert (target_proc->backendId != InvalidBackendId);
+
+    if (!resetall)
+    {
+        record = find_option(name, false, ERROR);
+        if (record == NULL)
+            ereport(ERROR,
+                    (errcode(ERRCODE_UNDEFINED_OBJECT),
+                     errmsg("unrecognized configuration parameter \"%s\"",
+                            name)));
+
+        /* PG_SUSET is changebale but only by superusers  */
+        if (!superuser() && record->context == PGC_SUSET)
+            ereport(ERROR,
+                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                     errmsg("permission denied to set parameter \"%s\"",
+                            name)));
+
+        if ((record->context != PGC_USERSET && record->context != PGC_SUSET) ||
+            record->context == PGC_INTERNAL ||
+            (record->flags & GUC_DISALLOW_IN_FILE) ||
+            (record->flags & GUC_DISALLOW_IN_AUTO_FILE))
+            ereport(ERROR,
+                    (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
+                     errmsg("parameter \"%s\" cannot be changed",
+                            name)));
+
+        /*
+         * If a value is specified, verify that it's sane.
+         */
+        if (value)
+        {
+        union config_var_val newval;
+        void       *newextra = NULL;
+
+        /* Check that it's acceptable for the indicated parameter */
+        if (!parse_and_validate_value(record, name, value,
+                                      PGC_S_FILE, ERROR,
+                                      &newval, &newextra))
+            ereport(ERROR,
+                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                     errmsg("invalid value for parameter \"%s\": \"%s\"",
+                            name, value)));
+
+        if (record->vartype == PGC_STRING && newval.stringval != NULL)
+            free(newval.stringval);
+        if (newextra)
+            free(newextra);
+
+        /*
+         * We must also reject values containing newlines, because the
+         * grammar for config files doesn't support embedded newlines in
+         * string literals.
+         */
+        if (strchr(value, '\n'))
+            ereport(ERROR,
+                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                     errmsg("parameter value for SET must not contain a newline")));
+        }
+    }
+
+    /* Wait for another user to finish its work if any */
+    SpinLockAcquire(&remote_setting->mutex);
+    while (remote_setting->busy)
+    {
+        SpinLockRelease(&remote_setting->mutex);
+        ConditionVariableSleep(&remote_setting->busy_cv, WAIT_EVENT_REMOTE_GUC);
+        SpinLockAcquire(&remote_setting->mutex);
+    }
+
+    /* my turn, send a request */
+    Assert(!remote_setting->busy);
+
+    remote_setting->busy = true;
+    SpinLockRelease(&remote_setting->mutex);
+    remote_setting->target_pid = target_pid;
+    remote_setting->setting.source_pid = MyProcPid;
+    remote_setting->setting.context = superuser() ? PGC_SUSET : PGC_USERSET;
+
+    if (!resetall)
+    {
+        strncpy(remote_setting->setting.name, name, NAMEDATALEN);
+        remote_setting->setting.name[NAMEDATALEN - 1] = 0;
+        if (value)
+        {
+            strncpy(remote_setting->value, value, GUC_REMOTE_MAX_VALUE_LEN);
+            remote_setting->value[GUC_REMOTE_MAX_VALUE_LEN - 1] = 0;
+            remote_setting->setting.value = NULL;
+        }
+        remote_setting->setting.reset = (value == NULL);
+        remote_setting->setting.reset_all = false;
+    }
+    else
+    {
+        remote_setting->setting.reset_all = true;
+    }
+    remote_setting->sender_latch = MyLatch;
+
+    /* Check for the target is there yet */
+    proc = BackendPidGetProc(target_pid);
+    if (proc != target_proc ||
+        proc->pid != target_pid || proc->starttimestamp != target_timestamp)
+    {
+        /* let anybody work on the area */
+        SpinLockAcquire(&remote_setting->mutex);
+        remote_setting->busy = false;
+        SpinLockRelease(&remote_setting->mutex);
+        ConditionVariableBroadcast(&remote_setting->busy_cv);
+        
+        ereport(ERROR,
+                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                 errmsg("target session has gone")));
+    }
+    
+    
+    if (SendProcSignal(target_pid, PROCSIG_REMOTE_GUC, InvalidBackendId) < 0)
+    {
+        /* let anybody work on the area */
+        SpinLockAcquire(&remote_setting->mutex);
+        remote_setting->busy = false;
+        SpinLockRelease(&remote_setting->mutex);
+        ConditionVariableBroadcast(&remote_setting->busy_cv);
+        
+        ereport(ERROR,
+                (errmsg("could not signal backend with PID %d: %m", target_pid)));
+    }
+
+    return true;
+}
+
+
+void
+HandleRemoteGucSetInterrupt(void)
+{
+    Assert(remote_setting->busy);
+
+    /* check if any request is being sent to me */
+    if (remote_setting->target_pid == MyProcPid)
+    {
+        GucPendingSetting  *setting;
+        GucPendingSetting  *r = &remote_setting->setting;
+        bool                found;
+
+        if (r->reset_all)
+        {
+            if (pending_setting)
+            {
+                MemoryContextReset(CacheMemoryContext);
+                pending_setting = NULL;
+            }
+            ResetAllOptions(PGC_S_REMOTE);
+            goto finish;
+        }
+
+        if (!RemoteConfigMemoryContext)
+            RemoteConfigMemoryContext =
+                AllocSetContextCreate(CacheMemoryContext,
+                                      "Remote GUC setting context",
+                                      ALLOCSET_DEFAULT_SIZES);
+
+        if (!pending_setting)
+        {
+            HASHCTL hashctl;
+
+            MemSet(&hashctl, 0, sizeof(hashctl));
+            hashctl.keysize = NAMEDATALEN;
+            hashctl.entrysize = sizeof(GucPendingSetting);
+            hashctl.hcxt = RemoteConfigMemoryContext;
+            pending_setting = hash_create("Pending remote GUC Changes",
+                                          8, &hashctl,
+                                          HASH_ELEM | HASH_CONTEXT);
+        }
+
+        /* Just overwrite existing entry */
+        setting = hash_search(pending_setting, r->name, HASH_ENTER, &found);
+        setting->context    = r->context;
+        setting->reset        = r->reset;
+        setting->reset_all    = r->reset_all;
+        setting->source_pid    = r->source_pid;
+
+        if (!found)
+            setting->value = NULL;
+
+        /* free existing value if new value is given or to reset */
+        if (setting->value &&
+            (r->reset ||
+             strcmp(setting->value, remote_setting->value) != 0))
+        {
+            pfree(setting->value);
+            setting->value = NULL;
+        }
+
+        /* non-null value means no use copying the value */
+        if (!r->reset && setting->value == NULL)
+            setting->value = MemoryContextStrdup(RemoteConfigMemoryContext,
+                                                 remote_setting->value);
+    }
+
+finish:
+    InterruptPending = true;
+    RemoteGucChangePending = true;
+
+    /* release the communication area */
+    SpinLockAcquire(&remote_setting->mutex);
+    remote_setting->busy = false;
+    SpinLockRelease(&remote_setting->mutex);
+    ConditionVariableBroadcast(&remote_setting->busy_cv);
+}
+
+void
+HandleGucRemoteChanges(void)
+{
+    HASH_SEQ_STATUS        seq;
+    GucPendingSetting  *entry;
+
+    RemoteGucChangePending = false;
+
+    /* reset all discards the hash, must return in the case */
+    if (!pending_setting)
+        return;
+
+    hash_seq_init(&seq, pending_setting);
+
+    while ((entry = hash_seq_search(&seq)))
+    {
+        int scres;
+        char *preval;
+        const char *valtmp = GetConfigOption(entry->name, true, false);
+
+        if (!valtmp)
+            valtmp = "";
+
+        preval = pstrdup(valtmp);
+
+        scres = set_config_option(entry->name, entry->value, entry->context,
+                                  PGC_S_REMOTE, GUC_ACTION_NONXACT,
+                                  true, WARNING, false);
+        if (scres > 0)
+        {
+            if (preval)
+            {
+                const char *postval = GetConfigOption(entry->name, true, false);
+                if (!postval)
+                    postval = "";
+                if (strcmp(preval, postval) != 0)
+                    ereport(NOTICE,
+                            (errmsg("GUC variable \"%s\" is changed to \"%s\" by request from backend with PID %d",
+                                    entry->name, postval, entry->source_pid)));
+            }
+        }
+        else if (scres == 0)
+            ereport(LOG,
+                    (errmsg("GUC variable \"%s\" could not be changed by request from backend with PID %d",
+                            entry->name, entry->source_pid)));
+
+        if (preval)
+            pfree(preval);
+    }
+
+    MemoryContextReset(RemoteConfigMemoryContext);
+    pending_setting = NULL;
+}
+
 /*
  * Validate a proposed option setting for GUCArrayAdd/Delete/Reset.
  *
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index b8de13f03b..e93a7b9938 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5700,8 +5700,8 @@
   proargtypes => 'text bool', prosrc => 'show_config_by_name_missing_ok' },
 { oid => '2078', descr => 'SET X as a function',
   proname => 'set_config', proisstrict => 'f', provolatile => 'v',
-  proparallel => 'u', prorettype => 'text', proargtypes => 'text text bool',
-  prosrc => 'set_config_by_name' },
+  proparallel => 'u', prorettype => 'text',
+  proargtypes => 'text text bool bool', prosrc => 'set_config_by_name' },
 { oid => '2084', descr => 'SHOW ALL as a function',
   proname => 'pg_show_all_settings', prorows => '1000', proretset => 't',
   provolatile => 's', prorettype => 'record', proargtypes => '',
@@ -9669,6 +9669,12 @@
   proargmodes => '{o,o,o,o,o,o,o,o,o,o,o}',
   proargnames =>
'{slot_name,plugin,slot_type,datoid,temporary,active,active_pid,xmin,catalog_xmin,restart_lsn,confirmed_flush_lsn}',
   prosrc => 'pg_get_replication_slots' },
+{ oid => '3424',
+  descr => 'set config of another backend',
+  proname => 'pg_set_backend_config', proisstrict => 'f',
+  proretset => 'f', provolatile => 'v', proparallel => 'u',
+  prorettype => 'bool', proargtypes => 'int4 text text',
+  prosrc => 'set_backend_config' },
 { oid => '3786', descr => 'set up a logical replication slot',
   proname => 'pg_create_logical_replication_slot', provolatile => 'v',
   proparallel => 'u', prorettype => 'record', proargtypes => 'name name bool',
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index fbe2dc14a7..74e4fe2f0d 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -407,6 +407,7 @@ typedef enum NodeTag
     T_RefreshMatViewStmt,
     T_ReplicaIdentityStmt,
     T_AlterSystemStmt,
+    T_AlterSessionStmt,
     T_CreatePolicyStmt,
     T_AlterPolicyStmt,
     T_CreateTransformStmt,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 4ec8a83541..98658ce714 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -3121,6 +3121,18 @@ typedef struct AlterSystemStmt
     VariableSetStmt *setstmt;    /* SET subcommand */
 } AlterSystemStmt;
 
+/* ----------------------
+ *        Alter Session Statement
+ * ----------------------
+ */
+typedef struct AlterSessionStmt
+{
+    NodeTag        type;
+    DefElem       *sessionopt;        /* session property */
+    VariableSetStmt *setstmt;    /* SET subcommand */
+    bool        immediate;        /* reload immediately */
+} AlterSessionStmt;
+
 /* ----------------------
  *        Cluster Statement (support pbrown's cluster index implementation)
  * ----------------------
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 88a75fb798..071deae55b 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -833,7 +833,8 @@ typedef enum
     WAIT_EVENT_REPLICATION_ORIGIN_DROP,
     WAIT_EVENT_REPLICATION_SLOT_DROP,
     WAIT_EVENT_SAFE_SNAPSHOT,
-    WAIT_EVENT_SYNC_REP
+    WAIT_EVENT_SYNC_REP,
+    WAIT_EVENT_REMOTE_GUC
 } WaitEventIPC;
 
 /* ----------
diff --git a/src/include/storage/procsignal.h b/src/include/storage/procsignal.h
index 9f2f965d5c..040877f5eb 100644
--- a/src/include/storage/procsignal.h
+++ b/src/include/storage/procsignal.h
@@ -42,6 +42,9 @@ typedef enum
     PROCSIG_RECOVERY_CONFLICT_BUFFERPIN,
     PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK,
 
+    /* Remote GUC setting */
+    PROCSIG_REMOTE_GUC,
+
     NUM_PROCSIGNALS                /* Must be last! */
 } ProcSignalReason;
 
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index c07e7b945e..c53e0c85c4 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -14,6 +14,7 @@
 #define GUC_H
 
 #include "nodes/parsenodes.h"
+#include "parser/parse_node.h"
 #include "tcop/dest.h"
 #include "utils/array.h"
 
@@ -117,7 +118,8 @@ typedef enum
     PGC_S_OVERRIDE,                /* special case to forcibly set default */
     PGC_S_INTERACTIVE,            /* dividing line for error reporting */
     PGC_S_TEST,                    /* test per-database or per-user setting */
-    PGC_S_SESSION                /* SET command */
+    PGC_S_SESSION,                /* SET command */
+    PGC_S_REMOTE                /* remote setting */
 } GucSource;
 
 /*
@@ -193,7 +195,8 @@ typedef enum
     /* Types of set_config_option actions */
     GUC_ACTION_SET,                /* regular SET command */
     GUC_ACTION_LOCAL,            /* SET LOCAL command */
-    GUC_ACTION_SAVE                /* function SET option, or temp assignment */
+    GUC_ACTION_SAVE,            /* function SET option, or temp assignment */
+    GUC_ACTION_NONXACT            /* transactional setting */
 } GucAction;
 
 #define GUC_QUALIFIER_SEPARATOR '.'
@@ -269,6 +272,8 @@ extern int    tcp_keepalives_idle;
 extern int    tcp_keepalives_interval;
 extern int    tcp_keepalives_count;
 
+extern volatile bool RemoteGucChangePending;
+
 #ifdef TRACE_SORT
 extern bool trace_sort;
 #endif
@@ -276,6 +281,11 @@ extern bool trace_sort;
 /*
  * Functions exported by guc.c
  */
+extern Size GucShmemSize(void);
+extern void GucShmemInit(void);
+extern Datum set_backend_setting(PG_FUNCTION_ARGS);
+extern void HandleRemoteGucSetInterrupt(void);
+extern void HandleGucRemoteChanges(void);
 extern void SetConfigOption(const char *name, const char *value,
                 GucContext context, GucSource source);
 
@@ -353,7 +363,7 @@ extern int    GetConfigOptionFlags(const char *name, bool missing_ok);
 extern void ProcessConfigFile(GucContext context);
 extern void InitializeGUCOptions(void);
 extern bool SelectConfigFiles(const char *userDoption, const char *progname);
-extern void ResetAllOptions(void);
+extern void ResetAllOptions(GucSource src);
 extern void AtStart_GUC(void);
 extern int    NewGUCNestLevel(void);
 extern void AtEOXact_GUC(bool isCommit, int nestLevel);
@@ -367,6 +377,8 @@ extern int set_config_option(const char *name, const char *value,
                   GucAction action, bool changeVal, int elevel,
                   bool is_reload);
 extern void AlterSystemSetConfigFile(AlterSystemStmt *setstmt);
+extern void AlterSessionSetRemoteConfig(ParseState *pstate,
+                                        AlterSessionStmt *setstmt);
 extern char *GetConfigOptionByName(const char *name, const char **varname,
                       bool missing_ok);
 extern void GetConfigOptionByNum(int varnum, const char **values, bool *noshow);
@@ -395,6 +407,9 @@ extern Size EstimateGUCStateSpace(void);
 extern void SerializeGUCState(Size maxsize, char *start_address);
 extern void RestoreGUCState(void *gucstate);
 
+/* Remote GUC setting */
+extern void HandleGucRemoteChanges(void);
+
 /* Support for messages reported from GUC check hooks */
 
 extern PGDLLIMPORT char *GUC_check_errmsg_string;
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index a0970b2e1c..c00520e90c 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -115,7 +115,10 @@ typedef enum
     GUC_SAVE,                    /* entry caused by function SET option */
     GUC_SET,                    /* entry caused by plain SET command */
     GUC_LOCAL,                    /* entry caused by SET LOCAL command */
-    GUC_SET_LOCAL                /* entry caused by SET then SET LOCAL */
+    GUC_NONXACT,                /* entry caused by non-transactional ops */
+    GUC_SET_LOCAL,                /* entry caused by SET then SET LOCAL */
+    GUC_NONXACT_SET,            /* entry caused by NONXACT then SET */
+    GUC_NONXACT_LOCAL            /* entry caused by NONXACT then (SET)LOCAL */
 } GucStackState;
 
 typedef struct guc_stack
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index b0d7351145..2d19697a8c 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -476,6 +476,229 @@ SELECT '2006-08-13 12:34:56'::timestamptz;
  2006-08-13 12:34:56-07
 (1 row)
 
+-- NONXACT followed by SET, SET LOCAL through COMMIT
+BEGIN;
+SELECT set_config('work_mem', '128kB', false, true); -- NONXACT
+ set_config 
+------------
+ 128kB
+(1 row)
+
+SET work_mem to '256kB';
+SET LOCAL work_mem to '512kB';
+SHOW work_mem;    -- must see 512kB
+ work_mem 
+----------
+ 512kB
+(1 row)
+
+COMMIT;
+SHOW work_mem;    -- must see 256kB
+ work_mem 
+----------
+ 256kB
+(1 row)
+
+-- NONXACT followed by SET, SET LOCAL through ROLLBACK
+BEGIN;
+SELECT set_config('work_mem', '128kB', false, true); -- NONXACT
+ set_config 
+------------
+ 128kB
+(1 row)
+
+SET work_mem to '256kB';
+SET LOCAL work_mem to '512kB';
+SHOW work_mem;    -- must see 512kB
+ work_mem 
+----------
+ 512kB
+(1 row)
+
+ROLLBACK;
+SHOW work_mem;    -- must see 128kB
+ work_mem 
+----------
+ 128kB
+(1 row)
+
+-- SET, SET LOCAL followed by NONXACT through COMMIT
+BEGIN;
+SET work_mem to '256kB';
+SET LOCAL work_mem to '512kB';
+SELECT set_config('work_mem', '128kB', false, true); -- NONXACT
+ set_config 
+------------
+ 128kB
+(1 row)
+
+SHOW work_mem;    -- must see 128kB
+ work_mem 
+----------
+ 128kB
+(1 row)
+
+COMMIT;
+SHOW work_mem;    -- must see 128kB
+ work_mem 
+----------
+ 128kB
+(1 row)
+
+-- SET, SET LOCAL followed by NONXACT through ROLLBACK
+BEGIN;
+SET work_mem to '256kB';
+SET LOCAL work_mem to '512kB';
+SELECT set_config('work_mem', '128kB', false, true); -- NONXACT
+ set_config 
+------------
+ 128kB
+(1 row)
+
+SHOW work_mem;    -- must see 128kB
+ work_mem 
+----------
+ 128kB
+(1 row)
+
+ROLLBACK;
+SHOW work_mem;    -- must see 128kB
+ work_mem 
+----------
+ 128kB
+(1 row)
+
+-- NONXACT and SAVEPOINT
+SET work_mem TO '64kB';
+BEGIN;
+SET work_mem TO '128kB';
+SAVEPOINT a;
+SELECT set_config('work_mem', '256kB', false, true); -- NONXACT
+ set_config 
+------------
+ 256kB
+(1 row)
+
+SHOW work_mem;
+ work_mem 
+----------
+ 256kB
+(1 row)
+
+SET LOCAL work_mem TO '384kB';
+RELEASE SAVEPOINT a;
+SHOW work_mem; -- will see 384kB
+ work_mem 
+----------
+ 384kB
+(1 row)
+
+COMMIT;
+SHOW work_mem; -- will see 256kB
+ work_mem 
+----------
+ 256kB
+(1 row)
+
+--
+SET work_mem TO '64kB';
+BEGIN;
+SET work_mem TO '128kB';
+SAVEPOINT a;
+SELECT set_config('work_mem', '256kB', false, true); -- NONXACT
+ set_config 
+------------
+ 256kB
+(1 row)
+
+SHOW work_mem;
+ work_mem 
+----------
+ 256kB
+(1 row)
+
+SET LOCAL work_mem TO '384kB';
+ROLLBACK TO SAVEPOINT a;
+SHOW work_mem; -- will see 256kB
+ work_mem 
+----------
+ 256kB
+(1 row)
+
+ROLLBACK;
+SHOW work_mem; -- will see 256kB
+ work_mem 
+----------
+ 256kB
+(1 row)
+
+--
+SET work_mem TO '64kB';
+BEGIN;
+SET work_mem TO '128kB';
+SET LOCAL work_mem TO '384kB';
+SAVEPOINT a;
+SELECT set_config('work_mem', '256kB', false, true); -- NONXACT
+ set_config 
+------------
+ 256kB
+(1 row)
+
+SHOW work_mem;
+ work_mem 
+----------
+ 256kB
+(1 row)
+
+SET LOCAL work_mem TO '384kB';
+RELEASE SAVEPOINT a;
+SHOW work_mem; -- will see 384kB
+ work_mem 
+----------
+ 384kB
+(1 row)
+
+ROLLBACK;
+SHOW work_mem; -- will see 256kB
+ work_mem 
+----------
+ 256kB
+(1 row)
+
+--
+SET work_mem TO '64kB';
+BEGIN;
+SET work_mem TO '128kB';
+SET LOCAL work_mem TO '384kB';
+SAVEPOINT a;
+SELECT set_config('work_mem', '256kB', false, true); -- NONXACT
+ set_config 
+------------
+ 256kB
+(1 row)
+
+SHOW work_mem;
+ work_mem 
+----------
+ 256kB
+(1 row)
+
+SET LOCAL work_mem TO '384kB';
+ROLLBACK TO SAVEPOINT a;
+SHOW work_mem; -- will see 256kB
+ work_mem 
+----------
+ 256kB
+(1 row)
+
+COMMIT;
+SHOW work_mem; -- will see 256kB
+ work_mem 
+----------
+ 256kB
+(1 row)
+
+SET work_mem TO DEFAULT;
 --
 -- Test RESET.  We use datestyle because the reset value is forced by
 -- pg_regress, so it doesn't depend on the installation's configuration.
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index 3b854ac496..bbb91aaa98 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -133,6 +133,94 @@ SHOW vacuum_cost_delay;
 SHOW datestyle;
 SELECT '2006-08-13 12:34:56'::timestamptz;
 
+-- NONXACT followed by SET, SET LOCAL through COMMIT
+BEGIN;
+SELECT set_config('work_mem', '128kB', false, true); -- NONXACT
+SET work_mem to '256kB';
+SET LOCAL work_mem to '512kB';
+SHOW work_mem;    -- must see 512kB
+COMMIT;
+SHOW work_mem;    -- must see 256kB
+
+-- NONXACT followed by SET, SET LOCAL through ROLLBACK
+BEGIN;
+SELECT set_config('work_mem', '128kB', false, true); -- NONXACT
+SET work_mem to '256kB';
+SET LOCAL work_mem to '512kB';
+SHOW work_mem;    -- must see 512kB
+ROLLBACK;
+SHOW work_mem;    -- must see 128kB
+
+-- SET, SET LOCAL followed by NONXACT through COMMIT
+BEGIN;
+SET work_mem to '256kB';
+SET LOCAL work_mem to '512kB';
+SELECT set_config('work_mem', '128kB', false, true); -- NONXACT
+SHOW work_mem;    -- must see 128kB
+COMMIT;
+SHOW work_mem;    -- must see 128kB
+
+-- SET, SET LOCAL followed by NONXACT through ROLLBACK
+BEGIN;
+SET work_mem to '256kB';
+SET LOCAL work_mem to '512kB';
+SELECT set_config('work_mem', '128kB', false, true); -- NONXACT
+SHOW work_mem;    -- must see 128kB
+ROLLBACK;
+SHOW work_mem;    -- must see 128kB
+
+-- NONXACT and SAVEPOINT
+SET work_mem TO '64kB';
+BEGIN;
+SET work_mem TO '128kB';
+SAVEPOINT a;
+SELECT set_config('work_mem', '256kB', false, true); -- NONXACT
+SHOW work_mem;
+SET LOCAL work_mem TO '384kB';
+RELEASE SAVEPOINT a;
+SHOW work_mem; -- will see 384kB
+COMMIT;
+SHOW work_mem; -- will see 256kB
+--
+SET work_mem TO '64kB';
+BEGIN;
+SET work_mem TO '128kB';
+SAVEPOINT a;
+SELECT set_config('work_mem', '256kB', false, true); -- NONXACT
+SHOW work_mem;
+SET LOCAL work_mem TO '384kB';
+ROLLBACK TO SAVEPOINT a;
+SHOW work_mem; -- will see 256kB
+ROLLBACK;
+SHOW work_mem; -- will see 256kB
+--
+SET work_mem TO '64kB';
+BEGIN;
+SET work_mem TO '128kB';
+SET LOCAL work_mem TO '384kB';
+SAVEPOINT a;
+SELECT set_config('work_mem', '256kB', false, true); -- NONXACT
+SHOW work_mem;
+SET LOCAL work_mem TO '384kB';
+RELEASE SAVEPOINT a;
+SHOW work_mem; -- will see 384kB
+ROLLBACK;
+SHOW work_mem; -- will see 256kB
+--
+SET work_mem TO '64kB';
+BEGIN;
+SET work_mem TO '128kB';
+SET LOCAL work_mem TO '384kB';
+SAVEPOINT a;
+SELECT set_config('work_mem', '256kB', false, true); -- NONXACT
+SHOW work_mem;
+SET LOCAL work_mem TO '384kB';
+ROLLBACK TO SAVEPOINT a;
+SHOW work_mem; -- will see 256kB
+COMMIT;
+SHOW work_mem; -- will see 256kB
+
+SET work_mem TO DEFAULT;
 --
 -- Test RESET.  We use datestyle because the reset value is forced by
 -- pg_regress, so it doesn't depend on the installation's configuration.
-- 
2.16.3


В списке pgsql-hackers по дате отправления:

Предыдущее
От: Michael Paquier
Дата:
Сообщение: Re: reloption to prevent VACUUM from truncating empty pages at theend of relation
Следующее
От: "Jamison, Kirk"
Дата:
Сообщение: RE: pg_upgrade: Pass -j down to vacuumdb