[prev in list] [next in list] [prev in thread] [next in thread] 

List:       postgresql-general
Subject:    [HACKERS] hackers mail broken?
From:       Bradley McLean <brad () bradm ! net>
Date:       2002-03-29 13:38:12
[Download RAW message or body]

Original titles:
 Patch to add real cancel to ODBC driver
 Patch to add real can--cel to ODBC driver

Bruce, sorry to bother you, would you forward this onto the list?
I can't post for reasons I can't fathom.

-----
Patch against 7,2 submitted for comment.
 
It's a little messy; I had some trouble trying to reconcile the code
style of libpq which I copied from, and odbc.
 
Suggestions on what parts look ugly, and or where to send this
(is there a separate ODBC place?) are welcome.
 
This seems to work just fine; Now, when our users submit a 2 hour
query with four million row sorts by accident, then cancel it 30 seconds
later, it doesn't bog down the server ...
 
regards,
 
-Brad

["odbccancel.patch" (text/plain)]

diff -cr postgresql-7.2/src/interfaces/odbc/connection.c \
                postgresql-7.2-brad/src/interfaces/odbc/connection.c
*** postgresql-7.2/src/interfaces/odbc/connection.c	Sun Dec 30 18:09:42 2001
--- postgresql-7.2-brad/src/interfaces/odbc/connection.c	Wed Mar 27 10:04:45 2002
***************
*** 19,24 ****
--- 19,27 ----
  #include <stdio.h>
  #include <string.h>
  #include <ctype.h>
+ #ifndef WIN32
+ #include <errno.h>
+ #endif
  
  #include "environ.h"
  #include "socket.h"
***************
*** 828,835 ****
  					}
  					break;
  				case 'K':		/* Secret key (6.4 protocol) */
! 					(void) SOCK_get_int(sock, 4);		/* pid */
! 					(void) SOCK_get_int(sock, 4);		/* key */
  
  					break;
  				case 'Z':		/* Backend is ready for new query (6.4) */
--- 831,839 ----
  					}
  					break;
  				case 'K':		/* Secret key (6.4 protocol) */
! 					self->be_pid = SOCK_get_int(sock, 4);		/* pid */
! 					self->be_key = SOCK_get_int(sock, 4);		/* key */
! 					qlog("conn=%u, Backend pid=%u\n",self,self->be_pid);
  
  					break;
  				case 'Z':		/* Backend is ready for new query (6.4) */
***************
*** 1837,1839 ****
--- 1841,1903 ----
  		value = BLCKSZ;
  	return value;
  }
+ 
+ int
+ CC_send_cancel_request(const ConnectionClass *conn)
+ {
+ #ifdef WIN32
+ 	int			save_errno = (WSAGetLastError());
+ #else
+         int                     save_errno = errno;
+ #endif
+         int                     tmpsock = -1;
+         struct
+         {
+                 uint32          packetlen;
+                 CancelRequestPacket cp;
+         }                       crp;
+ 
+         /* Check we have an open connection */
+         if (!conn)
+                 return FALSE;
+ 
+         if (conn->sock == NULL )
+         {
+                 return FALSE;
+         }
+ 
+         /*
+          * We need to open a temporary connection to the postmaster. Use the
+          * information saved by connectDB to do this with only kernel calls.
+          */
+         if ((tmpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+         {
+ 		return FALSE;
+         }
+         if (connect(tmpsock, (struct sockaddr *)&(conn->sock->sadr),
+ 				sizeof(conn->sock->sadr)) < 0)
+         {
+ 		return FALSE;
+         }
+ 
+         /*
+          * We needn't set nonblocking I/O or NODELAY options here.
+          */
+         crp.packetlen = htonl((uint32) sizeof(crp));
+         crp.cp.cancelRequestCode = (MsgType) htonl(CANCEL_REQUEST_CODE);
+         crp.cp.backendPID = htonl(conn->be_pid);
+         crp.cp.cancelAuthCode = htonl(conn->be_key);
+ 
+         if (send(tmpsock, (char *) &crp, sizeof(crp), 0) != (int) sizeof(crp))
+         {
+ 		return FALSE;
+         }
+ 
+         /* Sent it, done */
+         closesocket(tmpsock);
+ #ifdef WIN32
+         WSASetLastError(save_errno);
+ #else
+         errno = save_errno;
+ #endif
+ }
diff -cr postgresql-7.2/src/interfaces/odbc/connection.h \
                postgresql-7.2-brad/src/interfaces/odbc/connection.h
*** postgresql-7.2/src/interfaces/odbc/connection.h	Mon Nov  5 12:46:38 2001
--- postgresql-7.2-brad/src/interfaces/odbc/connection.h	Tue Mar 26 14:45:35 2002
***************
*** 125,130 ****
--- 125,146 ----
  	char		tty[PATH_SIZE];
  } StartupPacket6_2;
  
+ /* Transferred from pqcomm.h:  */
+ 
+ 
+ typedef ProtocolVersion MsgType;
+ 
+ #define PG_PROTOCOL(m,n)   (((m) << 16) | (n))
+ #define CANCEL_REQUEST_CODE PG_PROTOCOL(1234,5678)
+ 
+ typedef struct CancelRequestPacket
+ {
+         /* Note that each field is stored in network byte order! */
+         MsgType         cancelRequestCode;              /* code to identify a \
cancel request */ +         unsigned int    backendPID;             /* PID of \
client's backend */ +         unsigned int    cancelAuthCode; /* secret key to \
authorize cancel */ + } CancelRequestPacket;
+ 
  
  /*	Structure to hold all the connection attributes for a specific
  	connection (used for both registry and file, DSN and DRIVER)
***************
*** 266,271 ****
--- 282,289 ----
  	Int2		pg_version_major;
  	Int2		pg_version_minor;
  	char		ms_jet;
+ 	int		be_pid;		/* pid returned by backend */
+ 	int		be_key;	/* auth code needed to send cancel */
  #ifdef	MULTIBYTE
  	char	   *client_encoding;
  	char	   *server_encoding;
diff -cr postgresql-7.2/src/interfaces/odbc/execute.c \
                postgresql-7.2-brad/src/interfaces/odbc/execute.c
*** postgresql-7.2/src/interfaces/odbc/execute.c	Thu Oct 25 01:50:14 2001
--- postgresql-7.2-brad/src/interfaces/odbc/execute.c	Wed Mar 27 11:20:26 2002
***************
*** 510,515 ****
--- 510,519 ----
  	if (stmt->data_at_exec < 0)
  	{
  		/*
+ 		 * Tell the Backend that we're cancelling this request
+ 		 */
+ 		CC_send_cancel_request(SC_get_conn(stmt));
+ 		/*
  		 * MAJOR HACK for Windows to reset the driver manager's cursor
  		 * state: Because of what seems like a bug in the Odbc driver
  		 * manager, SQLCancel does not act like a SQLFreeStmt(CLOSE), as
***************
*** 517,523 ****
  		 * force method calls the driver manager's function on behalf of
  		 * the application.
  		 */
- 
  #ifdef WIN32
  		if (ci->drivers.cancel_as_freestmt)
  		{
--- 521,526 ----
diff -cr postgresql-7.2/src/interfaces/odbc/socket.c \
                postgresql-7.2-brad/src/interfaces/odbc/socket.c
*** postgresql-7.2/src/interfaces/odbc/socket.c	Sun Oct 28 01:26:14 2001
--- postgresql-7.2-brad/src/interfaces/odbc/socket.c	Tue Mar 26 21:40:59 2002
***************
*** 107,113 ****
  SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
  {
  	struct hostent *host;
- 	struct sockaddr_in sadr;
  	unsigned long iaddr;
  
  	if (self->socket != -1)
--- 107,112 ----
***************
*** 117,123 ****
  		return 0;
  	}
  
! 	memset((char *) &sadr, 0, sizeof(sadr));
  
  	/*
  	 * If it is a valid IP address, use it. Otherwise use hostname lookup.
--- 116,122 ----
  		return 0;
  	}
  
! 	memset((char *) &(self->sadr), 0, sizeof(self->sadr));
  
  	/*
  	 * If it is a valid IP address, use it. Otherwise use hostname lookup.
***************
*** 132,144 ****
  			self->errormsg = "Could not resolve hostname.";
  			return 0;
  		}
! 		memcpy(&(sadr.sin_addr), host->h_addr, host->h_length);
  	}
  	else
! 		memcpy(&(sadr.sin_addr), (struct in_addr *) & iaddr, sizeof(iaddr));
  
! 	sadr.sin_family = AF_INET;
! 	sadr.sin_port = htons(port);
  
  	self->socket = socket(AF_INET, SOCK_STREAM, 0);
  	if (self->socket == -1)
--- 131,143 ----
  			self->errormsg = "Could not resolve hostname.";
  			return 0;
  		}
! 		memcpy(&(self->sadr.sin_addr), host->h_addr, host->h_length);
  	}
  	else
! 		memcpy(&(self->sadr.sin_addr), (struct in_addr *) & iaddr, sizeof(iaddr));
  
! 	self->sadr.sin_family = AF_INET;
! 	self->sadr.sin_port = htons(port);
  
  	self->socket = socket(AF_INET, SOCK_STREAM, 0);
  	if (self->socket == -1)
***************
*** 148,155 ****
  		return 0;
  	}
  
! 	if (connect(self->socket, (struct sockaddr *) & (sadr),
! 				sizeof(sadr)) < 0)
  	{
  		self->errornumber = SOCKET_COULD_NOT_CONNECT;
  		self->errormsg = "Could not connect to remote socket.";
--- 147,154 ----
  		return 0;
  	}
  
! 	if (connect(self->socket, (struct sockaddr *) & (self->sadr),
! 				sizeof(self->sadr)) < 0)
  	{
  		self->errornumber = SOCKET_COULD_NOT_CONNECT;
  		self->errormsg = "Could not connect to remote socket.";
diff -cr postgresql-7.2/src/interfaces/odbc/socket.h \
                postgresql-7.2-brad/src/interfaces/odbc/socket.h
*** postgresql-7.2/src/interfaces/odbc/socket.h	Sun Oct 28 01:26:15 2001
--- postgresql-7.2-brad/src/interfaces/odbc/socket.h	Tue Mar 26 21:35:41 2002
***************
*** 64,70 ****
  
  	char		reverse;		/* used to handle Postgres 6.2 protocol
  								 * (reverse byte order) */
! 
  };
  
  #define SOCK_get_char(self)		(SOCK_get_next_byte(self))
--- 64,70 ----
  
  	char		reverse;		/* used to handle Postgres 6.2 protocol
  								 * (reverse byte order) */
!         struct sockaddr_in sadr; /* Used for handling connections for cancel */
  };
  
  #define SOCK_get_char(self)		(SOCK_get_next_byte(self))



---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
    (send "unregister YourEmailAddressHere" to majordomo@postgresql.org)


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic