Commit f8da3990 authored by Hiroshi Inoue's avatar Hiroshi Inoue

[HACKERS] Proposed patch for ODBC driver w/ C-a-n-c-e-l

    From: Bradley McLean <brad@bradm.net>

Patch against 7,2 submitted for comment.

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 ...
parent c26a44db
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#ifndef WIN32
#include <errno.h>
#endif /* WIN32 */
#include "environ.h" #include "environ.h"
#include "socket.h" #include "socket.h"
...@@ -289,6 +292,7 @@ CC_Constructor() ...@@ -289,6 +292,7 @@ CC_Constructor()
rv->ms_jet = 0; rv->ms_jet = 0;
rv->unicode = 0; rv->unicode = 0;
rv->result_uncommitted = 0; rv->result_uncommitted = 0;
rv->schema_support = 0;
#ifdef MULTIBYTE #ifdef MULTIBYTE
rv->client_encoding = NULL; rv->client_encoding = NULL;
rv->server_encoding = NULL; rv->server_encoding = NULL;
...@@ -882,8 +886,8 @@ another_version_retry: ...@@ -882,8 +886,8 @@ another_version_retry:
} }
break; break;
case 'K': /* Secret key (6.4 protocol) */ case 'K': /* Secret key (6.4 protocol) */
(void) SOCK_get_int(sock, 4); /* pid */ self->be_pid = SOCK_get_int(sock, 4); /* pid */
(void) SOCK_get_int(sock, 4); /* key */ self->be_key = SOCK_get_int(sock, 4); /* key */
break; break;
case 'Z': /* Backend is ready for new query (6.4) */ case 'Z': /* Backend is ready for new query (6.4) */
...@@ -1960,6 +1964,8 @@ CC_lookup_pg_version(ConnectionClass *self) ...@@ -1960,6 +1964,8 @@ CC_lookup_pg_version(ConnectionClass *self)
self->pg_version_minor = minor; self->pg_version_minor = minor;
} }
self->pg_version_number = (float) atof(szVersion); self->pg_version_number = (float) atof(szVersion);
if (PG_VERSION_GE(self, 7.3))
self->schema_support = 1;
mylog("Got the PostgreSQL version string: '%s'\n", self->pg_version); mylog("Got the PostgreSQL version string: '%s'\n", self->pg_version);
mylog("Extracted PostgreSQL version number: '%1.1f'\n", self->pg_version_number); mylog("Extracted PostgreSQL version number: '%1.1f'\n", self->pg_version_number);
...@@ -2019,3 +2025,64 @@ CC_get_max_query_len(const ConnectionClass *conn) ...@@ -2019,3 +2025,64 @@ CC_get_max_query_len(const ConnectionClass *conn)
value = BLCKSZ; value = BLCKSZ;
return value; 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
return TRUE;
}
...@@ -126,6 +126,21 @@ typedef struct _StartupPacket6_2 ...@@ -126,6 +126,21 @@ typedef struct _StartupPacket6_2
char tty[PATH_SIZE]; char tty[PATH_SIZE];
} StartupPacket6_2; } 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 /* Structure to hold all the connection attributes for a specific
connection (used for both registry and file, DSN and DRIVER) connection (used for both registry and file, DSN and DRIVER)
...@@ -273,11 +288,14 @@ struct ConnectionClass_ ...@@ -273,11 +288,14 @@ struct ConnectionClass_
char ms_jet; char ms_jet;
char unicode; char unicode;
char result_uncommitted; char result_uncommitted;
char schema_support;
#ifdef MULTIBYTE #ifdef MULTIBYTE
char *client_encoding; char *client_encoding;
char *server_encoding; char *server_encoding;
#endif /* MULTIBYTE */ #endif /* MULTIBYTE */
int ccsc; int ccsc;
int be_pid; /* pid returned by backend */
int be_key; /* auth code needed to send cancel */
}; };
...@@ -319,6 +337,7 @@ void CC_lookup_pg_version(ConnectionClass *conn); ...@@ -319,6 +337,7 @@ void CC_lookup_pg_version(ConnectionClass *conn);
void CC_initialize_pg_version(ConnectionClass *conn); void CC_initialize_pg_version(ConnectionClass *conn);
void CC_log_error(const char *func, const char *desc, const ConnectionClass *self); void CC_log_error(const char *func, const char *desc, const ConnectionClass *self);
int CC_get_max_query_len(const ConnectionClass *self); int CC_get_max_query_len(const ConnectionClass *self);
int CC_send_cancel_request(const ConnectionClass *conn);
void CC_on_commit(ConnectionClass *conn); void CC_on_commit(ConnectionClass *conn);
void CC_on_abort(ConnectionClass *conn, BOOL set_no_trans); void CC_on_abort(ConnectionClass *conn, BOOL set_no_trans);
void ProcessRollback(ConnectionClass *conn, BOOL undo); void ProcessRollback(ConnectionClass *conn, BOOL undo);
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Comments: See "notice.txt" for copyright and license information. * Comments: See "notice.txt" for copyright and license information.
* *
* $Id: descriptor.h,v 1.2 2002/04/01 03:01:14 inoue Exp $ * $Id: descriptor.h,v 1.3 2002/04/02 10:50:44 inoue Exp $
* *
*/ */
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
typedef struct typedef struct
{ {
COL_INFO *col_info; /* cached SQLColumns info for this table */ COL_INFO *col_info; /* cached SQLColumns info for this table */
char schema[MAX_TABLE_LEN + 1];
char name[MAX_TABLE_LEN + 1]; char name[MAX_TABLE_LEN + 1];
char alias[MAX_TABLE_LEN + 1]; char alias[MAX_TABLE_LEN + 1];
} TABLE_INFO; } TABLE_INFO;
......
...@@ -573,6 +573,7 @@ PGAPI_Cancel( ...@@ -573,6 +573,7 @@ PGAPI_Cancel(
{ {
static char *func = "PGAPI_Cancel"; static char *func = "PGAPI_Cancel";
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn;
RETCODE result; RETCODE result;
ConnInfo *ci; ConnInfo *ci;
...@@ -589,7 +590,8 @@ PGAPI_Cancel( ...@@ -589,7 +590,8 @@ PGAPI_Cancel(
SC_log_error(func, "", NULL); SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE; return SQL_INVALID_HANDLE;
} }
ci = &(SC_get_conn(stmt)->connInfo); conn = SC_get_conn(stmt);
ci = &(conn->connInfo);
/* /*
* Not in the middle of SQLParamData/SQLPutData so cancel like a * Not in the middle of SQLParamData/SQLPutData so cancel like a
...@@ -597,6 +599,11 @@ PGAPI_Cancel( ...@@ -597,6 +599,11 @@ PGAPI_Cancel(
*/ */
if (stmt->data_at_exec < 0) if (stmt->data_at_exec < 0)
{ {
/*
* Tell the Backend that we're cancelling this request
*/
if (stmt->status == STMT_EXECUTING)
CC_send_cancel_request(conn);
/* /*
* MAJOR HACK for Windows to reset the driver manager's cursor * MAJOR HACK for Windows to reset the driver manager's cursor
* state: Because of what seems like a bug in the Odbc driver * state: Because of what seems like a bug in the Odbc driver
......
This diff is collapsed.
...@@ -171,10 +171,10 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, ...@@ -171,10 +171,10 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
break; break;
case SQL_CREATE_SCHEMA: case SQL_CREATE_SCHEMA:
len = 4; len = 4;
if (PG_VERSION_LE(conn, 7.2)) if (conn->schema_support)
value = 0; value = SQL_CS_CREATE_SCHEMA | SQL_CS_AUTHORIZATION;
else else
value = SQL_CS_CREATE_SCHEMA | SQL_CS_AUTHORIZATION; /* hopefully */ value = 0;
break; break;
case SQL_CREATE_TABLE: case SQL_CREATE_TABLE:
len = 4; len = 4;
...@@ -218,10 +218,10 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, ...@@ -218,10 +218,10 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
break; break;
case SQL_DROP_SCHEMA: case SQL_DROP_SCHEMA:
len = 4; len = 4;
if (PG_VERSION_LE(conn, 7.2)) if (conn->schema_support)
value = 0; value = SQL_DS_DROP_SCHEMA | SQL_DS_RESTRICT | SQL_DS_CASCADE;
else else
value = SQL_DS_DROP_SCHEMA | SQL_DS_RESTRICT | SQL_DS_CASCADE; /* hopefully */ value = 0;
break; break;
case SQL_DROP_TABLE: case SQL_DROP_TABLE:
len = 4; len = 4;
......
...@@ -279,6 +279,18 @@ my_strcat(char *buf, const char *fmt, const char *s, int len) ...@@ -279,6 +279,18 @@ my_strcat(char *buf, const char *fmt, const char *s, int len)
return NULL; return NULL;
} }
char *
schema_strcat(char *buf, const char *fmt, const char *s, int len, const char *tbname, int tbnmlen)
{
if (!s || 0 == len)
{
if (tbname && (tbnmlen > 0 || tbnmlen == SQL_NTS))
return my_strcat(buf, fmt, "public", 6);
return NULL;
}
return my_strcat(buf, fmt, s, len);
}
void void
remove_newlines(char *string) remove_newlines(char *string)
......
...@@ -89,6 +89,9 @@ char *strncpy_null(char *dst, const char *src, int len); ...@@ -89,6 +89,9 @@ char *strncpy_null(char *dst, const char *src, int len);
char *trim(char *string); char *trim(char *string);
char *make_string(const char *s, int len, char *buf); char *make_string(const char *s, int len, char *buf);
char *my_strcat(char *buf, const char *fmt, const char *s, int len); char *my_strcat(char *buf, const char *fmt, const char *s, int len);
char *schema_strcat(char *buf, const char *fmt, const char *s, int len,
const char *, int);
#define GET_SCHEMA_NAME(nspname) (stricmp(nspname, "public") ? nspname : "")
/* defines for return value of my_strcpy */ /* defines for return value of my_strcpy */
#define STRCPY_SUCCESS 1 #define STRCPY_SUCCESS 1
......
...@@ -543,15 +543,21 @@ parse_statement(StatementClass *stmt) ...@@ -543,15 +543,21 @@ parse_statement(StatementClass *stmt)
*/ */
if (in_dot) if (in_dot)
{ {
irdflds->nfields--; int ifld = irdflds->nfields - 1;
strcpy(fi[irdflds->nfields]->dot, fi[irdflds->nfields]->name);
strcpy(fi[irdflds->nfields]->name, token); if (fi[ifld]->dot[0])
irdflds->nfields++; {
in_dot = FALSE; strcat(fi[ifld]->dot, ".");
strcat(fi[ifld]->dot, fi[ifld]->name);
}
else
strcpy(fi[ifld]->dot, fi[ifld]->name);
strcpy(fi[ifld]->name, token);
if (delim == ',') if (delim == ',')
{ {
mylog("in_dot: got comma\n"); mylog("in_dot: got comma\n");
in_dot = FALSE;
in_field = FALSE; in_field = FALSE;
} }
continue; continue;
...@@ -575,6 +581,7 @@ parse_statement(StatementClass *stmt) ...@@ -575,6 +581,7 @@ parse_statement(StatementClass *stmt)
/* Function */ /* Function */
if (token[0] == '(') if (token[0] == '(')
{ {
in_dot = FALSE;
in_func = TRUE; in_func = TRUE;
blevel = 1; blevel = 1;
fi[irdflds->nfields - 1]->func = TRUE; fi[irdflds->nfields - 1]->func = TRUE;
...@@ -594,6 +601,7 @@ parse_statement(StatementClass *stmt) ...@@ -594,6 +601,7 @@ parse_statement(StatementClass *stmt)
continue; continue;
} }
in_dot = FALSE;
if (!stricmp(token, "as")) if (!stricmp(token, "as"))
{ {
in_as = TRUE; in_as = TRUE;
...@@ -644,6 +652,7 @@ parse_statement(StatementClass *stmt) ...@@ -644,6 +652,7 @@ parse_statement(StatementClass *stmt)
return FALSE; return FALSE;
} }
ti[stmt->ntab]->schema[0] = '\0';
ti[stmt->ntab]->alias[0] = '\0'; ti[stmt->ntab]->alias[0] = '\0';
strcpy(ti[stmt->ntab]->name, token); strcpy(ti[stmt->ntab]->name, token);
...@@ -680,6 +689,7 @@ parse_statement(StatementClass *stmt) ...@@ -680,6 +689,7 @@ parse_statement(StatementClass *stmt)
in_table = TRUE; in_table = TRUE;
} }
stmt->ntab++; stmt->ntab++;
in_dot = FALSE;
continue; continue;
} }
...@@ -689,9 +699,21 @@ parse_statement(StatementClass *stmt) ...@@ -689,9 +699,21 @@ parse_statement(StatementClass *stmt)
out_table = TRUE; out_table = TRUE;
continue; continue;
} }
if (in_table && stricmp(token, "as")) if (in_table)
{ {
if (!dquote) if (in_dot)
{
strcpy(ti[stmt->ntab - 1]->schema, ti[stmt->ntab - 1]->name);
strcpy(ti[stmt->ntab - 1]->name, token);
in_dot = FALSE;
continue;
}
if (strcmp(token, ".") == 0)
{
in_dot = TRUE;
continue;
}
if (!dquote && stricmp(token, "as"))
{ {
if (stricmp(token, "LEFT") == 0 || if (stricmp(token, "LEFT") == 0 ||
stricmp(token, "RIGHT") == 0 || stricmp(token, "RIGHT") == 0 ||
...@@ -702,7 +724,6 @@ parse_statement(StatementClass *stmt) ...@@ -702,7 +724,6 @@ parse_statement(StatementClass *stmt)
in_table = FALSE; in_table = FALSE;
continue; continue;
} }
}
strcpy(ti[stmt->ntab - 1]->alias, token); strcpy(ti[stmt->ntab - 1]->alias, token);
mylog("alias for table '%s' is '%s'\n", ti[stmt->ntab - 1]->name, ti[stmt->ntab - 1]->alias); mylog("alias for table '%s' is '%s'\n", ti[stmt->ntab - 1]->name, ti[stmt->ntab - 1]->alias);
in_table = FALSE; in_table = FALSE;
...@@ -712,6 +733,7 @@ parse_statement(StatementClass *stmt) ...@@ -712,6 +733,7 @@ parse_statement(StatementClass *stmt)
mylog("more than 1 tables\n"); mylog("more than 1 tables\n");
} }
} }
}
} /* in_from */ } /* in_from */
} }
...@@ -823,8 +845,8 @@ parse_statement(StatementClass *stmt) ...@@ -823,8 +845,8 @@ parse_statement(StatementClass *stmt)
col_stmt = (StatementClass *) hcol_stmt; col_stmt = (StatementClass *) hcol_stmt;
col_stmt->internal = TRUE; col_stmt->internal = TRUE;
result = PGAPI_Columns(hcol_stmt, "", 0, "", 0, result = PGAPI_Columns(hcol_stmt, "", 0, ti[i]->schema,
ti[i]->name, (SWORD) strlen(ti[i]->name), "", 0, PODBC_NOT_SEARCH_PATTERN); SQL_NTS, ti[i]->name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN);
mylog(" Past PG_Columns\n"); mylog(" Past PG_Columns\n");
if (result == SQL_SUCCESS) if (result == SQL_SUCCESS)
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Comments: See "notice.txt" for copyright and license information. * Comments: See "notice.txt" for copyright and license information.
* *
* $Id: psqlodbc.h,v 1.62 2002/04/01 03:01:15 inoue Exp $ * $Id: psqlodbc.h,v 1.63 2002/04/02 10:50:49 inoue Exp $
* *
*/ */
......
...@@ -107,7 +107,6 @@ char ...@@ -107,7 +107,6 @@ char
SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname) SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
{ {
struct hostent *host; struct hostent *host;
struct sockaddr_in sadr;
unsigned long iaddr; unsigned long iaddr;
if (self->socket != -1) if (self->socket != -1)
...@@ -117,7 +116,7 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname) ...@@ -117,7 +116,7 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
return 0; return 0;
} }
memset((char *) &sadr, 0, sizeof(sadr)); memset((char *) &(self->sadr), 0, sizeof(self->sadr));
/* /*
* If it is a valid IP address, use it. Otherwise use hostname lookup. * If it is a valid IP address, use it. Otherwise use hostname lookup.
...@@ -132,13 +131,13 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname) ...@@ -132,13 +131,13 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
self->errormsg = "Could not resolve hostname."; self->errormsg = "Could not resolve hostname.";
return 0; return 0;
} }
memcpy(&(sadr.sin_addr), host->h_addr, host->h_length); memcpy(&(self->sadr.sin_addr), host->h_addr, host->h_length);
} }
else else
memcpy(&(sadr.sin_addr), (struct in_addr *) & iaddr, sizeof(iaddr)); memcpy(&(self->sadr.sin_addr), (struct in_addr *) & iaddr, sizeof(iaddr));
sadr.sin_family = AF_INET; self->sadr.sin_family = AF_INET;
sadr.sin_port = htons(port); self->sadr.sin_port = htons(port);
self->socket = socket(AF_INET, SOCK_STREAM, 0); self->socket = socket(AF_INET, SOCK_STREAM, 0);
if (self->socket == -1) if (self->socket == -1)
...@@ -148,8 +147,8 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname) ...@@ -148,8 +147,8 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
return 0; return 0;
} }
if (connect(self->socket, (struct sockaddr *) & (sadr), if (connect(self->socket, (struct sockaddr *) & (self->sadr),
sizeof(sadr)) < 0) sizeof(self->sadr)) < 0)
{ {
self->errornumber = SOCKET_COULD_NOT_CONNECT; self->errornumber = SOCKET_COULD_NOT_CONNECT;
self->errormsg = "Could not connect to remote socket."; self->errormsg = "Could not connect to remote socket.";
......
...@@ -61,6 +61,7 @@ struct SocketClass_ ...@@ -61,6 +61,7 @@ struct SocketClass_
char *errormsg; char *errormsg;
int errornumber; int errornumber;
struct sockaddr_in sadr; /* Used for handling connections for cancel */
char reverse; /* used to handle Postgres 6.2 protocol char reverse; /* used to handle Postgres 6.2 protocol
* (reverse byte order) */ * (reverse byte order) */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment