psql: \d+ show tablespace of indices

Started by Qingqing Zhouover 20 years ago13 messages
#1Qingqing Zhou
zhouqq@cs.toronto.edu

Now \d+ is able to show the tablespace details of indices. A sample output
is followed:

test=# \d+ m
Table "public.m"
Column | Type | Modifiers | Description
--------+---------+-----------+-------------
i | integer | |
j | integer | |
Indexes:
"mi" btree (i) - Tablespace: "testspace"
"mj" btree (j)
Has OIDs: no

Index: describe.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/describe.c,v
retrieving revision 1.115
diff -c -r1.115 describe.c
*** describe.c 6 Apr 2005 05:23:32 -0000 1.115
--- describe.c 23 May 2005 10:41:48 -0000
***************
*** 37,43 ****
         const char *schemavar, const char *namevar,
         const char *altnamevar, const char *visibilityrule);

! static void add_tablespace_footer(char relkind, Oid tablespace,
char **footers, int *count, PQExpBufferData buf);

  /*----------------
--- 37,43 ----
         const char *schemavar, const char *namevar,
         const char *altnamevar, const char *visibilityrule);

! static bool add_tablespace_footer(char relkind, Oid tablespace,
char **footers, int *count, PQExpBufferData buf);

  /*----------------
***************
*** 1022,1028 ****
    {
     printfPQExpBuffer(&buf,
           "SELECT c2.relname, i.indisprimary, i.indisunique,
i.indisclustered, "
!      "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true)\n"
           "FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,
pg_catalog.pg_index i\n"
           "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid =
c2.oid\n"
           "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname",
--- 1022,1028 ----
    {
     printfPQExpBuffer(&buf,
           "SELECT c2.relname, i.indisprimary, i.indisunique,
i.indisclustered, "
!      "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),
c2.reltablespace\n"
           "FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.p
g_index i\n"
           "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid =
c2.oid\n"
           "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname",
***************
*** 1165,1170 ****
--- 1165,1190 ----
      if (strcmp(PQgetvalue(result1, i, 3), "t") == 0)
       appendPQExpBuffer(&buf, " CLUSTER");
+     /* Print tablespace of the index on the same line */
+     if (verbose)
+     {
+      PQExpBufferData tmpbuf;
+
+      count_footers += 1;
+      initPQExpBuffer(&tmpbuf);
+      if (add_tablespace_footer('i', atoi(PQgetvalue(result1, i, 5)),
+           footers, &count_footers, tmpbuf))
+      {
+       appendPQExpBuffer(&buf, " - ");
+       appendPQExpBuffer(&buf, tmpbuf.data);
+
+       count_footers -= 2;
+      }
+      else
+       count_footers -= 1;
+      termPQExpBuffer(&tmpbuf);
+     }
+
      footers[count_footers++] = pg_strdup(buf.data);
     }
    }
***************
*** 1316,1323 ****
   return retval;
  }
!
! static void
  add_tablespace_footer(char relkind, Oid tablespace, char **footers,
         int *count, PQExpBufferData buf)
  {
--- 1336,1343 ----
   return retval;
  }
! /* Return true if the relation uses non default tablespace; otherwise
return false */
! static bool
  add_tablespace_footer(char relkind, Oid tablespace, char **footers,
         int *count, PQExpBufferData buf)
  {
***************
*** 1336,1342 ****
           "WHERE oid = '%u';", tablespace);
     result1 = PSQLexec(buf.data, false);
     if (!result1)
!     return;
     /* Should always be the case, but.... */
     if (PQntuples(result1) > 0)
     {
--- 1356,1362 ----
           "WHERE oid = '%u';", tablespace);
     result1 = PSQLexec(buf.data, false);
     if (!result1)
!     return false;
     /* Should always be the case, but.... */
     if (PQntuples(result1) > 0)
     {
***************
*** 1345,1352 ****
--- 1365,1376 ----
      footers[(*count)++] = pg_strdup(buf.data);
     }
     PQclear(result1);
+
+    return true;
    }
   }
+
+  return false;
  }

