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

