commit 37c032f813c9e20ea64ac05f67e42461a0a3502e
Author: Dave Page <dpage@pgadmin.org>
Date:   Tue Oct 13 15:34:43 2009 +0100

    Initial cut of server aupport for 'application name'

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 9e25da1..2c3e51a 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
*** 1723,1728 ****
--- 1724,1739 ----
  		/* 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)
*** 2028,2033 ****
--- 2039,2049 ----
  		appendCSVLiteral(&buf, msgbuf.data);
  		pfree(msgbuf.data);
  	}
+ 	
+ 	/* application name */
+ 	if (application_name)
+ 		appendCSVLiteral(&buf, application_name);
+ 	appendStringInfoCharMacro(&buf, ',');
  
  	appendStringInfoChar(&buf, '\n');
  
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 1f63e06..d04e1e4 100644
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
*************** char	   *pgstat_temp_directory;
*** 387,392 ****
--- 387,394 ----
  
  char	   *default_do_language;
  
+ char       *application_name;
+ 
  int			tcp_keepalives_idle;
  int			tcp_keepalives_interval;
  int			tcp_keepalives_count;
*************** static struct config_string ConfigureNam
*** 2550,2555 ****
--- 2552,2566 ----
  		"plpgsql", NULL, NULL
  	},
  
+         {
+                 {"application_name", PGC_USERSET, LOGGING,
+                         gettext_noop("Sets the application name to be reported in statistics and logs."),
+                         NULL
+                 },
+                 &application_name,
+                 "", NULL, NULL
+         },
+ 
  	/* End-of-list marker */
  	{
  		{NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index d6cf7e2..d0024c3 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/bin/psql/startup.c b/src/bin/psql/startup.c
index 429e5d9..a4739f4 100644
*** a/src/bin/psql/startup.c
--- b/src/bin/psql/startup.c
*************** main(int argc, char *argv[])
*** 199,206 ****
  	}
  
  	PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
! 
  	SyncVariables();
  
  	if (options.action == ACT_LIST_DB)
  	{
--- 199,210 ----
  	}
  
  	PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
! 	
  	SyncVariables();
+ 	
+ 	/* Set the application name */
+ 	if (pset.sversion >= 80500)
+ 		SendQuery("SET application_name = 'psql';");
  
  	if (options.action == ACT_LIST_DB)
  	{
*************** main(int argc, char *argv[])
*** 209,215 ****
  		PQfinish(pset.db);
  		exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
  	}
! 
  	if (options.logfilename)
  	{
  		pset.logfile = fopen(options.logfilename, "a");
--- 213,219 ----
  		PQfinish(pset.db);
  		exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
  	}
! 	
  	if (options.logfilename)
  	{
  		pset.logfile = fopen(options.logfilename, "a");
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 289c6c0..1d06a3b 100644
*** a/src/include/utils/guc.h
--- b/src/include/utils/guc.h
*************** extern char *HbaFileName;
*** 179,184 ****
--- 179,186 ----
  extern char *IdentFileName;
  extern char *external_pid_file;
  
+ extern char *application_name;
+ 
  extern char *default_do_language;
  
  extern int	tcp_keepalives_idle;