/*

#2Neil Conway
neilc@samurai.com
In reply to: Qingqing Zhou (#1)
Re: psql: \d+ show tablespace of indices

On Mon, 2005-05-23 at 18:52 +0800, Qingqing Zhou wrote:

Now \d+ is able to show the tablespace details of indices.

Should this be included in \d? Tablespace information for the table
itself is, so I think we should probably do the same for indexes.

Also, can you resend the patch as an attachment? Perhaps the ML software
munged your email or my MUA is just broken, but the patch you sent seems
to be corrupted.

-Neil

#3Tom Lane
tgl@sss.pgh.pa.us
In reply to: Neil Conway (#2)
Re: psql: \d+ show tablespace of indices

Neil Conway <neilc@samurai.com> writes:

On Mon, 2005-05-23 at 18:52 +0800, Qingqing Zhou wrote:

Now \d+ is able to show the tablespace details of indices.

Should this be included in \d? Tablespace information for the table
itself is, so I think we should probably do the same for indexes.

Seems reasonable. In the minor-carping department, I didn't much like
the formatting:

Indexes:
"mi" btree (i) - Tablespace: "testspace"
"mj" btree (j)

That looks a bit ugly to me ... not sure why, exactly, but maybe it's
that there's too much punctuation. The underlying CREATE INDEX command
would just look like

"mi" btree (i) tablespace "testspace"

Does that look better or worse to you?

regards, tom lane

#4Christopher Kings-Lynne
chriskl@familyhealth.com.au
In reply to: Tom Lane (#3)
Tablespaces

I'm interested if anyone is using tablespaces? Do we have any actual
reports of people actually using them, to advantage, in the field??

Maybe the next postgresql.org survey could be on tablespace usage?

Chris

#5Neil Conway
neilc@samurai.com
In reply to: Tom Lane (#3)
Re: psql: \d+ show tablespace of indices

On Thu, 2005-06-02 at 22:15 -0400, Tom Lane wrote:

Does that look better or worse to you?

I agree the patch's format is a bit off. What about

"mi" btree (i), tablespace "testspace"

"PRIMARY KEY" is currently separated from the rest of the index
description via a comma -- although on the other hand the column list
isn't preceded by a comma. Perhaps this whole format should be
rethought?

-Neil

#6Hans-Jürgen Schönig
postgres@cybertec.at
In reply to: Christopher Kings-Lynne (#4)
Re: Tablespaces

Christopher Kings-Lynne wrote:

I'm interested if anyone is using tablespaces? Do we have any actual
reports of people actually using them, to advantage, in the field??

Maybe the next postgresql.org survey could be on tablespace usage?

Chris

I have seen that tablespaces are widely used and highly appreciated.
I have not seen people complaining about the current implementation.

best regards,

hans

--
Cybertec Geschwinde u Schoenig
Schoengrabern 134, A-2020 Hollabrunn, Austria
Tel: +43/664/393 39 74
www.cybertec.at, www.postgresql.at

#7Simon Riggs
simon@2ndquadrant.com
In reply to: Hans-Jürgen Schönig (#6)
Re: Tablespaces

On Fri, 2005-06-03 at 08:41 +0200, Hans-Jürgen Schönig wrote:

Christopher Kings-Lynne wrote:

I'm interested if anyone is using tablespaces? Do we have any actual
reports of people actually using them, to advantage, in the field??

Maybe the next postgresql.org survey could be on tablespace usage?

I have seen that tablespaces are widely used and highly appreciated.
I have not seen people complaining about the current implementation.

My recent experience is that it is mostly the new Windows users who are
using 8.0. Yes, there are people using Tablespaces on those. The only
complaint is why can't you move pg_xlog easily also?

The migration to 8.0 for a many users appears very slow, with many
PostgreSQL users still planning to enter production on 7.3 and 7.4. This
has much to do with supported versions of integrated products, rather
than any lack of interest in 8.0.

Best Regards, Simon Riggs

#8Simon Riggs
simon@2ndquadrant.com
In reply to: Christopher Kings-Lynne (#4)
Re: Tablespaces

On Fri, 2005-06-03 at 11:17 +0800, Christopher Kings-Lynne wrote:

Maybe the next postgresql.org survey could be on tablespace usage?

Could we plan a more comprehensive survey, with more than one question?

Judging by the number of people who fill out surveys, we would still get
thousands of replies if we asked them 10 questions instead of 1. That
would allow us to cross-correlate the answers to gain an even better
picture of what is happening and what is wanted.

Best Regards, Simon Riggs

#9Qingqing Zhou
zhouqq@cs.toronto.edu
In reply to: Qingqing Zhou (#1)
Re: psql: \d+ show tablespace of indices

"Neil Conway" <neilc@samurai.com> writes

On Thu, 2005-06-02 at 22:15 -0400, Tom Lane wrote:

Does that look better or worse to you?

I agree the patch's format is a bit off. What about

"mi" btree (i), tablespace "testspace"

"PRIMARY KEY" is currently separated from the rest of the index
description via a comma -- although on the other hand the column list
isn't preceded by a comma. Perhaps this whole format should be
rethought?

yes, you are right, both forms you showed up are better than mine - the
reason I use that format is because add_tablespace_footer() prints a
"Tablespace: \"tablespace_name\"" in the PQExpBufferData. I could hack the
content in the buffer to make it looks better. Is this acceptable?

Regards,
Qingqing

#10Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Qingqing Zhou (#9)
Re: psql: \d+ show tablespace of indices

Qingqing Zhou wrote:

"Neil Conway" <neilc@samurai.com> writes

On Thu, 2005-06-02 at 22:15 -0400, Tom Lane wrote:

Does that look better or worse to you?

I agree the patch's format is a bit off. What about

"mi" btree (i), tablespace "testspace"

"PRIMARY KEY" is currently separated from the rest of the index
description via a comma -- although on the other hand the column list
isn't preceded by a comma. Perhaps this whole format should be
rethought?

yes, you are right, both forms you showed up are better than mine - the
reason I use that format is because add_tablespace_footer() prints a
"Tablespace: \"tablespace_name\"" in the PQExpBufferData. I could hack the
content in the buffer to make it looks better. Is this acceptable?

Yes, I am thinking you should replace the string "Tablespace:" with a
char pointer that is passed to the function and can be tailored to the
specific use.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
#11Qingqing Zhou
zhouqq@cs.toronto.edu
In reply to: Bruce Momjian (#10)
1 attachment(s)
Re: psql: \d+ show tablespace of indices

Now \d show tablespace of indices per discussion.

test=# \d e
Table "public.e"
Column | Type | Modifiers
--------+---------+-----------
i | integer | not null
j | integer | not null
k | integer |
Indexes:
"e_pkey" PRIMARY KEY, btree (i, j), tablespace "haha"
"ei" btree (i)
"ej" btree (j), tablespace "haha"
"ek" btree (k)
Tablespace: "haha"

Attachments:

describe.difftext/plain; charset=US-ASCII; name=describe.diffDownload
Index: describe.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/describe.c,v
retrieving revision 1.115
diff -c -r1.115 describe.c
*** describe.c	6 Apr 2005 05:23:32 -0000	1.115
--- describe.c	4 Jun 2005 06:37:36 -0000
***************
*** 37,44 ****
  				   const char *schemavar, const char *namevar,
  				   const char *altnamevar, const char *visibilityrule);
  
! static void add_tablespace_footer(char relkind, Oid tablespace,
! 					  char **footers, int *count, PQExpBufferData buf);
  
  /*----------------
   * Handlers for various slash commands displaying some sort of list
--- 37,44 ----
  				   const char *schemavar, const char *namevar,
  				   const char *altnamevar, const char *visibilityrule);
  
! static bool add_tablespace_footer(char relkind, Oid tablespace, char **footers, 
! 										int *count, PQExpBufferData buf, bool newline);
  
  /*----------------
   * Handlers for various slash commands displaying some sort of list
***************
*** 942,948 ****
  			footers = pg_malloc_zero(4 * sizeof(*footers));
  			footers[count_footers++] = pg_strdup(tmpbuf.data);
  			add_tablespace_footer(tableinfo.relkind, tableinfo.tablespace,
! 								  footers, &count_footers, tmpbuf);
  			footers[count_footers] = NULL;
  
  		}
--- 942,948 ----
  			footers = pg_malloc_zero(4 * sizeof(*footers));
  			footers[count_footers++] = pg_strdup(tmpbuf.data);
  			add_tablespace_footer(tableinfo.relkind, tableinfo.tablespace,
! 								  footers, &count_footers, tmpbuf, true);
  			footers[count_footers] = NULL;
  
  		}
***************
*** 1022,1028 ****
  		{
  			printfPQExpBuffer(&buf,
  							  "SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, "
! 					"pg_catalog.pg_get_indexdef(i.indexrelid, 0, true)\n"
  							  "FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n"
  							  "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
  							  "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname",
--- 1022,1028 ----
  		{
  			printfPQExpBuffer(&buf,
  							  "SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, "
! 					"pg_catalog.pg_get_indexdef(i.indexrelid, 0, true), c2.reltablespace\n"
  							  "FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n"
  							  "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
  							  "ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname",
***************
*** 1142,1147 ****
--- 1142,1148 ----
  			{
  				const char *indexdef;
  				const char *usingpos;
+ 				PQExpBufferData	tmpbuf;
  
  				/* Output index name */
  				printfPQExpBuffer(&buf, _("    \"%s\""),
***************
*** 1165,1170 ****
--- 1166,1187 ----
  				if (strcmp(PQgetvalue(result1, i, 3), "t") == 0)
  					appendPQExpBuffer(&buf, " CLUSTER");
  
+ 				/* Print tablespace of the index on the same line */
+ 				count_footers += 1;
+ 				initPQExpBuffer(&tmpbuf);
+ 				if (add_tablespace_footer('i', 
+ 									atooid(PQgetvalue(result1, i, 5)),
+ 									footers, &count_footers, tmpbuf, false))
+ 				{
+ 					appendPQExpBuffer(&buf, ", ");
+ 					appendPQExpBuffer(&buf, tmpbuf.data);
+ 					
+ 					count_footers -= 2;
+ 				}
+ 				else
+ 					count_footers -= 1;
+ 				termPQExpBuffer(&tmpbuf);
+ 				
  				footers[count_footers++] = pg_strdup(buf.data);
  			}
  		}
