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
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 [EMAIL PROTECTED])

Reply via email to