diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index e42f301..40c46cc 100644
*** a/doc/src/sgml/config.sgml
--- b/doc/src/sgml/config.sgml
*************** local0.*    /var/log/postgresql
*** 2881,2886 ****
--- 2881,2904 ----
       <variablelist>
  
       <varlistentry>
+       <term><varname>application_name</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>application_name</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         The <varname>application_name</varname> is typically set by an 
+         application upon connection to the server. The value will be included
+         in CSV logs and may be included in the <varname>log_line_prefix</varname>.
+         In addition, it will be included in the <literal>pg_stat_activity</> view.
+         Only ASCII characters with decimal values between 32 and 126 may be used
+         in the <varname>application_name</varname> configuration variable. Other 
+         values will be replaced with the <literal>?</literal> character.
+        </para>
+       </listitem>
+      </varlistentry>
+ 	 
+      <varlistentry>
        <term><varname>debug_print_parse</varname> (<type>boolean</type>)</term>
        <term><varname>debug_print_rewritten</varname> (<type>boolean</type>)</term>
        <term><varname>debug_print_plan</varname> (<type>boolean</type>)</term>
*************** CREATE TABLE postgres_log
*** 3325,3330 ****
--- 3343,3349 ----
    query text,
    query_pos integer,
    location text,
+   application_name text,
    PRIMARY KEY (session_id, session_line_num)
  );
  </programlisting>
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 86affb0..1337363 100644
*** a/doc/src/sgml/libpq.sgml
--- b/doc/src/sgml/libpq.sgml
***************
*** 248,253 ****
--- 248,280 ----
            </para>
           </listitem>
          </varlistentry>
+ 		
+         <varlistentry id="libpq-connect-application-name" xreflabel="application_name">
+          <term><literal>application_name</literal></term>
+          <listitem>
+           <para>
+            Allows an application to specify a value for the <literal>application_name</>
+ 		   configuration variable, the value of which may be included in logging 
+ 		   output and monitoring data from views such as <literal>pg_stat_activity</>.
+           </para>
+          </listitem>
+         </varlistentry>
+ 		
+         <varlistentry id="libpq-connect-fallback-application-name" xreflabel="fallback_application_name">
+          <term><literal>fallback_application_name</literal></term>
+          <listitem>
+           <para>
+            Allows an application to specify a fallback value for the 
+ 		   <literal>application_name</> configuration variable. This value
+ 		   is used if neither the <literal>application_name</> connection 
+ 		   string option or <envar>PGCLIENTENCODING</envar> are set, 
+ 		   which offers the application a way to allow the enviroment to 
+ 		   override a compiled in default. This is useful when scripting 
+ 		   generic utilities to perform specific tasks where a bespoke
+ 		   application name is desirable.
+ 		  </para>
+          </listitem>
+         </varlistentry>
  
          <varlistentry id="libpq-connect-tty" xreflabel="tty">
           <term><literal>tty</literal></term>
*************** myEventProc(PGEventId evtId, void *evtIn
*** 5781,5786 ****
--- 5808,5823 ----
        linkend="libpq-connect-options"> connection parameter.
       </para>
      </listitem>
+ 	
+     <listitem>
+      <para>
+       <indexterm>
+        <primary><envar>PGAPPNAME</envar></primary>
+       </indexterm>
+       <envar>PGAPPNAME</envar> behaves the same as <xref
+       linkend="libpq-connect-application-name"> connection parameter.
+      </para>
+     </listitem>
  
      <listitem>
       <para>
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 31da86d..580d2fa 100644
*** a/doc/src/sgml/monitoring.sgml
--- b/doc/src/sgml/monitoring.sgml
*************** postgres: <replaceable>user</> <replacea
*** 238,249 ****
        name, process <acronym>ID</>, user OID, user name, current query,
        query's waiting status, time at which the current transaction and
        current query began execution, time at which the process was
!       started, and client's address and port number.  The columns that
!       report data on the current query are available unless the parameter
!       <varname>track_activities</varname> has been turned off.
!       Furthermore, these columns are only visible if the user examining
!       the view is a superuser or the same as the user owning the process
!       being reported on.
       </entry>
       </row>
  
--- 238,249 ----
        name, process <acronym>ID</>, user OID, user name, current query,
        query's waiting status, time at which the current transaction and
        current query began execution, time at which the process was
!       started, client's address and port number and application name.
! 	  The columns that report data on the current query are available 
! 	  unless the parameter <varname>track_activities</varname> has been 
! 	  turned off. Furthermore, these columns are only visible if the user 
! 	  examining the view is a superuser or the same as the user owning the 
! 	  process being reported on.
       </entry>
       </row>
  
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 98e9685..6d11a14 100644
*** a/src/backend/catalog/system_views.sql
--- b/src/backend/catalog/system_views.sql
*************** CREATE VIEW pg_stat_activity AS 
*** 339,345 ****
              S.query_start,
              S.backend_start,
              S.client_addr,
!             S.client_port
      FROM pg_database D, pg_stat_get_activity(NULL) AS S, pg_authid U
      WHERE S.datid = D.oid AND 
              S.usesysid = U.oid;
--- 339,346 ----
              S.query_start,
              S.backend_start,
              S.client_addr,
!             S.client_port,
!             S.application_name
      FROM pg_database D, pg_stat_get_activity(NULL) AS S, pg_authid U
      WHERE S.datid = D.oid AND 
              S.usesysid = U.oid;
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 1a818ef..519cef4 100644
*** a/src/backend/postmaster/pgstat.c
--- b/src/backend/postmaster/pgstat.c
*************** pgstat_fetch_global(void)
*** 2074,2079 ****
--- 2074,2080 ----
  static PgBackendStatus *BackendStatusArray = NULL;
  static PgBackendStatus *MyBEEntry = NULL;
  static char *BackendActivityBuffer = NULL;
+ static char *BackendAppnameBuffer = NULL;
  
  
  /*
*************** BackendStatusShmemSize(void)
*** 2090,2096 ****
  }
  
  /*
!  * Initialize the shared status array and activity string buffer during
   * postmaster startup.
   */
  void
--- 2091,2097 ----
  }
  
  /*
!  * Initialize the shared status array and activity/appname string buffers during
   * postmaster startup.
   */
  void
*************** CreateSharedBackendStatus(void)
*** 2099,2105 ****
  	Size		size;
  	bool		found;
  	int			i;
! 	char	   *buffer;
  
  	/* Create or attach to the shared array */
  	size = mul_size(sizeof(PgBackendStatus), MaxBackends);
--- 2100,2106 ----
  	Size		size;
  	bool		found;
  	int			i;
! 	char	   *activitybuffer, *appnamebuffer;
  
  	/* Create or attach to the shared array */
  	size = mul_size(sizeof(PgBackendStatus), MaxBackends);
*************** CreateSharedBackendStatus(void)
*** 2124,2134 ****
  		MemSet(BackendActivityBuffer, 0, size);
  
  		/* Initialize st_activity pointers. */
! 		buffer = BackendActivityBuffer;
  		for (i = 0; i < MaxBackends; i++)
  		{
! 			BackendStatusArray[i].st_activity = buffer;
! 			buffer += pgstat_track_activity_query_size;
  		}
  	}
  }
--- 2125,2153 ----
  		MemSet(BackendActivityBuffer, 0, size);
  
  		/* Initialize st_activity pointers. */
! 		activitybuffer = BackendActivityBuffer;
  		for (i = 0; i < MaxBackends; i++)
  		{
! 			BackendStatusArray[i].st_activity = activitybuffer;
! 			activitybuffer += pgstat_track_activity_query_size;
! 		}
! 	}
! 	
! 	/* Create or attach to the shared appname buffer */
! 	size = mul_size(NAMEDATALEN, MaxBackends);
! 	BackendAppnameBuffer = (char *)
! 		ShmemInitStruct("Backend Application Name Buffer", size, &found);
! 	
! 	if (!found)
! 	{
! 		MemSet(BackendAppnameBuffer, 0, size);
! 		
! 		/* Initialize st_activity pointers. */
! 		appnamebuffer = BackendAppnameBuffer;
! 		for (i = 0; i < MaxBackends; i++)
! 		{
! 			BackendStatusArray[i].st_appname = appnamebuffer;
! 			appnamebuffer += NAMEDATALEN;
  		}
  	}
  }
*************** pgstat_bestart(void)
*** 2169,2175 ****
  	TimestampTz proc_start_timestamp;
  	Oid			userid;
  	SockAddr	clientaddr;
! 	volatile PgBackendStatus *beentry;
  
  	/*
  	 * To minimize the time spent modifying the PgBackendStatus entry, fetch
--- 2188,2194 ----
  	TimestampTz proc_start_timestamp;
  	Oid			userid;
  	SockAddr	clientaddr;
! 	volatile    PgBackendStatus *beentry;
  
  	/*
  	 * To minimize the time spent modifying the PgBackendStatus entry, fetch
*************** pgstat_bestart(void)
*** 2214,2221 ****
--- 2233,2242 ----
  	beentry->st_userid = userid;
  	beentry->st_clientaddr = clientaddr;
  	beentry->st_waiting = false;
+ 	beentry->st_appname[0] = '\0';
  	beentry->st_activity[0] = '\0';
  	/* Also make sure the last byte in the string area is always 0 */
+ 	beentry->st_appname[NAMEDATALEN - 1] = '\0';
  	beentry->st_activity[pgstat_track_activity_query_size - 1] = '\0';
  
  	beentry->st_changecount++;
*************** pgstat_report_activity(const char *cmd_s
*** 2271,2277 ****
  {
  	volatile PgBackendStatus *beentry = MyBEEntry;
  	TimestampTz start_timestamp;
! 	int			len;
  
  	TRACE_POSTGRESQL_STATEMENT_STATUS(cmd_str);
  
--- 2292,2298 ----
  {
  	volatile PgBackendStatus *beentry = MyBEEntry;
  	TimestampTz start_timestamp;
! 	int			activity_len, appname_len;
  
  	TRACE_POSTGRESQL_STATEMENT_STATUS(cmd_str);
  
*************** pgstat_report_activity(const char *cmd_s
*** 2284,2291 ****
  	 */
  	start_timestamp = GetCurrentStatementStartTimestamp();
  
! 	len = strlen(cmd_str);
! 	len = pg_mbcliplen(cmd_str, len, pgstat_track_activity_query_size - 1);
  
  	/*
  	 * Update my status entry, following the protocol of bumping
--- 2305,2315 ----
  	 */
  	start_timestamp = GetCurrentStatementStartTimestamp();
  
! 	activity_len = strlen(cmd_str);
! 	activity_len = pg_mbcliplen(cmd_str, activity_len, pgstat_track_activity_query_size - 1);
! 	
! 	appname_len = strlen(application_name);
! 	appname_len = pg_mbcliplen(application_name, appname_len, NAMEDATALEN - 1);
  
  	/*
  	 * Update my status entry, following the protocol of bumping
*************** pgstat_report_activity(const char *cmd_s
*** 2295,2302 ****
  	beentry->st_changecount++;
  
  	beentry->st_activity_start_timestamp = start_timestamp;
! 	memcpy((char *) beentry->st_activity, cmd_str, len);
! 	beentry->st_activity[len] = '\0';
  
  	beentry->st_changecount++;
  	Assert((beentry->st_changecount & 1) == 0);
--- 2319,2328 ----
  	beentry->st_changecount++;
  
  	beentry->st_activity_start_timestamp = start_timestamp;
! 	memcpy((char *) beentry->st_appname, application_name, appname_len);
! 	beentry->st_appname[appname_len] = '\0';
! 	memcpy((char *) beentry->st_activity, cmd_str, activity_len);
! 	beentry->st_activity[activity_len] = '\0';
  
  	beentry->st_changecount++;
  	Assert((beentry->st_changecount & 1) == 0);
*************** pgstat_read_current_status(void)
*** 2364,2370 ****
  	volatile PgBackendStatus *beentry;
  	PgBackendStatus *localtable;
  	PgBackendStatus *localentry;
! 	char	   *localactivity;
  	int			i;
  
  	Assert(!pgStatRunningInCollector);
--- 2390,2396 ----
  	volatile PgBackendStatus *beentry;
  	PgBackendStatus *localtable;
  	PgBackendStatus *localentry;
! 	char	   *localactivity, *localappname;
  	int			i;
  
  	Assert(!pgStatRunningInCollector);
*************** pgstat_read_current_status(void)
*** 2379,2384 ****
--- 2405,2413 ----
  	localactivity = (char *)
  		MemoryContextAlloc(pgStatLocalContext,
  						   pgstat_track_activity_query_size * MaxBackends);
+ 	localappname = (char *)
+ 		MemoryContextAlloc(pgStatLocalContext,
+ 					   NAMEDATALEN * MaxBackends);
  	localNumBackends = 0;
  
  	beentry = BackendStatusArray;
*************** pgstat_read_current_status(void)
*** 2405,2410 ****
--- 2434,2441 ----
  				 * strcpy is safe even if the string is modified concurrently,
  				 * because there's always a \0 at the end of the buffer.
  				 */
+ 				strcpy(localappname, (char *) beentry->st_appname);
+ 				localentry->st_appname = localappname;
  				strcpy(localactivity, (char *) beentry->st_activity);
  				localentry->st_activity = localactivity;
  			}
*************** pgstat_read_current_status(void)
*** 2423,2428 ****
--- 2454,2460 ----
  		{
  			localentry++;
  			localactivity += pgstat_track_activity_query_size;
+ 			localappname += NAMEDATALEN;
  			localNumBackends++;
  		}
  	}
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 39bb558..03243a4 100644
*** a/src/backend/utils/adt/pgstatfuncs.c
--- b/src/backend/utils/adt/pgstatfuncs.c
*************** pg_stat_get_activity(PG_FUNCTION_ARGS)
*** 416,422 ****
  
  		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
  
! 		tupdesc = CreateTemplateTupleDesc(10, false);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "datid", OIDOID, -1, 0);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "procpid", INT4OID, -1, 0);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "usesysid", OIDOID, -1, 0);
--- 416,422 ----
  
  		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
  
! 		tupdesc = CreateTemplateTupleDesc(11, false);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "datid", OIDOID, -1, 0);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "procpid", INT4OID, -1, 0);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "usesysid", OIDOID, -1, 0);
*************** pg_stat_get_activity(PG_FUNCTION_ARGS)
*** 427,432 ****
--- 427,433 ----
  		TupleDescInitEntry(tupdesc, (AttrNumber) 8, "backend_start", TIMESTAMPTZOID, -1, 0);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 9, "client_addr", INETOID, -1, 0);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 10, "client_port", INT4OID, -1, 0);
+ 		TupleDescInitEntry(tupdesc, (AttrNumber) 11, "application_name", TEXTOID, -1, 0);
  
  		funcctx->tuple_desc = BlessTupleDesc(tupdesc);
  
*************** pg_stat_get_activity(PG_FUNCTION_ARGS)
*** 478,485 ****
  	if (funcctx->call_cntr < funcctx->max_calls)
  	{
  		/* for each row */
! 		Datum		values[10];
! 		bool		nulls[10];
  		HeapTuple	tuple;
  		PgBackendStatus *beentry;
  		SockAddr	zero_clientaddr;
--- 479,486 ----
  	if (funcctx->call_cntr < funcctx->max_calls)
  	{
  		/* for each row */
! 		Datum		values[11];
! 		bool		nulls[11];
  		HeapTuple	tuple;
  		PgBackendStatus *beentry;
  		SockAddr	zero_clientaddr;
*************** pg_stat_get_activity(PG_FUNCTION_ARGS)
*** 598,604 ****
--- 599,613 ----
  					nulls[8] = true;
  					nulls[9] = true;
  				}
+ 							
  			}
+ 			
+ 			/* application name */
+ 			if (beentry->st_appname)	
+ 			    values[10] = CStringGetTextDatum(beentry->st_appname);
+ 			else
+ 				nulls[10] = true;
+ 
  		}
  		else
  		{
*************** pg_stat_get_activity(PG_FUNCTION_ARGS)
*** 610,615 ****
--- 619,625 ----
  			nulls[7] = true;
  			nulls[8] = true;
  			nulls[9] = true;
+ 			nulls[10] = true;
  		}
  
  		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 61751bb..8b1f255 100644
*** a/src/backend/utils/error/elog.c
--- b/src/backend/utils/error/elog.c
***************
*** 68,73 ****
--- 68,74 ----
  #include "storage/ipc.h"
  #include "storage/proc.h"
  #include "tcop/tcopprot.h"
+ #include "utils/guc.h"
  #include "utils/memutils.h"
  #include "utils/ps_status.h"
  
*************** log_line_prefix(StringInfo buf, ErrorDat
*** 1798,1803 ****
--- 1799,1814 ----
  		/* process the option */
  		switch (Log_line_prefix[i])
  		{
+ 			case 'a':
+ 				if (application_name)
+ 				{
+ 					const char *appname = application_name;
+ 					
+ 					if (appname == NULL || *appname == '\0')
+ 						appname = _("[unknown]");
+ 					appendStringInfo(buf, "%s", appname);
+ 				}
+ 				break;
  			case 'u':
  				if (MyProcPort)
  				{
*************** write_csvlog(ErrorData *edata)
*** 2101,2108 ****
--- 2112,2124 ----
  			appendStringInfo(&msgbuf, "%s:%d",
  							 edata->filename, edata->lineno);
  		appendCSVLiteral(&buf, msgbuf.data);
+ 		appendStringInfoCharMacro(&buf, ',');
  		pfree(msgbuf.data);
  	}
+ 	
+ 	/* application name */
+ 	if (application_name)
+ 		appendCSVLiteral(&buf, application_name);
  
  	appendStringInfoChar(&buf, '\n');
  
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index a0a6605..0dd005c 100644
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
*************** static bool assign_maxconnections(int ne
*** 168,173 ****
--- 168,174 ----
  static bool assign_autovacuum_max_workers(int newval, bool doit, GucSource source);
  static bool assign_effective_io_concurrency(int newval, bool doit, GucSource source);
  static const char *assign_pgstat_temp_directory(const char *newval, bool doit, GucSource source);
+ static const char *assign_application_name(const char *newval, bool doit, GucSource source);
  
  static char *config_enum_get_options(struct config_enum * record,
  						const char *prefix, const char *suffix,
*************** char	   *pgstat_temp_directory;
*** 378,383 ****
--- 379,386 ----
  
  char	   *default_do_language;
  
+ char       *application_name;
+ 
  int			tcp_keepalives_idle;
  int			tcp_keepalives_interval;
  int			tcp_keepalives_count;
*************** static struct config_string ConfigureNam
*** 2534,2539 ****
--- 2537,2551 ----
  		"plpgsql", NULL, NULL
  	},
  
+         {
+                 {"application_name", PGC_USERSET, LOGGING,
+                         gettext_noop("Sets the application name to be reported in statistics and logs."),
+                         NULL
+                 },
+                 &application_name,
+                 "", assign_application_name, NULL
+         },
+ 
  	/* End-of-list marker */
  	{
  		{NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL
*************** InitializeGUCOptions(void)
*** 3283,3289 ****
  	env = getenv("PGCLIENTENCODING");
  	if (env != NULL)
  		SetConfigOption("client_encoding", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
! 
  	/*
  	 * rlimit isn't exactly an "environment variable", but it behaves about
  	 * the same.  If we can identify the platform stack depth rlimit, increase
--- 3295,3301 ----
  	env = getenv("PGCLIENTENCODING");
  	if (env != NULL)
  		SetConfigOption("client_encoding", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
! 	
  	/*
  	 * rlimit isn't exactly an "environment variable", but it behaves about
  	 * the same.  If we can identify the platform stack depth rlimit, increase
*************** assign_pgstat_temp_directory(const char 
*** 7717,7720 ****
--- 7729,7753 ----
  		return newval;
  }
  
+ static const char *
+ assign_application_name(const char *newval, bool doit, GucSource source)
+ {
+ 	/* Only allow clean ASCII chars in the application name */
+ 	int x;
+ 
+ 	char *repval = guc_malloc(ERROR, strlen(newval) + 1);
+ 	repval[0] = 0;
+ 
+ 	for (x=0; x<strlen(newval); x++)
+ 	{
+ 		if (newval[x] < 32 || newval[x] > 126)
+ 			repval[x] = '?';
+ 		else
+ 			repval[x] = newval[x];
+ 	}
+ 
+ 	repval[x+1] = 0;
+ 	return repval;
+ }
+ 
  #include "guc-file.c"
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 4c5f159..76f2c4e 100644
*** a/src/backend/utils/misc/postgresql.conf.sample
--- b/src/backend/utils/misc/postgresql.conf.sample
***************
*** 334,339 ****
--- 334,340 ----
  #log_duration = off
  #log_hostname = off
  #log_line_prefix = ''			# special values:
+ 					#   %a = application name 
  					#   %u = user name
  					#   %d = database name
  					#   %r = remote host and port
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 90111e9..9d5da3d 100644
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DATA(insert OID = 2784 (  pg_stat_get_la
*** 2999,3005 ****
  DESCR("statistics: last auto analyze time for a table");
  DATA(insert OID = 1936 (  pg_stat_get_backend_idset		PGNSP PGUID 12 1 100 0 f f f t t s 0 0 23 "" _null_ _null_ _null_ _null_ pg_stat_get_backend_idset _null_ _null_ _null_ ));
  DESCR("statistics: currently active backend IDs");
! DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 f f f f t s 1 0 2249 "23" "{23,26,23,26,25,16,1184,1184,1184,869,23}" "{i,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,procpid,usesysid,current_query,waiting,xact_start,query_start,backend_start,client_addr,client_port}" _null_ pg_stat_get_activity _null_ _null_ _null_ ));
  DESCR("statistics: information about currently active backends");
  DATA(insert OID = 2026 (  pg_backend_pid				PGNSP PGUID 12 1 0 0 f f f t f s 0 0 23 "" _null_ _null_ _null_ _null_ pg_backend_pid _null_ _null_ _null_ ));
  DESCR("statistics: current backend PID");
--- 2999,3005 ----
  DESCR("statistics: last auto analyze time for a table");
  DATA(insert OID = 1936 (  pg_stat_get_backend_idset		PGNSP PGUID 12 1 100 0 f f f t t s 0 0 23 "" _null_ _null_ _null_ _null_ pg_stat_get_backend_idset _null_ _null_ _null_ ));
  DESCR("statistics: currently active backend IDs");
! DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 f f f f t s 1 0 2249 "23" "{23,26,23,26,25,16,1184,1184,1184,869,23,25}" "{i,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,procpid,usesysid,current_query,waiting,xact_start,query_start,backend_start,client_addr,client_port,application_name}" _null_ pg_stat_get_activity _null_ _null_ _null_ ));
  DESCR("statistics: information about currently active backends");
  DATA(insert OID = 2026 (  pg_backend_pid				PGNSP PGUID 12 1 0 0 f f f t f s 0 0 23 "" _null_ _null_ _null_ _null_ pg_backend_pid _null_ _null_ _null_ ));
  DESCR("statistics: current backend PID");
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 91ad364..455517b 100644
*** a/src/include/pgstat.h
--- b/src/include/pgstat.h
*************** typedef struct PgBackendStatus
*** 564,571 ****
--- 564,575 ----
  	/* Is backend currently waiting on an lmgr lock? */
  	bool		st_waiting;
  
+ 	/* application name */
+ 	char       *st_appname;
+ 	
  	/* current command string; MUST be null-terminated */
  	char	   *st_activity;
+ 	
  } PgBackendStatus;
  
  /*
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 66617f3..eb64cb5 100644
*** a/src/include/utils/guc.h
--- b/src/include/utils/guc.h
*************** extern char *HbaFileName;
*** 181,186 ****
--- 181,188 ----
  extern char *IdentFileName;
  extern char *external_pid_file;
  
+ extern char *application_name;
+ 
  extern char *default_do_language;
  
  extern int	tcp_keepalives_idle;
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 011ebab..3f12dfe 100644
*** a/src/interfaces/libpq/fe-connect.c
--- b/src/interfaces/libpq/fe-connect.c
*************** static const PQconninfoOption PQconninfo
*** 163,168 ****
--- 163,174 ----
  
  	{"options", "PGOPTIONS", DefaultOption, NULL,
  	"Backend-Debug-Options", "D", 40},
+ 	
+ 	{"application_name", "PGAPPNAME", NULL, NULL,
+ 	"Application-Name", "", 40},
+ 	
+ 	{"fallback_application_name", NULL, NULL, NULL,
+ 	"Fallback-Application-Name", "", 40},
  
  #ifdef USE_SSL
  
*************** connectOptions1(PGconn *conn, const char
*** 416,421 ****
--- 422,431 ----
  	conn->pgtty = tmp ? strdup(tmp) : NULL;
  	tmp = conninfo_getval(connOptions, "options");
  	conn->pgoptions = tmp ? strdup(tmp) : NULL;
+ 	tmp = conninfo_getval(connOptions, "application_name");
+ 	conn->appname = tmp ? strdup(tmp) : NULL;
+ 	tmp = conninfo_getval(connOptions, "fallback_application_name");
+ 	conn->fbappname = tmp ? strdup(tmp) : NULL;
  	tmp = conninfo_getval(connOptions, "dbname");
  	conn->dbName = tmp ? strdup(tmp) : NULL;
  	tmp = conninfo_getval(connOptions, "user");
*************** PQconnectPoll(PGconn *conn)
*** 1064,1070 ****
  		case CONNECTION_MADE:
  			break;
  
! 			/* We allow pqSetenvPoll to decide whether to proceed. */
  		case CONNECTION_SETENV:
  			break;
  
--- 1074,1080 ----
  		case CONNECTION_MADE:
  			break;
  
! 			/* We allow pqSetenvPoll/pqAppnamePoll to decide whether to proceed. */
  		case CONNECTION_SETENV:
  			break;
  
*************** keep_going:						/* We will come back to
*** 1888,1894 ****
  				conn->addrlist = NULL;
  				conn->addr_cur = NULL;
  
! 				/* Fire up post-connection housekeeping if needed */
  				if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
  				{
  					conn->status = CONNECTION_SETENV;
--- 1898,1910 ----
  				conn->addrlist = NULL;
  				conn->addr_cur = NULL;
  
! 				/*
! 				 * Note: To avoid changing the application visible connection states
! 				 *       the v2 enviroment setup and the v3 application name setup
! 				 *       both happen in the CONNECTION_SETENV state.
! 				 */
! 				
! 				/* Fire up post-connection housekeeping or appname setup if needed */
  				if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
  				{
  					conn->status = CONNECTION_SETENV;
*************** keep_going:						/* We will come back to
*** 1896,1901 ****
--- 1912,1923 ----
  					conn->next_eo = EnvironmentOptions;
  					return PGRES_POLLING_WRITING;
  				}
+ 				else if (conn->sversion >= 80500 && (conn->appname || conn->fbappname))
+ 				{
+ 					conn->status = CONNECTION_SETENV;
+ 					conn->appname_state = APPNAME_STATE_OPTION_SEND;
+ 					return PGRES_POLLING_WRITING;
+ 				}
  
  				/* Otherwise, we are open for business! */
  				conn->status = CONNECTION_OK;
*************** keep_going:						/* We will come back to
*** 1903,1918 ****
  			}
  
  		case CONNECTION_SETENV:
! 
  			/*
! 			 * Do post-connection housekeeping (only needed in protocol 2.0).
  			 *
  			 * We pretend that the connection is OK for the duration of these
  			 * queries.
  			 */
  			conn->status = CONNECTION_OK;
  
! 			switch (pqSetenvPoll(conn))
  			{
  				case PGRES_POLLING_OK:	/* Success */
  					break;
--- 1925,1948 ----
  			}
  
  		case CONNECTION_SETENV:
! 		{
  			/*
! 			 * Do post-connection housekeeping (only needed in protocol 2.0)
! 			 * or setup the application name in PG8.5/v3+
  			 *
  			 * We pretend that the connection is OK for the duration of these
  			 * queries.
  			 */
+ 			PostgresPollingStatusType ret = PGRES_POLLING_OK;
+ 			
  			conn->status = CONNECTION_OK;
  
! 			if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
! 				ret = pqSetenvPoll(conn);
! 			else if (conn->sversion >= 80500 && (conn->appname || conn->fbappname))
! 				ret = pqAppnamePoll(conn);
! 					
! 			switch (ret)
  			{
  				case PGRES_POLLING_OK:	/* Success */
  					break;
*************** keep_going:						/* We will come back to
*** 1927,1938 ****
  
  				default:
  					goto error_return;
! 			}
! 
  			/* We are open for business! */
  			conn->status = CONNECTION_OK;
  			return PGRES_POLLING_OK;
! 
  		default:
  			appendPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext(
--- 1957,1969 ----
  
  				default:
  					goto error_return;
! 			}	
! 			
  			/* We are open for business! */
  			conn->status = CONNECTION_OK;
  			return PGRES_POLLING_OK;
! 		}
! 			
  		default:
  			appendPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext(
*************** makeEmptyPGconn(void)
*** 2000,2005 ****
--- 2031,2037 ----
  	conn->options_valid = false;
  	conn->nonblocking = false;
  	conn->setenv_state = SETENV_STATE_IDLE;
+ 	conn->appname_state = APPNAME_STATE_IDLE;
  	conn->client_encoding = PG_SQL_ASCII;
  	conn->std_strings = false;	/* unless server says differently */
  	conn->verbosity = PQERRORS_DEFAULT;
*************** freePGconn(PGconn *conn)
*** 2082,2087 ****
--- 2114,2123 ----
  		free(conn->connect_timeout);
  	if (conn->pgoptions)
  		free(conn->pgoptions);
+ 	if (conn->appname)
+ 		free(conn->appname);
+ 	if (conn->fbappname)
+ 		free(conn->fbappname);
  	if (conn->dbName)
  		free(conn->dbName);
  	if (conn->pguser)
*************** PQregisterThreadLock(pgthreadlock_t newh
*** 4057,4059 ****
--- 4093,4226 ----
  
  	return prev;
  }
+ 
+ /*
+  *		pqAppnamePoll
+  *
+  * Polls the process of passing the values of the application name to the backend.
+  */
+ PostgresPollingStatusType
+ pqAppnamePoll(PGconn *conn)
+ {
+ 	PGresult   *res;
+ 	
+ 	if (conn == NULL || conn->status == CONNECTION_BAD)
+ 		return PGRES_POLLING_FAILED;
+ 	
+ 	/* Check whether there are any data for us */
+ 	switch (conn->appname_state)
+ 	{
+ 			/* These is a reading state */
+ 		case APPNAME_STATE_OPTION_WAIT:
+ 		{
+ 			/* Load waiting data */
+ 			int			n = pqReadData(conn);
+ 			
+ 			if (n < 0)
+ 				goto error_return;
+ 			if (n == 0)
+ 				return PGRES_POLLING_READING;
+ 			
+ 			break;
+ 		}
+ 			
+ 			/* These is a writing state, so we just proceed. */
+ 		case APPNAME_STATE_OPTION_SEND:
+ 			break;
+ 			
+ 			/* Should we raise an error if called when not active? */
+ 		case APPNAME_STATE_IDLE:
+ 			return PGRES_POLLING_OK;
+ 			
+ 		default:
+ 			printfPQExpBuffer(&conn->errorMessage,
+ 							  libpq_gettext(
+ 											"invalid appname state %c, "
+ 											"probably indicative of memory corruption\n"
+ 											),
+ 							  conn->appname_state);
+ 			goto error_return;
+ 	}
+ 	
+ 	/* We will loop here until there is nothing left to do in this call. */
+ 	for (;;)
+ 	{
+ 		switch (conn->appname_state)
+ 		{
+ 			case APPNAME_STATE_OPTION_SEND:
+ 			{
+ 				char *val, *safeVal, *setQuery;
+ 				int len;
+ 				
+ 				/* Use the appname if present, otherwise use the fallback */
+ 				val = conn->appname ? conn->appname : conn->fbappname;
+ 				len = strlen(val);
+ 				
+ 				/* We need to sanitise the data */
+ 				safeVal = malloc((len * 2) + 1);
+ 				PQescapeStringConn(conn, safeVal, val, len, NULL);
+ 				
+ 				setQuery = malloc(strlen(safeVal) + 26);
+ 				sprintf(setQuery, "SET application_name = '%s'", safeVal);
+ 
+ 				if (!PQsendQuery(conn, setQuery))
+ 				{
+ 					if (safeVal)
+ 						free(safeVal);
+ 					if (setQuery)
+ 						free(setQuery);
+ 					goto error_return;
+ 				}
+ 				
+ 				if (safeVal)
+ 					free(safeVal);
+ 				if (setQuery)
+ 					free(setQuery);
+ 						
+ 				conn->appname_state = APPNAME_STATE_OPTION_WAIT;
+ 				
+ 				break;
+ 			}
+ 				
+ 			case APPNAME_STATE_OPTION_WAIT:
+ 			{
+ 				if (PQisBusy(conn))
+ 					return PGRES_POLLING_READING;
+ 				
+ 				res = PQgetResult(conn);
+ 				
+ 				if (res)
+ 				{
+ 					if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ 					{
+ 						PQclear(res);
+ 						goto error_return;
+ 					}
+ 					PQclear(res);
+ 					/* Keep reading until PQgetResult returns NULL */
+ 				}
+ 				else
+ 				{
+ 					/* Query finished, so we're done */
+ 					conn->appname_state = APPNAME_STATE_IDLE;
+ 					return PGRES_POLLING_OK;
+ 				}
+ 				break;
+ 			}
+ 				
+ 				
+ 			default:
+ 				printfPQExpBuffer(&conn->errorMessage,
+ 								  libpq_gettext("invalid state %c, "
+ 												"probably indicative of memory corruption\n"),
+ 								  conn->appname_state);
+ 				goto error_return;
+ 		}
+ 	}
+ 	
+ 	/* Unreachable */
+ 	
+ error_return:
+ 	conn->appname_state = APPNAME_STATE_IDLE;
+ 	return PGRES_POLLING_FAILED;
+ }
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 724e922..2aa93f9 100644
*** a/src/interfaces/libpq/libpq-int.h
--- b/src/interfaces/libpq/libpq-int.h
*************** typedef enum
*** 244,249 ****
--- 244,257 ----
  	SETENV_STATE_IDLE
  } PGSetenvStatusType;
  
+ /* PGAppnameStatusType defines the state of the PQAppname state machine */
+ typedef enum
+ {
+ 	APPNAME_STATE_OPTION_SEND,	/* About to send the appname */
+ 	APPNAME_STATE_OPTION_WAIT,	/* Waiting for above send to complete */
+ 	APPNAME_STATE_IDLE
+ } PGAppnameStatusType;
+ 
  /* Typedef for the EnvironmentOptions[] array */
  typedef struct PQEnvironmentOption
  {
*************** struct pg_conn
*** 295,300 ****
--- 303,310 ----
  								 * displayed (OBSOLETE, NOT USED) */
  	char	   *connect_timeout;	/* connection timeout (numeric string) */
  	char	   *pgoptions;		/* options to start the backend with */
+ 	char	   *appname;		/* application name */	
+ 	char	   *fbappname;		/* fallback application name */
  	char	   *dbName;			/* database name */
  	char	   *pguser;			/* Postgres username and password, if any */
  	char	   *pgpass;
*************** struct pg_conn
*** 349,354 ****
--- 359,365 ----
  	struct addrinfo *addr_cur;	/* the one currently being tried */
  	int			addrlist_family;	/* needed to know how to free addrlist */
  	PGSetenvStatusType setenv_state;	/* for 2.0 protocol only */
+ 	PGAppnameStatusType appname_state;
  	const PQEnvironmentOption *next_eo;
  
  	/* Miscellaneous stuff */
*************** extern char *const pgresStatus[];
*** 458,463 ****
--- 469,475 ----
  extern int pqPacketSend(PGconn *conn, char pack_type,
  			 const void *buf, size_t buf_len);
  extern bool pqGetHomeDirectory(char *buf, int bufsize);
+ extern PostgresPollingStatusType pqAppnamePoll(PGconn *conn);
  
  #ifdef ENABLE_THREAD_SAFETY
  extern pgthreadlock_t pg_g_threadlock;
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 9561a23..a402543 100644
*** a/src/test/regress/expected/rules.out
--- b/src/test/regress/expected/rules.out
*************** SELECT viewname, definition FROM pg_view
*** 1289,1295 ****
   pg_rules                 | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name);
   pg_settings              | SELECT a.name, a.setting, a.unit, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val, a.enumvals, a.boot_val, a.reset_val, a.sourcefile, a.sourceline FROM pg_show_all_settings() a(name, setting, unit, category, short_desc, extra_desc, context, vartype, source, min_val, max_val, enumvals, boot_val, reset_val, sourcefile, sourceline);
   pg_shadow                | SELECT pg_authid.rolname AS usename, pg_authid.oid AS usesysid, pg_authid.rolcreatedb AS usecreatedb, pg_authid.rolsuper AS usesuper, pg_authid.rolcatupdate AS usecatupd, pg_authid.rolpassword AS passwd, (pg_authid.rolvaliduntil)::abstime AS valuntil, s.setconfig AS useconfig FROM (pg_authid LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid)))) WHERE pg_authid.rolcanlogin;
!  pg_stat_activity         | SELECT s.datid, d.datname, s.procpid, s.usesysid, u.rolname AS usename, s.current_query, s.waiting, s.xact_start, s.query_start, s.backend_start, s.client_addr, s.client_port FROM pg_database d, pg_stat_get_activity(NULL::integer) s(datid, procpid, usesysid, current_query, waiting, xact_start, query_start, backend_start, client_addr, client_port), pg_authid u WHERE ((s.datid = d.oid) AND (s.usesysid = u.oid));
   pg_stat_all_indexes      | SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, pg_stat_get_tuples_returned(i.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"]));
   pg_stat_all_tables       | SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, pg_stat_get_numscans(c.oid) AS seq_scan, pg_stat_get_tuples_returned(c.oid) AS seq_tup_read, (sum(pg_stat_get_numscans(i.indexrelid)))::bigint AS idx_scan, ((sum(pg_stat_get_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_tuples_fetched(c.oid)) AS idx_tup_fetch, pg_stat_get_tuples_inserted(c.oid) AS n_tup_ins, pg_stat_get_tuples_updated(c.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(c.oid) AS n_tup_del, pg_stat_get_tuples_hot_updated(c.oid) AS n_tup_hot_upd, pg_stat_get_live_tuples(c.oid) AS n_live_tup, pg_stat_get_dead_tuples(c.oid) AS n_dead_tup, pg_stat_get_last_vacuum_time(c.oid) AS last_vacuum, pg_stat_get_last_autovacuum_time(c.oid) AS last_autovacuum, pg_stat_get_last_analyze_time(c.oid) AS last_analyze, pg_stat_get_last_autoanalyze_time(c.oid) AS last_autoanalyze FROM ((pg_class c LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"])) GROUP BY c.oid, n.nspname, c.relname;
   pg_stat_bgwriter         | SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed, pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req, pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint, pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean, pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean, pg_stat_get_buf_written_backend() AS buffers_backend, pg_stat_get_buf_alloc() AS buffers_alloc;
--- 1289,1295 ----
   pg_rules                 | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name);
   pg_settings              | SELECT a.name, a.setting, a.unit, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val, a.enumvals, a.boot_val, a.reset_val, a.sourcefile, a.sourceline FROM pg_show_all_settings() a(name, setting, unit, category, short_desc, extra_desc, context, vartype, source, min_val, max_val, enumvals, boot_val, reset_val, sourcefile, sourceline);
   pg_shadow                | SELECT pg_authid.rolname AS usename, pg_authid.oid AS usesysid, pg_authid.rolcreatedb AS usecreatedb, pg_authid.rolsuper AS usesuper, pg_authid.rolcatupdate AS usecatupd, pg_authid.rolpassword AS passwd, (pg_authid.rolvaliduntil)::abstime AS valuntil, s.setconfig AS useconfig FROM (pg_authid LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid)))) WHERE pg_authid.rolcanlogin;
!  pg_stat_activity         | SELECT s.datid, d.datname, s.procpid, s.usesysid, u.rolname AS usename, s.current_query, s.waiting, s.xact_start, s.query_start, s.backend_start, s.client_addr, s.client_port, s.application_name FROM pg_database d, pg_stat_get_activity(NULL::integer) s(datid, procpid, usesysid, current_query, waiting, xact_start, query_start, backend_start, client_addr, client_port, application_name), pg_authid u WHERE ((s.datid = d.oid) AND (s.usesysid = u.oid));
   pg_stat_all_indexes      | SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, pg_stat_get_tuples_returned(i.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"]));
   pg_stat_all_tables       | SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, pg_stat_get_numscans(c.oid) AS seq_scan, pg_stat_get_tuples_returned(c.oid) AS seq_tup_read, (sum(pg_stat_get_numscans(i.indexrelid)))::bigint AS idx_scan, ((sum(pg_stat_get_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_tuples_fetched(c.oid)) AS idx_tup_fetch, pg_stat_get_tuples_inserted(c.oid) AS n_tup_ins, pg_stat_get_tuples_updated(c.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(c.oid) AS n_tup_del, pg_stat_get_tuples_hot_updated(c.oid) AS n_tup_hot_upd, pg_stat_get_live_tuples(c.oid) AS n_live_tup, pg_stat_get_dead_tuples(c.oid) AS n_dead_tup, pg_stat_get_last_vacuum_time(c.oid) AS last_vacuum, pg_stat_get_last_autovacuum_time(c.oid) AS last_autovacuum, pg_stat_get_last_analyze_time(c.oid) AS last_analyze, pg_stat_get_last_autoanalyze_time(c.oid) AS last_autoanalyze FROM ((pg_class c LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"])) GROUP BY c.oid, n.nspname, c.relname;
   pg_stat_bgwriter         | SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed, pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req, pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint, pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean, pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean, pg_stat_get_buf_written_backend() AS buffers_backend, pg_stat_get_buf_alloc() AS buffers_alloc;