***************
*** 1265,1271 ****
  		}
  
  		add_tablespace_footer(tableinfo.relkind, tableinfo.tablespace,
! 							  footers, &count_footers, buf);
  		/* end of list marker */
  		footers[count_footers] = NULL;
  
--- 1282,1288 ----
  		}
  
  		add_tablespace_footer(tableinfo.relkind, tableinfo.tablespace,
! 							  footers, &count_footers, buf, true);
  		/* end of list marker */
  		footers[count_footers] = NULL;
  
***************
*** 1317,1325 ****
  }
  
  
! static void
  add_tablespace_footer(char relkind, Oid tablespace, char **footers,
! 					  int *count, PQExpBufferData buf)
  {
  	/* relkinds for which we support tablespaces */
  	if (relkind == 'r' || relkind == 'i')
--- 1334,1346 ----
  }
  
  
! /* 
!  * Return true if the relation uses non default tablespace; 
!  * otherwise return false 
!  */
! static bool
  add_tablespace_footer(char relkind, Oid tablespace, char **footers,
! 					  int *count, PQExpBufferData buf, bool newline)
  {
  	/* relkinds for which we support tablespaces */
  	if (relkind == 'r' || relkind == 'i')
***************
*** 1336,1352 ****
  							  "WHERE oid = '%u';", tablespace);
  			result1 = PSQLexec(buf.data, false);
  			if (!result1)
! 				return;
  			/* Should always be the case, but.... */
  			if (PQntuples(result1) > 0)
  			{
! 				printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
! 								  PQgetvalue(result1, 0, 0));
  				footers[(*count)++] = pg_strdup(buf.data);
  			}
  			PQclear(result1);
  		}
  	}
  }
  
  /*
--- 1357,1379 ----
  							  "WHERE oid = '%u';", tablespace);
  			result1 = PSQLexec(buf.data, false);
  			if (!result1)
! 				return false;
  			/* Should always be the case, but.... */
  			if (PQntuples(result1) > 0)
  			{
! 				printfPQExpBuffer(&buf, 
! 					newline?_("Tablespace: \"%s\""):_("tablespace \"%s\""),
! 					PQgetvalue(result1, 0, 0));
! 					
  				footers[(*count)++] = pg_strdup(buf.data);
  			}
  			PQclear(result1);
+ 			
+ 			return true;
  		}
  	}
+ 	
+ 	return false;
  }
  
  /*
#12Qingqing Zhou
zhouqq@cs.toronto.edu
In reply to: Neil Conway (#2)
4 attachment(s)
Re: Simplify Win32 Signaling code

Revised patch to avoid "lost signals before signaling mechanism is set up
in Win32". This was tested by plus a line:

Sleep(10*1000);

in the front of pgwin32_signal_initialize().

Regards,
Qingqing

Attachments:

kill.difftext/plain; charset=US-ASCII; name=kill.diffDownload
Index: src/port/kill.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/port/kill.c,v
retrieving revision 1.6
diff -c -r1.6 kill.c
*** src/port/kill.c	31 Dec 2004 22:03:53 -0000	1.6
--- src/port/kill.c	4 Jun 2005 12:16:07 -0000
***************
*** 17,61 ****
  #include "c.h"
  
  #ifdef WIN32
! /* signal sending */
  int
  pgkill(int pid, int sig)
  {
! 	char		pipename[128];
! 	BYTE		sigData = sig;
! 	BYTE		sigRet = 0;
! 	DWORD		bytes;
  
! 	/* we allow signal 0 here, but it will be ignored in pg_queue_signal */
  	if (sig >= PG_SIGNAL_COUNT || sig < 0)
! 	{
! 		errno = EINVAL;
! 		return -1;
! 	}
  	if (pid <= 0)
! 	{
! 		/* No support for process groups */
! 		errno = EINVAL;
! 		return -1;
! 	}
! 	wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%i", pid);
! 	if (!CallNamedPipe(pipename, &sigData, 1, &sigRet, 1, &bytes, 1000))
! 	{
! 		if (GetLastError() == ERROR_FILE_NOT_FOUND)
! 			errno = ESRCH;
! 		else if (GetLastError() == ERROR_ACCESS_DENIED)
! 			errno = EPERM;
! 		else
! 			errno = EINVAL;
! 		return -1;
! 	}
! 	if (bytes != 1 || sigRet != sig)
! 	{
! 		errno = ESRCH;
! 		return -1;
! 	}
  
! 	return 0;
  }
  
  #endif
--- 17,120 ----
  #include "c.h"
  
  #ifdef WIN32
! 
! /* Convenience macro to set errno and return */
! #define set_error_and_return(e)	\
! do{	\
! 	if (shmem)	UnmapViewOfFile(shmem);	\
! 	if (hShmem)	CloseHandle(hShmem);	\
! 	if (hEvent)	CloseHandle(hEvent);	\
! 	if (hMutex)	CloseHandle(hMutex);	\
! 	\
! 	errno = (e); \
! 	return ((e) == 0)? 0 : -1;	\
! } while (0)
! 
! /* 
!  * pgkill
!  *		kill() win32 emulation. 
!  *
!  *		pgkill() will fail if: 
!  *		[EINVAL] The value of the sig argument is an invalid 
!  *				 or target process id <= 0.
!  *		[ESRCH]  No process can be found corresponding to that 
!  *				 specified by pid.  
!  *		[EPERM]  Any other win32 system call fails.
!  */
  int
  pgkill(int pid, int sig)
  {
! 	char	name[64];
! 	HANDLE	hShmem, hMutex, hEvent;
! 	Win32SignalShmemStruct *shmem;
! 
! 	shmem  = NULL;
! 	hShmem = NULL;
! 	hMutex = NULL;
! 	hEvent = NULL;
  
! 	/* we allow signal 0 here, and handle later */
  	if (sig >= PG_SIGNAL_COUNT || sig < 0)
! 		set_error_and_return(EINVAL);
! 	
! 	/* No support for process groups */
  	if (pid <= 0)
! 		set_error_and_return(EINVAL);
! 	
! 	/* 
! 	 * Attach to the signaling shared memory. If it is attachable,
! 	 * we decide that the process is alive. 
! 	 */
! 	wsprintf(name, "%s.%d", SIGNAL_SHMEM_PREFIX, pid);
! 	if (NULL == (hShmem = OpenFileMapping(FILE_MAP_ALL_ACCESS, 
! 								FALSE, 
! 								name)))
! 		set_error_and_return(ESRCH);
! 	
! 	if (sig == 0)
! 		set_error_and_return(0);
! 
! 	if (NULL == (shmem = MapViewOfFile(hShmem, 	   
! 			    				FILE_MAP_ALL_ACCESS,   
! 	    						0, 0, 0)))        
! 		set_error_and_return(EPERM);
! 
! 	/* Grab the mutex */
! 	wsprintf(name, "%s.%d", SIGNAL_MUTEX_PREFIX, pid);
! 	if (NULL == (hMutex = OpenMutex(MUTEX_ALL_ACCESS, 
! 								FALSE, name)))
! 		set_error_and_return(EPERM);
! 
! 	if (WaitForSingleObject(hMutex, INFINITE) != WAIT_OBJECT_0)	
! 		set_error_and_return(EPERM);
! 
! 	/* Write down the signal number */
! 	shmem->queue |= sigmask(sig);
! 	
! 	/* 
! 	 * If we can't release the mutex, we have to exit the
! 	 * process to make mutex released by the system. If we 
! 	 * can't set the event, that's really awkward, but the 
! 	 * target process would find out the signal when next
! 	 * set event is successfully done. 
! 	 */
! 	if (!ReleaseMutex(hMutex))
! 		set_error_and_return(EPERM);
! 
! 	if (!UnmapViewOfFile(shmem))
! 		set_error_and_return(EPERM);
! 
! 	/* Set event */
! 	wsprintf(name, "%s.%d", SIGNAL_EVENT_PREFIX, pid);
! 	if (NULL == (hEvent = OpenEvent(EVENT_ALL_ACCESS, 
! 								FALSE, name)))
! 		set_error_and_return(EPERM);
! 
! 	if (!SetEvent(hEvent))
! 		set_error_and_return(EPERM);
  
! 	/* Successfully done */
! 	set_error_and_return(0);
  }
  
  #endif
postmaster.difftext/plain; charset=US-ASCII; name=postmaster.diffDownload
Index: src/backend/postmaster/postmaster.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/postmaster/postmaster.c,v
retrieving revision 1.451
diff -c -r1.451 postmaster.c
*** src/backend/postmaster/postmaster.c	15 May 2005 00:26:18 -0000	1.451
--- src/backend/postmaster/postmaster.c	4 Jun 2005 12:29:17 -0000
***************
*** 332,338 ****
  	pid_t PostmasterPid;
  #ifdef WIN32
  	HANDLE PostmasterHandle;
! 	HANDLE initial_signal_pipe;
  	HANDLE syslogPipe[2];
  #else
  	int syslogPipe[2];
--- 332,338 ----
  	pid_t PostmasterPid;
  #ifdef WIN32
  	HANDLE PostmasterHandle;
! 	HANDLE initial_signal_handles[N_SIGNALING_HANDLES];
  	HANDLE syslogPipe[2];
  #else
  	int syslogPipe[2];
***************
*** 3561,3567 ****
  #define write_inheritable_socket(dest, src, childpid) (*(dest) = (src))
  #define read_inheritable_socket(dest, src) (*(dest) = *(src))
  #else
! static void write_duplicated_handle(HANDLE *dest, HANDLE src, HANDLE child);
  static void write_inheritable_socket(InheritableSocket *dest, SOCKET src,
  									 pid_t childPid);
  static void read_inheritable_socket(SOCKET *dest, InheritableSocket *src);
--- 3561,3567 ----
  #define write_inheritable_socket(dest, src, childpid) (*(dest) = (src))
  #define read_inheritable_socket(dest, src) (*(dest) = *(src))
  #else
! static void write_duplicated_handles(int num, HANDLE *dest, HANDLE *src, HANDLE child);
  static void write_inheritable_socket(InheritableSocket *dest, SOCKET src,
  									 pid_t childPid);
  static void read_inheritable_socket(SOCKET *dest, InheritableSocket *src);
***************
*** 3606,3613 ****
  
  #ifdef WIN32
  	param->PostmasterHandle = PostmasterHandle;
! 	write_duplicated_handle(&param->initial_signal_pipe,
! 							pgwin32_create_signal_listener(childPid),
  							childProcess);
  #endif
  
--- 3606,3617 ----
  
  #ifdef WIN32
  	param->PostmasterHandle = PostmasterHandle;
! 
! 	/* Create signaling area for my child */
! 	pgwin32_create_signaling_area(childPid);
! 	write_duplicated_handles(N_SIGNALING_HANDLES, 
! 							param->initial_signal_handles,
! 							pgwin32_initial_signal_handles, 
  							childProcess);
  #endif
  
***************
*** 3626,3651 ****
  
  #ifdef WIN32
  /*
!  * Duplicate a handle for usage in a child process, and write the child
!  * process instance of the handle to the parameter file.
   */
  static void
! write_duplicated_handle(HANDLE *dest, HANDLE src, HANDLE childProcess)
  {
! 	HANDLE hChild = INVALID_HANDLE_VALUE;
  
! 	if (!DuplicateHandle(GetCurrentProcess(),
! 						 src,
! 						 childProcess,
! 						 &hChild,
! 						 0,
! 						 TRUE,
! 						 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
! 		ereport(ERROR,
! 				(errmsg_internal("could not duplicate handle to be written to backend parameter file: error code %d",
! 								 (int) GetLastError())));
  
! 	*dest = hChild;
  }
  
  /*
--- 3630,3667 ----
  
  #ifdef WIN32
  /*
!  * Duplicate handles for usage in a child process, and write the child
!  * process instance of the handles to the parameter file.
   */
  static void
! write_duplicated_handles(int num, HANDLE *dest, HANDLE *src, HANDLE childProcess)
  {
! 	int		i, j;
! 	HANDLE 	hChild;
  
! 	for (i = 0; i < num; i++)
! 	{
! 		hChild = INVALID_HANDLE_VALUE;
! 		
! 		if (!DuplicateHandle(GetCurrentProcess(),
! 							 src[i],
! 							 childProcess,
! 							 &hChild,
! 							 0,
! 							 TRUE,
! 							 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
! 		{
! 			/* close previousely duplicated handles */
! 			for (j = 0; j < i; j++)
! 				CloseHandle(dest[j]);
! 			
! 			ereport(ERROR,
! 					(errmsg_internal("could not duplicate handle to be written to backend parameter file: error code %d",
! 									 (int) GetLastError())));
! 		}
  
! 		dest[i] = hChild;
! 	}
  }
  
  /*
***************
*** 3808,3814 ****
  
  #ifdef WIN32
  	PostmasterHandle = param->PostmasterHandle;
! 	pgwin32_initial_signal_pipe = param->initial_signal_pipe;
  #endif
  
  	memcpy(&syslogPipe, &param->syslogPipe, sizeof(syslogPipe));
--- 3824,3832 ----
  
  #ifdef WIN32
  	PostmasterHandle = param->PostmasterHandle;
! 	memcpy(pgwin32_initial_signal_handles, 
! 			param->initial_signal_handles,
! 			sizeof(HANDLE) * N_SIGNALING_HANDLES);
  #endif
  
  	memcpy(&syslogPipe, &param->syslogPipe, sizeof(syslogPipe));
signal.difftext/plain; charset=US-ASCII; name=signal.diffDownload
Index: src/backend/port/win32/signal.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/port/win32/signal.c,v
retrieving revision 1.11
diff -c -r1.11 signal.c
*** src/backend/port/win32/signal.c	31 Dec 2004 22:00:37 -0000	1.11
--- src/backend/port/win32/signal.c	4 Jun 2005 13:04:49 -0000
***************
*** 14,43 ****
  #include "postgres.h"
  
  #include <libpq/pqsignal.h>
  
  
! /* pg_signal_crit_sec is used to protect only pg_signal_queue. That is the only
!  * variable that can be accessed from the signal sending threads! */
! static CRITICAL_SECTION pg_signal_crit_sec;
! static int	pg_signal_queue;
  
  static pqsigfunc pg_signal_array[PG_SIGNAL_COUNT];
  static pqsigfunc pg_signal_defaults[PG_SIGNAL_COUNT];
  static int	pg_signal_mask;
  
- DLLIMPORT HANDLE pgwin32_signal_event;
- HANDLE pgwin32_initial_signal_pipe = INVALID_HANDLE_VALUE;
- 
- 
- /* Signal handling thread function */
- static DWORD WINAPI pg_signal_thread(LPVOID param);
  static BOOL WINAPI pg_console_handler(DWORD dwCtrlType);
  
! /* Sleep function that can be interrupted by signals */
  void
  pgwin32_backend_usleep(long microsec)
  {
! 	if (WaitForSingleObject(pgwin32_signal_event, (microsec < 500 ? 1 : (microsec + 500) / 1000)) == WAIT_OBJECT_0)
  	{
  		pgwin32_dispatch_queued_signals();
  		errno = EINTR;
--- 14,74 ----
  #include "postgres.h"
  
  #include <libpq/pqsignal.h>
+ #include "miscadmin.h"
+ #include "utils/memutils.h"
  
+ /* Simplified error report for this module */
+ #define ereport_signal(elevel, msg)	\
+ do{	\
+ 	if (ErrorContext != NULL)	\
+ 		ereport((elevel), \
+ 				(errmsg_internal("Win32 Singaling: %s: error code: %d", \
+ 						(msg), (int)GetLastError()))); \
+ 	else{	\
+ 		write_stderr("Win32 Signaling: %s\n", msg);	\
+ 		exit (-1);	\
+ 	}\
+ }while (0)
+ 
+ /* Lock/Unlock signal area primitives */
+ #define lock_signal_shmem()	\
+ do { \
+ 	if (WaitForSingleObject(MySignalShmem->mutex, INFINITE) != WAIT_OBJECT_0)	\
+ 		ereport_signal(ERROR, "failed to wait on signal mutex");	\
+ }while(0)
+ 
+ #define unlock_signal_shmem()	\
+ do{	\
+ 	if (!ReleaseMutex(MySignalShmem->mutex))	\
+ 		ereport_signal(ERROR, "failed to release signal mutex");	\
+ }while(0)
  
! /* Signaling shared memory of current process */
! DLLIMPORT Win32SignalShmemStruct *MySignalShmem;
! 
! /* Array to save handles for child process */
! HANDLE pgwin32_initial_signal_handles[N_SIGNALING_HANDLES] = 
! {
! 	/* shmem handle */	NULL,
! 	/* mutex handle */	NULL,
! 	/* event handle */	NULL
! };
  
  static pqsigfunc pg_signal_array[PG_SIGNAL_COUNT];
  static pqsigfunc pg_signal_defaults[PG_SIGNAL_COUNT];
  static int	pg_signal_mask;
  
  static BOOL WINAPI pg_console_handler(DWORD dwCtrlType);
  
! /* 
!  * pgwin32_backend_usleep
!  * 		Sleep function that can be interrupted by signals 
!  */
  void
  pgwin32_backend_usleep(long microsec)
  {
! 	if (WaitForSingleObject(pgwin32_signal_event, (microsec < 500 ? 
! 						1 : (microsec + 500) / 1000)) == WAIT_OBJECT_0)
  	{
  		pgwin32_dispatch_queued_signals();
  		errno = EINTR;
***************
*** 45,101 ****
  	}
  }
  
  
! /* Initialization */
  void
  pgwin32_signal_initialize(void)
  {
  	int			i;
- 	HANDLE		signal_thread_handle;
- 
- 	InitializeCriticalSection(&pg_signal_crit_sec);
  
  	for (i = 0; i < PG_SIGNAL_COUNT; i++)
  	{
  		pg_signal_array[i] = SIG_DFL;
  		pg_signal_defaults[i] = SIG_IGN;
  	}
  	pg_signal_mask = 0;
- 	pg_signal_queue = 0;
  
! 	/* Create the global event handle used to flag signals */
! 	pgwin32_signal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
! 	if (pgwin32_signal_event == NULL)
! 		ereport(FATAL,
! 				(errmsg_internal("failed to create signal event: %d", (int) GetLastError())));
! 
! 	/* Create thread for handling signals */
! 	signal_thread_handle = CreateThread(NULL, 0, pg_signal_thread, NULL, 0, NULL);
! 	if (signal_thread_handle == NULL)
! 		ereport(FATAL,
! 			(errmsg_internal("failed to create signal handler thread")));
  
  	/* Create console control handle to pick up Ctrl-C etc */
  	if (!SetConsoleCtrlHandler(pg_console_handler, TRUE))
! 		ereport(FATAL,
! 			 (errmsg_internal("failed to set console control handler")));
  }
  
! 
! /* Dispatch all signals currently queued and not blocked
!  * Blocked signals are ignored, and will be fired at the time of
!  * the sigsetmask() call. */
  void
  pgwin32_dispatch_queued_signals(void)
  {
  	int			i;
  
! 	EnterCriticalSection(&pg_signal_crit_sec);
! 	while (pg_signal_queue & ~pg_signal_mask)
  	{
  		/* One or more unblocked signals queued for execution */
! 
! 		int			exec_mask = pg_signal_queue & ~pg_signal_mask;
  
  		for (i = 0; i < PG_SIGNAL_COUNT; i++)
  		{
--- 76,229 ----
  	}
  }
  
+ /* 
+  * pgwin32_create_signaling_area
+  * 		Create the signal area for specified pid. If any step 
+  *		failed, the error level is set to ERROR only since 
+  *		postmaster will call it at process fork. Accordingly,
+  *		we have to cleanup opened handles to avoid leakage. 
+  */
+ #define cleanup_and_ereport(elevel, msg)	\
+ do{	\
+ 	if (shmem)	UnmapViewOfFile(shmem);	\
+ 	if (hShmem)	CloseHandle(hShmem);	\
+ 	if (hEvent)	CloseHandle(hEvent);	\
+ 	if (hMutex)	CloseHandle(hMutex);	\
+ 	\
+ 	ereport_signal((elevel), (msg));	\
+ } while (0)
+ 
+ void
+ pgwin32_create_signaling_area(pid_t pid)
+ {
+ 	char	name[64];
+ 	SECURITY_ATTRIBUTES sa;
+ 	HANDLE	hShmem, hMutex, hEvent;
+ 	Win32SignalShmemStruct *shmem;
+ 
+ 	shmem  = NULL;
+ 	hShmem = NULL;
+ 	hMutex = NULL;
+ 	hEvent = NULL;
+ 
+ 	ZeroMemory(&sa, sizeof(sa));
+ 	sa.nLength = sizeof(sa);
+ 	sa.bInheritHandle = TRUE;	
+ 
+ 	/* Create the global shared memory */ 
+ 	wsprintf(name, "%s.%d", SIGNAL_SHMEM_PREFIX, pid);
+ 	if (NULL == (hShmem = CreateFileMapping((HANDLE) 0xFFFFFFFF,
+ 								&sa, PAGE_READWRITE,
+ 								0L, sizeof(Win32SignalShmemStruct),
+ 								name)))
+ 		cleanup_and_ereport(ERROR, 
+ 					"failed to create shared memory");
+ 	
+ 	if (NULL == (shmem = MapViewOfFile(hShmem,
+ 							FILE_MAP_ALL_ACCESS,
+ 							0, 0, 0)))
+ 		cleanup_and_ereport(ERROR, 
+ 					"failed to attach to signaling area");
+ 	
+ 	MemSet(shmem, 0, sizeof(Win32SignalShmemStruct));
+ 	
+ 	/* Create the global mutex */
+ 	wsprintf(name, "%s.%d", SIGNAL_MUTEX_PREFIX, pid);
+ 	if (NULL == (hMutex = CreateMutex(&sa, FALSE, name)))
+ 		cleanup_and_ereport(ERROR, 
+ 					"failed to create signal mutex");	
+ 
+ 	/* Create the global event */
+ 	wsprintf(name, "%s.%d", SIGNAL_EVENT_PREFIX, pid);
+ 	if (NULL == (hEvent = CreateEvent(&sa, TRUE, FALSE, name)))
+ 		cleanup_and_ereport(ERROR, 
+ 					"failed to create signal event");
+ 
+ 	/* 
+ 	 * Only the postmater or standalone backend should save the
+ 	 * handles in shared memory for its own use. For others, it
+ 	 * is called by postmaster who create these handles for its 
+ 	 * children, so save them in pgwin32_initial_signal_handles[]. 
+ 	 */
+ 	if (pid == PostmasterPid || !IsPostmasterEnvironment)
+ 	{
+ 		shmem->mutex = hMutex;
+ 		shmem->event = hEvent;
+ 		MySignalShmem = shmem;
+ 	}
+ 	else
+ 	{
+ 		pgwin32_initial_signal_handles[0] = hShmem;
+ 		pgwin32_initial_signal_handles[1] = hMutex;
+ 		pgwin32_initial_signal_handles[2] = hEvent;
+ 	}
+ }
  
! /* 
!  * pgwin32_signal_initialize
!  * 		Allocate and initialize signal emulation shared memory, 
!  * 		including a mutex protecting the whole area, an event 
!  * 		notifying that a signal was sent to current process, and 
!  * 		a queue saving signals. All of them are in global namespace. 
!  */
  void
  pgwin32_signal_initialize(void)
  {
  	int			i;
  
+ 	/* Initialize the local part */
  	for (i = 0; i < PG_SIGNAL_COUNT; i++)
  	{
  		pg_signal_array[i] = SIG_DFL;
  		pg_signal_defaults[i] = SIG_IGN;
  	}
  	pg_signal_mask = 0;
  
! 	/* Initialize the shared memory part */
! 	if (pgwin32_initial_signal_handles[0] != NULL)
! 	{
! 		/* Use the postmaster created shared memory */
! 		if (NULL == (MySignalShmem = MapViewOfFile(
! 								pgwin32_initial_signal_handles[0], 
! 								FILE_MAP_ALL_ACCESS, 
! 								0, 0, 0)))
! 			ereport_signal(FATAL, 
! 						"failed to attach to signal area");
! 
! 		MySignalShmem->mutex = pgwin32_initial_signal_handles[1];
! 		MySignalShmem->event = pgwin32_initial_signal_handles[2];
! 
! 		/*
! 		 * Don't dispatch any signals for now, since the signal 
! 		 * handlers are not set up yet.
! 		 */
! 	}
! 	else
! 		/* Create the singaling area for myself */
! 		pgwin32_create_signaling_area(GetCurrentProcessId());
  
  	/* Create console control handle to pick up Ctrl-C etc */
  	if (!SetConsoleCtrlHandler(pg_console_handler, TRUE))
! 		ereport_signal(FATAL, 
! 					"failed to set console control");	
  }
  
! /* 
!  * pgwin32_dispatch_queued_signals
!  * 		Dispatch all signals currently queued and not blocked
!  * 		Blocked signals are ignored, and will be fired at the 
!  *      time of the sigsetmask() call. 
!  */
  void
  pgwin32_dispatch_queued_signals(void)
  {
  	int			i;
  
! 	lock_signal_shmem();
! 	while (MySignalShmem->queue & ~pg_signal_mask)
  	{
  		/* One or more unblocked signals queued for execution */
! 		int	exec_mask = MySignalShmem->queue & ~pg_signal_mask;
  
  		for (i = 0; i < PG_SIGNAL_COUNT; i++)
  		{
***************
*** 106,117 ****
  
  				if (sig == SIG_DFL)
  					sig = pg_signal_defaults[i];
! 				pg_signal_queue &= ~sigmask(i);
  				if (sig != SIG_ERR && sig != SIG_IGN && sig != SIG_DFL)
  				{
! 					LeaveCriticalSection(&pg_signal_crit_sec);
  					sig(i);
! 					EnterCriticalSection(&pg_signal_crit_sec);
  					break;		/* Restart outer loop, in case signal mask
  								 * or queue has been modified inside
  								 * signal handler */
--- 234,245 ----
  
  				if (sig == SIG_DFL)
  					sig = pg_signal_defaults[i];
! 				MySignalShmem->queue &= ~sigmask(i);
  				if (sig != SIG_ERR && sig != SIG_IGN && sig != SIG_DFL)
  				{
! 					unlock_signal_shmem();
  					sig(i);
! 					lock_signal_shmem();
  					break;		/* Restart outer loop, in case signal mask
  								 * or queue has been modified inside
  								 * signal handler */
***************
*** 119,129 ****
  			}
  		}
  	}
! 	ResetEvent(pgwin32_signal_event);
! 	LeaveCriticalSection(&pg_signal_crit_sec);
  }
  
! /* signal masking. Only called on main thread, no sync required */
  int
  pqsigsetmask(int mask)
  {
--- 247,263 ----
  			}
  		}
  	}
! 	unlock_signal_shmem();
! 	
! 	if (!ResetEvent(MySignalShmem->event))
! 		ereport_signal(ERROR, 
! 				"failed to reset signal waiting event");	
  }
  
! /* 
!  * pqsigsetmask
!  * 		Signal masking emulation in win32. 
!  */
  int
  pqsigsetmask(int mask)
  {
***************
*** 141,148 ****
  	return prevmask;
  }
  
! 
! /* signal manipulation. Only called on main thread, no sync required */
  pqsigfunc
  pqsignal(int signum, pqsigfunc handler)
  {
--- 275,284 ----
  	return prevmask;
  }
  
! /* 
!  * pqsignal
!  * 		Function signal() emulation in win32
!  */
  pqsigfunc
  pqsignal(int signum, pqsigfunc handler)
  {
***************
*** 155,286 ****
  	return prevfunc;
  }
  
! /* Create the signal listener pipe for specified pid */
! HANDLE
! pgwin32_create_signal_listener(pid_t pid)
! {
! 	char		pipename[128];
! 	HANDLE		pipe;
! 
! 	wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%d", (int) pid);
! 
! 	pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
! 						   PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
! 						   PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
! 
! 	if (pipe == INVALID_HANDLE_VALUE)
! 		ereport(ERROR,
! 				(errmsg("could not create signal listener pipe for pid %d: error code %d",
! 						(int) pid, (int) GetLastError())));
! 
! 	return pipe;
! }
! 
! 
! /*
!  * All functions below execute on the signal handler thread
!  * and must be synchronized as such!
!  * NOTE! The only global variable that can be used is
!  * pg_signal_queue!
   */
- 
- 
  void
  pg_queue_signal(int signum)
  {
  	if (signum >= PG_SIGNAL_COUNT || signum <= 0)
  		return;
  
! 	EnterCriticalSection(&pg_signal_crit_sec);
! 	pg_signal_queue |= sigmask(signum);
! 	LeaveCriticalSection(&pg_signal_crit_sec);
! 
! 	SetEvent(pgwin32_signal_event);
! }
! 
! /* Signal dispatching thread */
! static DWORD WINAPI
! pg_signal_dispatch_thread(LPVOID param)
! {
! 	HANDLE		pipe = (HANDLE) param;
! 	BYTE		sigNum;
! 	DWORD		bytes;
! 
! 	if (!ReadFile(pipe, &sigNum, 1, &bytes, NULL))
! 	{
! 		/* Client died before sending */
! 		CloseHandle(pipe);
! 		return 0;
! 	}
! 	if (bytes != 1)
! 	{
! 		/* Received <bytes> bytes over signal pipe (should be 1) */
! 		CloseHandle(pipe);
! 		return 0;
! 	}
! 	WriteFile(pipe, &sigNum, 1, &bytes, NULL);	/* Don't care if it works
! 												 * or not.. */
! 	FlushFileBuffers(pipe);
! 	DisconnectNamedPipe(pipe);
! 	CloseHandle(pipe);
! 
! 	pg_queue_signal(sigNum);
! 	return 0;
! }
! 
! /* Signal handling thread */
! static DWORD WINAPI
! pg_signal_thread(LPVOID param)
! {
! 	char		pipename[128];
! 	HANDLE      pipe = pgwin32_initial_signal_pipe;
! 
! 	wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%d", GetCurrentProcessId());
! 
! 	for (;;)
! 	{
! 		BOOL		fConnected;
! 		HANDLE		hThread;
! 
! 		if (pipe == INVALID_HANDLE_VALUE)
! 		{
! 			pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
! 								   PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
! 								   PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
! 
! 			if (pipe == INVALID_HANDLE_VALUE)
! 			{
! 				write_stderr("could not create signal listener pipe: error code %d; retrying\n", (int) GetLastError());
! 				SleepEx(500, FALSE);
! 				continue;
! 			}
! 		}
! 
! 		fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
! 		if (fConnected)
! 		{
! 			hThread = CreateThread(NULL, 0,
! 					  (LPTHREAD_START_ROUTINE) pg_signal_dispatch_thread,
! 								   (LPVOID) pipe, 0, NULL);
! 			if (hThread == INVALID_HANDLE_VALUE)
! 				write_stderr("could not create signal dispatch thread: error code %d\n",
! 							 (int) GetLastError());
! 			else
! 				CloseHandle(hThread);
! 		}
! 		else
! 			/* Connection failed. Cleanup and try again */
! 			CloseHandle(pipe);
! 
! 		/* Set up so we create a new pipe on next loop */
! 		pipe = INVALID_HANDLE_VALUE;
! 	}
! 	return 0;
  }
  
! 
! /* Console control handler will execute on a thread created
!    by the OS at the time of invocation */
  static BOOL WINAPI
  pg_console_handler(DWORD dwCtrlType)
  {
--- 291,320 ----
  	return prevfunc;
  }
  
! /* 
!  * pg_queue_signal
!  * 		Trigger a signal handling of current process
   */
  void
  pg_queue_signal(int signum)
  {
  	if (signum >= PG_SIGNAL_COUNT || signum <= 0)
  		return;
  
! 	lock_signal_shmem();
! 	MySignalShmem->queue |= sigmask(signum);
! 	unlock_signal_shmem();
! 
! 	if (!SetEvent(MySignalShmem->event))
! 		ereport_signal(ERROR, 
! 				"failed to set signal waiting event");	
  }
  
! /* 
!  * pg_console_handler
!  * 		Console control handler will execute on a thread created
!  *		by the OS at the time of invocation 
!  */
  static BOOL WINAPI
  pg_console_handler(DWORD dwCtrlType)
  {
win32.difftext/plain; charset=US-ASCII; name=win32.diffDownload
Index: src/include/port/win32.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/port/win32.h,v
retrieving revision 1.45
diff -c -r1.45 win32.h
*** src/include/port/win32.h	20 May 2005 14:53:26 -0000	1.45
--- src/include/port/win32.h	4 Jun 2005 11:55:36 -0000
***************
*** 144,149 ****
--- 144,164 ----
  #define SIGUSR1				30
  #define SIGUSR2				31
  
+ /* Number of signaling handles */
+ #define N_SIGNALING_HANDLES		3
+ 
+ /* Signaling variables name prefix */
+ #define SIGNAL_SHMEM_PREFIX		"Global\\PostgreSQL.SignalShmem"
+ #define SIGNAL_MUTEX_PREFIX		"Global\\PostgreSQL.SignalMutex"
+ #define SIGNAL_EVENT_PREFIX		"Global\\PostgreSQL.SignalEvent"
+ 
+ /* Signaling shared memory structure */
+ typedef struct Win32SignalShmemStruct{
+ 	HANDLE	mutex;
+ 	HANDLE  event;
+ 	int		queue;
+ }Win32SignalShmemStruct;
+ 
  struct timezone
  {
  	int			tz_minuteswest; /* Minutes west of GMT.  */
***************
*** 212,225 ****
  
  
  /* In backend/port/win32/signal.c */
- extern DLLIMPORT HANDLE pgwin32_signal_event;
- extern HANDLE pgwin32_initial_signal_pipe;
- 
  void		pgwin32_signal_initialize(void);
! HANDLE		pgwin32_create_signal_listener(pid_t pid);
  void		pgwin32_dispatch_queued_signals(void);
  void		pg_queue_signal(int signum);
  
  #ifndef FRONTEND
  #define pg_usleep(t) pgwin32_backend_usleep(t)
  void		pgwin32_backend_usleep(long microsec);
--- 227,242 ----
  
  
  /* In backend/port/win32/signal.c */
  void		pgwin32_signal_initialize(void);
! void 		pgwin32_create_signaling_area(pid_t pid);
  void		pgwin32_dispatch_queued_signals(void);
  void		pg_queue_signal(int signum);
  
+ extern DLLIMPORT Win32SignalShmemStruct	*MySignalShmem;
+ extern HANDLE pgwin32_initial_signal_handles[N_SIGNALING_HANDLES];
+ 
+ #define pgwin32_signal_event	(MySignalShmem->event)
+ 
  #ifndef FRONTEND
  #define pg_usleep(t) pgwin32_backend_usleep(t)
  void		pgwin32_backend_usleep(long microsec);
#13Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Qingqing Zhou (#11)
Re: psql: \d+ show tablespace of indices

Patch applied. Thanks.

---------------------------------------------------------------------------
Qingqing Zhou wrote:

Now \d show tablespace of indices per discussion.

test=# \d e
Table "public.e"
Column | Type | Modifiers
--------+---------+-----------
i | integer | not null
j | integer | not null
k | integer |
Indexes:
"e_pkey" PRIMARY KEY, btree (i, j), tablespace "haha"
"ei" btree (i)
"ej" btree (j), tablespace "haha"
"ek" btree (k)
Tablespace: "haha"

Content-Description:

[ Attachment, skipping... ]

---------------------------(end of broadcast)---------------------------
TIP 8: explain analyze is your friend

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073