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
......
...@@ -1169,7 +1169,7 @@ PGAPI_Tables( ...@@ -1169,7 +1169,7 @@ PGAPI_Tables(
systable; systable;
int i; int i;
mylog("%s: entering...stmt=%u\n", func, stmt); mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner);
if (!stmt) if (!stmt)
{ {
...@@ -1196,7 +1196,13 @@ PGAPI_Tables( ...@@ -1196,7 +1196,13 @@ PGAPI_Tables(
/* /*
* Create the query to find out the tables * Create the query to find out the tables
*/ */
if (PG_VERSION_GE(conn, 7.1)) if (conn->schema_support)
{
/* view is represented by its relkind since 7.1 */
strcpy(tables_query, "select relname, nspname, relkind from pg_class, pg_namespace");
strcat(tables_query, " where relkind in ('r', 'v')");
}
else if (PG_VERSION_GE(conn, 7.1))
{ {
/* view is represented by its relkind since 7.1 */ /* view is represented by its relkind since 7.1 */
strcpy(tables_query, "select relname, usename, relkind from pg_class, pg_user"); strcpy(tables_query, "select relname, usename, relkind from pg_class, pg_user");
...@@ -1208,7 +1214,10 @@ PGAPI_Tables( ...@@ -1208,7 +1214,10 @@ PGAPI_Tables(
strcat(tables_query, " where relkind = 'r'"); strcat(tables_query, " where relkind = 'r'");
} }
my_strcat(tables_query, " and usename like '%.*s'", szTableOwner, cbTableOwner); if (conn->schema_support)
schema_strcat(tables_query, " and nspname like '%.*s'", szTableOwner, cbTableOwner, szTableName, cbTableName);
else
my_strcat(tables_query, " and usename like '%.*s'", szTableOwner, cbTableOwner);
my_strcat(tables_query, " and relname like '%.*s'", szTableName, cbTableName); my_strcat(tables_query, " and relname like '%.*s'", szTableName, cbTableName);
/* Parse the extra systable prefix */ /* Parse the extra systable prefix */
...@@ -1278,8 +1287,10 @@ PGAPI_Tables( ...@@ -1278,8 +1287,10 @@ PGAPI_Tables(
/* filter out large objects in older versions */ /* filter out large objects in older versions */
strcat(tables_query, " and relname !~ '^xinv[0-9]+'"); strcat(tables_query, " and relname !~ '^xinv[0-9]+'");
strcat(tables_query, " and usesysid = relowner"); if (conn->schema_support)
strcat(tables_query, " order by relname"); strcat(tables_query, " and pg_namespace.oid = relnamespace order by nspname, relname");
else
strcat(tables_query, " and usesysid = relowner order by relname");
result = PGAPI_ExecDirect(htbl_stmt, tables_query, strlen(tables_query)); result = PGAPI_ExecDirect(htbl_stmt, tables_query, strlen(tables_query));
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
...@@ -1404,7 +1415,6 @@ PGAPI_Tables( ...@@ -1404,7 +1415,6 @@ PGAPI_Tables(
row = (TupleNode *) malloc(sizeof(TupleNode) + (5 - 1) *sizeof(TupleField)); row = (TupleNode *) malloc(sizeof(TupleNode) + (5 - 1) *sizeof(TupleField));
/*set_tuplefield_string(&row->tuple[0], "");*/ /*set_tuplefield_string(&row->tuple[0], "");*/
/*set_tuplefield_string(&row->tuple[0], "cat0");*/
set_tuplefield_null(&row->tuple[0]); set_tuplefield_null(&row->tuple[0]);
/* /*
...@@ -1418,8 +1428,11 @@ PGAPI_Tables( ...@@ -1418,8 +1428,11 @@ PGAPI_Tables(
mylog("%s: table_name = '%s'\n", func, table_name); mylog("%s: table_name = '%s'\n", func, table_name);
/* set_tuplefield_string(&row->tuple[1], ""); */ if (conn->schema_support)
set_tuplefield_null(&row->tuple[1]); set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner));
else
/* set_tuplefield_string(&row->tuple[1], ""); */
set_tuplefield_null(&row->tuple[1]);
set_tuplefield_string(&row->tuple[2], table_name); set_tuplefield_string(&row->tuple[2], table_name);
set_tuplefield_string(&row->tuple[3], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE")); set_tuplefield_string(&row->tuple[3], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE"));
/*set_tuplefield_string(&row->tuple[4], "");*/ /*set_tuplefield_string(&row->tuple[4], "");*/
...@@ -1561,7 +1574,7 @@ PGAPI_Columns( ...@@ -1561,7 +1574,7 @@ PGAPI_Columns(
ConnectionClass *conn; ConnectionClass *conn;
mylog("%s: entering...stmt=%u\n", func, stmt); mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner);
if (!stmt) if (!stmt)
{ {
...@@ -1579,7 +1592,15 @@ PGAPI_Columns( ...@@ -1579,7 +1592,15 @@ PGAPI_Columns(
* Create the query to find out the columns (Note: pre 6.3 did not * Create the query to find out the columns (Note: pre 6.3 did not
* have the atttypmod field) * have the atttypmod field)
*/ */
sprintf(columns_query, "select u.usename, c.relname, a.attname, a.atttypid" if (conn->schema_support)
sprintf(columns_query, "select u.nspname, c.relname, a.attname, a.atttypid"
", t.typname, a.attnum, a.attlen, %s, a.attnotnull, c.relhasrules"
" from pg_namespace u, pg_class c, pg_attribute a, pg_type t"
" where u.oid = c.relnamespace"
" and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)",
"a.atttypmod");
else
sprintf(columns_query, "select u.usename, c.relname, a.attname, a.atttypid"
", t.typname, a.attnum, a.attlen, %s, a.attnotnull, c.relhasrules" ", t.typname, a.attnum, a.attlen, %s, a.attnotnull, c.relhasrules"
" from pg_user u, pg_class c, pg_attribute a, pg_type t" " from pg_user u, pg_class c, pg_attribute a, pg_type t"
" where u.usesysid = c.relowner" " where u.usesysid = c.relowner"
...@@ -1589,7 +1610,10 @@ PGAPI_Columns( ...@@ -1589,7 +1610,10 @@ PGAPI_Columns(
if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0) if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0)
{ {
my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName); my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName);
my_strcat(columns_query, " and u.usename = '%.*s'", szTableOwner, cbTableOwner); if (conn->schema_support)
schema_strcat(columns_query, " and u.nspname = '%.*s'", szTableOwner, cbTableOwner, szTableName, cbTableName);
else
my_strcat(columns_query, " and u.usename = '%.*s'", szTableOwner, cbTableOwner);
my_strcat(columns_query, " and a.attname = '%.*s'", szColumnName, cbColumnName); my_strcat(columns_query, " and a.attname = '%.*s'", szColumnName, cbColumnName);
} }
else else
...@@ -1599,7 +1623,10 @@ PGAPI_Columns( ...@@ -1599,7 +1623,10 @@ PGAPI_Columns(
escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name), conn->ccsc); escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name), conn->ccsc);
my_strcat(columns_query, " and c.relname like '%.*s'", esc_table_name, escTbnamelen); my_strcat(columns_query, " and c.relname like '%.*s'", esc_table_name, escTbnamelen);
my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner); if (conn->schema_support)
schema_strcat(columns_query, " and u.nspname like '%.*s'", szTableOwner, cbTableOwner, szTableName, cbTableName);
else
my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner);
my_strcat(columns_query, " and a.attname like '%.*s'", szColumnName, cbColumnName); my_strcat(columns_query, " and a.attname like '%.*s'", szColumnName, cbColumnName);
} }
...@@ -1607,7 +1634,10 @@ PGAPI_Columns( ...@@ -1607,7 +1634,10 @@ PGAPI_Columns(
* give the output in the order the columns were defined when the * give the output in the order the columns were defined when the
* table was created * table was created
*/ */
strcat(columns_query, " order by attnum"); if (conn->schema_support)
strcat(columns_query, " order by u.nspname, c.relname, attnum");
else
strcat(columns_query, " order by c.relname, attnum");
result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt); result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
...@@ -1815,8 +1845,10 @@ PGAPI_Columns( ...@@ -1815,8 +1845,10 @@ PGAPI_Columns(
set_tuplefield_string(&row->tuple[0], ""); set_tuplefield_string(&row->tuple[0], "");
/* see note in SQLTables() */ /* see note in SQLTables() */
/* set_tuplefield_string(&row->tuple[1], table_owner); */ if (conn->schema_support)
set_tuplefield_string(&row->tuple[1], ""); set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner));
else
set_tuplefield_string(&row->tuple[1], "");
set_tuplefield_string(&row->tuple[2], table_name); set_tuplefield_string(&row->tuple[2], table_name);
set_tuplefield_string(&row->tuple[3], "oid"); set_tuplefield_string(&row->tuple[3], "oid");
sqltype = pgtype_to_concise_type(stmt, the_type); sqltype = pgtype_to_concise_type(stmt, the_type);
...@@ -1854,8 +1886,10 @@ PGAPI_Columns( ...@@ -1854,8 +1886,10 @@ PGAPI_Columns(
set_tuplefield_string(&row->tuple[0], ""); set_tuplefield_string(&row->tuple[0], "");
/* see note in SQLTables() */ /* see note in SQLTables() */
/* set_tuplefield_string(&row->tuple[1], table_owner); */ if (conn->schema_support)
set_tuplefield_string(&row->tuple[1], ""); set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner));
else
set_tuplefield_string(&row->tuple[1], "");
set_tuplefield_string(&row->tuple[2], table_name); set_tuplefield_string(&row->tuple[2], table_name);
set_tuplefield_string(&row->tuple[3], field_name); set_tuplefield_string(&row->tuple[3], field_name);
sqltype = pgtype_to_concise_type(stmt, field_type); sqltype = pgtype_to_concise_type(stmt, field_type);
...@@ -1980,7 +2014,10 @@ PGAPI_Columns( ...@@ -1980,7 +2014,10 @@ PGAPI_Columns(
(result_cols - 1) *sizeof(TupleField)); (result_cols - 1) *sizeof(TupleField));
set_tuplefield_string(&row->tuple[0], ""); set_tuplefield_string(&row->tuple[0], "");
set_tuplefield_string(&row->tuple[1], ""); if (conn->schema_support)
set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner));
else
set_tuplefield_string(&row->tuple[1], "");
set_tuplefield_string(&row->tuple[2], table_name); set_tuplefield_string(&row->tuple[2], table_name);
set_tuplefield_string(&row->tuple[3], "xmin"); set_tuplefield_string(&row->tuple[3], "xmin");
sqltype = pgtype_to_concise_type(stmt, the_type); sqltype = pgtype_to_concise_type(stmt, the_type);
...@@ -2040,6 +2077,7 @@ PGAPI_SpecialColumns( ...@@ -2040,6 +2077,7 @@ PGAPI_SpecialColumns(
static char *func = "PGAPI_SpecialColumns"; static char *func = "PGAPI_SpecialColumns";
TupleNode *row; TupleNode *row;
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn;
QResultClass *res; QResultClass *res;
ConnInfo *ci; ConnInfo *ci;
HSTMT hcol_stmt; HSTMT hcol_stmt;
...@@ -2048,28 +2086,37 @@ PGAPI_SpecialColumns( ...@@ -2048,28 +2086,37 @@ PGAPI_SpecialColumns(
RETCODE result; RETCODE result;
char relhasrules[MAX_INFO_STRING]; char relhasrules[MAX_INFO_STRING];
mylog("%s: entering...stmt=%u\n", func, stmt); mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner);
if (!stmt) if (!stmt)
{ {
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);
stmt->manual_result = TRUE; stmt->manual_result = TRUE;
/* /*
* Create the query to find out if this is a view or not... * Create the query to find out if this is a view or not...
*/ */
sprintf(columns_query, "select c.relhasrules " if (conn->schema_support)
sprintf(columns_query, "select c.relhasrules "
"from pg_namespace u, pg_class c where "
"u.oid = c.relnamespace");
else
sprintf(columns_query, "select c.relhasrules "
"from pg_user u, pg_class c where " "from pg_user u, pg_class c where "
"u.usesysid = c.relowner"); "u.usesysid = c.relowner");
/* TableName cannot contain a string search pattern */ /* TableName cannot contain a string search pattern */
my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName); my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName);
/* SchemaName cannot contain a string search pattern */ /* SchemaName cannot contain a string search pattern */
my_strcat(columns_query, " and u.usename = '%.*s'", szTableOwner, cbTableOwner); if (conn->schema_support)
schema_strcat(columns_query, " and u.nspname = '%.*s'", szTableOwner, cbTableOwner, szTableName, cbTableName);
else
my_strcat(columns_query, " and u.usename = '%.*s'", szTableOwner, cbTableOwner);
result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt); result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
...@@ -2188,11 +2235,12 @@ PGAPI_Statistics( ...@@ -2188,11 +2235,12 @@ PGAPI_Statistics(
{ {
static char *func = "PGAPI_Statistics"; static char *func = "PGAPI_Statistics";
StatementClass *stmt = (StatementClass *) hstmt; StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn;
QResultClass *res; QResultClass *res;
char index_query[INFO_INQUIRY_LEN]; char index_query[INFO_INQUIRY_LEN];
HSTMT hindx_stmt; HSTMT hindx_stmt;
RETCODE result; RETCODE result;
char *table_name; char *table_name, *schema_name = NULL;
char index_name[MAX_INFO_STRING]; char index_name[MAX_INFO_STRING];
short fields_vector[16]; short fields_vector[16];
char isunique[10], char isunique[10],
...@@ -2206,7 +2254,8 @@ PGAPI_Statistics( ...@@ -2206,7 +2254,8 @@ PGAPI_Statistics(
StatementClass *col_stmt, StatementClass *col_stmt,
*indx_stmt; *indx_stmt;
char column_name[MAX_INFO_STRING], char column_name[MAX_INFO_STRING],
relhasrules[MAX_INFO_STRING]; table_qualifier[MAX_INFO_STRING],
relhasrules[10];
char **column_names = 0; char **column_names = 0;
SQLINTEGER column_name_len; SQLINTEGER column_name_len;
int total_columns = 0; int total_columns = 0;
...@@ -2214,7 +2263,7 @@ PGAPI_Statistics( ...@@ -2214,7 +2263,7 @@ PGAPI_Statistics(
ConnInfo *ci; ConnInfo *ci;
char buf[256]; char buf[256];
mylog("%s: entering...stmt=%u\n", func, stmt); mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner);
if (!stmt) if (!stmt)
{ {
...@@ -2225,7 +2274,8 @@ PGAPI_Statistics( ...@@ -2225,7 +2274,8 @@ PGAPI_Statistics(
stmt->manual_result = TRUE; stmt->manual_result = TRUE;
stmt->errormsg_created = TRUE; stmt->errormsg_created = TRUE;
ci = &(SC_get_conn(stmt)->connInfo); conn = SC_get_conn(stmt);
ci = &(conn->connInfo);
if (res = QR_Constructor(), !res) if (res = QR_Constructor(), !res)
{ {
...@@ -2272,6 +2322,9 @@ PGAPI_Statistics( ...@@ -2272,6 +2322,9 @@ PGAPI_Statistics(
SC_log_error(func, "", stmt); SC_log_error(func, "", stmt);
return SQL_ERROR; return SQL_ERROR;
} }
table_qualifier[0] = '\0';
if (conn->schema_support)
schema_strcat(table_qualifier, "%.*s", szTableOwner, cbTableOwner, szTableName, cbTableName);
/* /*
* we need to get a list of the field names first, so we can return * we need to get a list of the field names first, so we can return
...@@ -2295,8 +2348,8 @@ PGAPI_Statistics( ...@@ -2295,8 +2348,8 @@ PGAPI_Statistics(
/* /*
* table_name parameter cannot contain a string search pattern. * table_name parameter cannot contain a string search pattern.
*/ */
result = PGAPI_Columns(hcol_stmt, "", 0, "", 0, result = PGAPI_Columns(hcol_stmt, "", 0, table_qualifier, SQL_NTS,
table_name, (SWORD) strlen(table_name), "", 0, PODBC_NOT_SEARCH_PATTERN); table_name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN);
col_stmt->internal = FALSE; col_stmt->internal = FALSE;
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
...@@ -2308,7 +2361,7 @@ PGAPI_Statistics( ...@@ -2308,7 +2361,7 @@ PGAPI_Statistics(
goto SEEYA; goto SEEYA;
} }
result = PGAPI_BindCol(hcol_stmt, 4, SQL_C_CHAR, result = PGAPI_BindCol(hcol_stmt, 4, SQL_C_CHAR,
column_name, MAX_INFO_STRING, &column_name_len); column_name, sizeof(column_name), &column_name_len);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{ {
stmt->errormsg = col_stmt->errormsg; stmt->errormsg = col_stmt->errormsg;
...@@ -2359,16 +2412,32 @@ PGAPI_Statistics( ...@@ -2359,16 +2412,32 @@ PGAPI_Statistics(
} }
indx_stmt = (StatementClass *) hindx_stmt; indx_stmt = (StatementClass *) hindx_stmt;
sprintf(index_query, "select c.relname, i.indkey, i.indisunique" if (conn->schema_support)
sprintf(index_query, "select c.relname, i.indkey, i.indisunique"
", i.indisclustered, a.amname, c.relhasrules, n.nspname"
" from pg_index i, pg_class c, pg_class d, pg_am a, pg_namespace n"
" where d.relname = '%s'"
" and n.nspname = '%s'"
" and n.oid = d.relnamespace"
" and d.oid = i.indrelid"
" and i.indexrelid = c.oid"
" and c.relam = a.oid order by"
,table_name, table_qualifier);
else
sprintf(index_query, "select c.relname, i.indkey, i.indisunique"
", i.indisclustered, a.amname, c.relhasrules" ", i.indisclustered, a.amname, c.relhasrules"
" from pg_index i, pg_class c, pg_class d, pg_am a" " from pg_index i, pg_class c, pg_class d, pg_am a"
" where d.relname = '%s'" " where d.relname = '%s'"
" and d.oid = i.indrelid" " and d.oid = i.indrelid"
" and i.indexrelid = c.oid" " and i.indexrelid = c.oid"
" and c.relam = a.oid" " and c.relam = a.oid order by"
,table_name); ,table_name);
if (PG_VERSION_GT(SC_get_conn(stmt), 6.4)) if (PG_VERSION_GT(SC_get_conn(stmt), 6.4))
strcat(index_query, " order by i.indisprimary desc"); strcat(index_query, " i.indisprimary desc,");
if (conn->schema_support)
strcat(index_query, " i.indisunique, n.nspname, c.relname");
else
strcat(index_query, " i.indisunique, c.relname");
result = PGAPI_ExecDirect(hindx_stmt, index_query, strlen(index_query)); result = PGAPI_ExecDirect(hindx_stmt, index_query, strlen(index_query));
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
...@@ -2447,7 +2516,7 @@ PGAPI_Statistics( ...@@ -2447,7 +2516,7 @@ PGAPI_Statistics(
} }
result = PGAPI_BindCol(hindx_stmt, 6, SQL_C_CHAR, result = PGAPI_BindCol(hindx_stmt, 6, SQL_C_CHAR,
relhasrules, MAX_INFO_STRING, NULL); relhasrules, sizeof(relhasrules), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{ {
stmt->errormsg = indx_stmt->errormsg; stmt->errormsg = indx_stmt->errormsg;
...@@ -2465,7 +2534,7 @@ PGAPI_Statistics( ...@@ -2465,7 +2534,7 @@ PGAPI_Statistics(
/* no table qualifier */ /* no table qualifier */
set_tuplefield_string(&row->tuple[0], ""); set_tuplefield_string(&row->tuple[0], "");
/* don't set the table owner, else Access tries to use it */ /* don't set the table owner, else Access tries to use it */
set_tuplefield_string(&row->tuple[1], ""); set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_qualifier));
set_tuplefield_string(&row->tuple[2], table_name); set_tuplefield_string(&row->tuple[2], table_name);
/* non-unique index? */ /* non-unique index? */
...@@ -2509,7 +2578,7 @@ PGAPI_Statistics( ...@@ -2509,7 +2578,7 @@ PGAPI_Statistics(
/* no table qualifier */ /* no table qualifier */
set_tuplefield_string(&row->tuple[0], ""); set_tuplefield_string(&row->tuple[0], "");
/* don't set the table owner, else Access tries to use it */ /* don't set the table owner, else Access tries to use it */
set_tuplefield_string(&row->tuple[1], ""); set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_qualifier));
set_tuplefield_string(&row->tuple[2], table_name); set_tuplefield_string(&row->tuple[2], table_name);
/* non-unique index? */ /* non-unique index? */
...@@ -2654,13 +2723,13 @@ PGAPI_PrimaryKeys( ...@@ -2654,13 +2723,13 @@ PGAPI_PrimaryKeys(
char tables_query[INFO_INQUIRY_LEN]; char tables_query[INFO_INQUIRY_LEN];
char attname[MAX_INFO_STRING]; char attname[MAX_INFO_STRING];
SDWORD attname_len; SDWORD attname_len;
char pktab[MAX_TABLE_LEN + 1]; char pktab[MAX_TABLE_LEN + 1], pkscm[MAX_TABLE_LEN + 1];
Int2 result_cols; Int2 result_cols;
int qno, int qno,
qstart, qstart,
qend; qend;
mylog("%s: entering...stmt=%u\n", func, stmt); mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner);
if (!stmt) if (!stmt)
{ {
...@@ -2708,6 +2777,7 @@ PGAPI_PrimaryKeys( ...@@ -2708,6 +2777,7 @@ PGAPI_PrimaryKeys(
} }
tbl_stmt = (StatementClass *) htbl_stmt; tbl_stmt = (StatementClass *) htbl_stmt;
conn = SC_get_conn(stmt);
pktab[0] = '\0'; pktab[0] = '\0';
make_string(szTableName, cbTableName, pktab); make_string(szTableName, cbTableName, pktab);
if (pktab[0] == '\0') if (pktab[0] == '\0')
...@@ -2718,6 +2788,9 @@ PGAPI_PrimaryKeys( ...@@ -2718,6 +2788,9 @@ PGAPI_PrimaryKeys(
PGAPI_FreeStmt(htbl_stmt, SQL_DROP); PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR; return SQL_ERROR;
} }
pkscm[0] = '\0';
if (conn->schema_support)
schema_strcat(pkscm, "%.*s", szTableOwner, cbTableOwner, szTableName, cbTableName);
result = PGAPI_BindCol(htbl_stmt, 1, SQL_C_CHAR, result = PGAPI_BindCol(htbl_stmt, 1, SQL_C_CHAR,
attname, MAX_INFO_STRING, &attname_len); attname, MAX_INFO_STRING, &attname_len);
...@@ -2730,7 +2803,6 @@ PGAPI_PrimaryKeys( ...@@ -2730,7 +2803,6 @@ PGAPI_PrimaryKeys(
return SQL_ERROR; return SQL_ERROR;
} }
conn = SC_get_conn(stmt);
if (PG_VERSION_LE(conn, 6.4)) if (PG_VERSION_LE(conn, 6.4))
qstart = 2; qstart = 2;
else else
...@@ -2747,7 +2819,20 @@ PGAPI_PrimaryKeys( ...@@ -2747,7 +2819,20 @@ PGAPI_PrimaryKeys(
* possible index columns. Courtesy of Tom Lane - thomas * possible index columns. Courtesy of Tom Lane - thomas
* 2000-03-21 * 2000-03-21
*/ */
sprintf(tables_query, "select ta.attname, ia.attnum" if (conn->schema_support)
sprintf(tables_query, "select ta.attname, ia.attnum"
" from pg_attribute ta, pg_attribute ia, pg_class c, pg_index i, pg_namespace n"
" where c.relname = '%s'"
" AND n.nspname = '%s'"
" AND c.oid = i.indrelid"
" AND n.oid = c.relnamespace"
" AND i.indisprimary = 't'"
" AND ia.attrelid = i.indexrelid"
" AND ta.attrelid = i.indrelid"
" AND ta.attnum = i.indkey[ia.attnum-1]"
" order by ia.attnum", pktab, pkscm);
else
sprintf(tables_query, "select ta.attname, ia.attnum"
" from pg_attribute ta, pg_attribute ia, pg_class c, pg_index i" " from pg_attribute ta, pg_attribute ia, pg_class c, pg_index i"
" where c.relname = '%s'" " where c.relname = '%s'"
" AND c.oid = i.indrelid" " AND c.oid = i.indrelid"
...@@ -2762,7 +2847,19 @@ PGAPI_PrimaryKeys( ...@@ -2762,7 +2847,19 @@ PGAPI_PrimaryKeys(
/* /*
* Simplified query to search old fashoned primary key * Simplified query to search old fashoned primary key
*/ */
sprintf(tables_query, "select ta.attname, ia.attnum" if (conn->schema_support)
sprintf(tables_query, "select ta.attname, ia.attnum"
" from pg_attribute ta, pg_attribute ia, pg_class c, pg_index i, pg_namespace n"
" where c.relname = '%s_pkey'"
" AND n.nspname = '%s'"
" AND c.oid = i.indexrelid"
" AND n.oid = c.relnamespace"
" AND ia.attrelid = i.indexrelid"
" AND ta.attrelid = i.indrelid"
" AND ta.attnum = i.indkey[ia.attnum-1]"
" order by ia.attnum", pktab, pkscm);
else
sprintf(tables_query, "select ta.attname, ia.attnum"
" from pg_attribute ta, pg_attribute ia, pg_class c, pg_index i" " from pg_attribute ta, pg_attribute ia, pg_class c, pg_index i"
" where c.relname = '%s_pkey'" " where c.relname = '%s_pkey'"
" AND c.oid = i.indexrelid" " AND c.oid = i.indexrelid"
...@@ -2801,7 +2898,7 @@ PGAPI_PrimaryKeys( ...@@ -2801,7 +2898,7 @@ PGAPI_PrimaryKeys(
* valid according to the ODBC SQL grammar, but Postgres won't * valid according to the ODBC SQL grammar, but Postgres won't
* support it.) * support it.)
*/ */
set_tuplefield_string(&row->tuple[1], ""); set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(pkscm));
set_tuplefield_string(&row->tuple[2], pktab); set_tuplefield_string(&row->tuple[2], pktab);
set_tuplefield_string(&row->tuple[3], attname); set_tuplefield_string(&row->tuple[3], attname);
set_tuplefield_int2(&row->tuple[4], (Int2) (++seq)); set_tuplefield_int2(&row->tuple[4], (Int2) (++seq));
...@@ -2859,7 +2956,7 @@ isMultibyte(const unsigned char *str) ...@@ -2859,7 +2956,7 @@ isMultibyte(const unsigned char *str)
return FALSE; return FALSE;
} }
static char * static char *
getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloced) getClientTableName(ConnectionClass *conn, const char *serverSchemaName, char *serverTableName, BOOL *nameAlloced)
{ {
char query[1024], char query[1024],
saveoid[24], saveoid[24],
...@@ -2886,7 +2983,10 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc ...@@ -2886,7 +2983,10 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc
bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL); bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
if (!bError && continueExec) if (!bError && continueExec)
{ {
sprintf(query, "select OID from pg_class where relname = '%s'", serverTableName); if (conn->schema_support)
sprintf(query, "select OID from pg_class where relname = '%s' and pg_namespace.oid = relnamespace and pg_namespace.nspname = '%s'", serverTableName, serverSchemaName);
else
sprintf(query, "select OID from pg_class where relname = '%s'", serverTableName);
if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res) if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
{ {
if (QR_get_num_tuples(res) > 0) if (QR_get_num_tuples(res) > 0)
...@@ -2922,7 +3022,7 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc ...@@ -2922,7 +3022,7 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc
return ret; return ret;
} }
static char * static char *
getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *serverColumnName, BOOL *nameAlloced) getClientColumnName(ConnectionClass *conn, const char * serverSchemaName, const char *serverTableName, char *serverColumnName, BOOL *nameAlloced)
{ {
char query[1024], char query[1024],
saveattrelid[24], saveattrelid[24],
...@@ -2950,7 +3050,12 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se ...@@ -2950,7 +3050,12 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se
bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL); bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
if (!bError && continueExec) if (!bError && continueExec)
{ {
sprintf(query, "select attrelid, attnum from pg_class, pg_attribute " if (conn->schema_support)
sprintf(query, "select attrelid, attnum from pg_class, pg_attribute "
"where relname = '%s' and attrelid = pg_class.oid "
"and attname = '%s' and pg_namespace.oid = relnamespace and pg_namespace.nspname = '%s'", serverTableName, serverColumnName, serverSchemaName);
else
sprintf(query, "select attrelid, attnum from pg_class, pg_attribute "
"where relname = '%s' and attrelid = pg_class.oid " "where relname = '%s' and attrelid = pg_class.oid "
"and attname = '%s'", serverTableName, serverColumnName); "and attname = '%s'", serverTableName, serverColumnName);
if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res) if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
...@@ -3025,6 +3130,7 @@ PGAPI_ForeignKeys( ...@@ -3025,6 +3130,7 @@ PGAPI_ForeignKeys(
del_rule[MAX_TABLE_LEN]; del_rule[MAX_TABLE_LEN];
char pk_table_needed[MAX_TABLE_LEN + 1]; char pk_table_needed[MAX_TABLE_LEN + 1];
char fk_table_needed[MAX_TABLE_LEN + 1]; char fk_table_needed[MAX_TABLE_LEN + 1];
char schema_needed[MAX_TABLE_LEN + 1];
char *pkey_ptr, char *pkey_ptr,
*pkey_text, *pkey_text,
*fkey_ptr, *fkey_ptr,
...@@ -3034,12 +3140,12 @@ PGAPI_ForeignKeys( ...@@ -3034,12 +3140,12 @@ PGAPI_ForeignKeys(
*fk_table, *fk_table,
*fkt_text; *fkt_text;
ConnectionClass *conn;
#ifdef MULTIBYTE #ifdef MULTIBYTE
BOOL pkey_alloced, BOOL pkey_alloced,
fkey_alloced, fkey_alloced,
pkt_alloced, pkt_alloced,
fkt_alloced; fkt_alloced;
ConnectionClass *conn;
#endif /* MULTIBYTE */ #endif /* MULTIBYTE */
int i, int i,
j, j,
...@@ -3081,7 +3187,11 @@ PGAPI_ForeignKeys( ...@@ -3081,7 +3187,11 @@ PGAPI_ForeignKeys(
* a statement is actually executed, so we'll have to do this * a statement is actually executed, so we'll have to do this
* ourselves. * ourselves.
*/ */
#if (ODBCVER >= 0x0300)
result_cols = 15;
#else
result_cols = 14; result_cols = 14;
#endif /* ODBCVER */
extend_column_bindings(SC_get_ARD(stmt), result_cols); extend_column_bindings(SC_get_ARD(stmt), result_cols);
/* set the field names */ /* set the field names */
...@@ -3129,14 +3239,15 @@ PGAPI_ForeignKeys( ...@@ -3129,14 +3239,15 @@ PGAPI_ForeignKeys(
pk_table_needed[0] = '\0'; pk_table_needed[0] = '\0';
fk_table_needed[0] = '\0'; fk_table_needed[0] = '\0';
schema_needed[0] = '\0';
make_string(szPkTableName, cbPkTableName, pk_table_needed); make_string(szPkTableName, cbPkTableName, pk_table_needed);
make_string(szFkTableName, cbFkTableName, fk_table_needed); make_string(szFkTableName, cbFkTableName, fk_table_needed);
conn = SC_get_conn(stmt);
#ifdef MULTIBYTE #ifdef MULTIBYTE
pkey_text = fkey_text = pkt_text = fkt_text = NULL; pkey_text = fkey_text = pkt_text = fkt_text = NULL;
pkey_alloced = fkey_alloced = pkt_alloced = fkt_alloced = FALSE; pkey_alloced = fkey_alloced = pkt_alloced = fkt_alloced = FALSE;
conn = SC_get_conn(stmt);
#endif /* MULTIBYTE */ #endif /* MULTIBYTE */
/* /*
...@@ -3146,7 +3257,42 @@ PGAPI_ForeignKeys( ...@@ -3146,7 +3257,42 @@ PGAPI_ForeignKeys(
if (fk_table_needed[0] != '\0') if (fk_table_needed[0] != '\0')
{ {
mylog("%s: entering Foreign Key Case #2", func); mylog("%s: entering Foreign Key Case #2", func);
sprintf(tables_query, "SELECT pt.tgargs, " if (conn->schema_support)
{
schema_strcat(schema_needed, "%.*s", szFkTableOwner, cbFkTableOwner, szFkTableName, cbFkTableName);
sprintf(tables_query, "SELECT pt.tgargs, "
" pt.tgnargs, "
" pt.tgdeferrable, "
" pt.tginitdeferred, "
" pg_proc.proname, "
" pg_proc_1.proname "
"FROM pg_class pc, "
" pg_proc pg_proc, "
" pg_proc pg_proc_1, "
" pg_trigger pg_trigger, "
" pg_trigger pg_trigger_1, "
" pg_proc pp, "
" pg_trigger pt "
"WHERE pt.tgrelid = pc.oid "
"AND pp.oid = pt.tgfoid "
"AND pg_trigger.tgconstrrelid = pc.oid "
"AND pg_proc.oid = pg_trigger.tgfoid "
"AND pg_trigger_1.tgfoid = pg_proc_1.oid "
"AND pg_trigger_1.tgconstrrelid = pc.oid "
"AND ((pc.relname='%s') "
"AND (pg_namespace.oid = pc.relnamespace) "
"AND (pg_namespace.nspname = '%s') "
"AND (pp.proname LIKE '%%ins') "
"AND (pg_proc.proname LIKE '%%upd') "
"AND (pg_proc_1.proname LIKE '%%del') "
"AND (pg_trigger.tgrelid=pt.tgconstrrelid) "
"AND (pg_trigger.tgconstrname=pt.tgconstrname) "
"AND (pg_trigger_1.tgrelid=pt.tgconstrrelid) "
"AND (pg_trigger_1.tgconstrname=pt.tgconstrname))",
fk_table_needed, schema_needed);
}
else
sprintf(tables_query, "SELECT pt.tgargs, "
" pt.tgnargs, " " pt.tgnargs, "
" pt.tgdeferrable, " " pt.tgdeferrable, "
" pt.tginitdeferred, " " pt.tginitdeferred, "
...@@ -3300,7 +3446,7 @@ PGAPI_ForeignKeys( ...@@ -3300,7 +3446,7 @@ PGAPI_ForeignKeys(
#ifdef MULTIBYTE #ifdef MULTIBYTE
fk_table = trig_args + strlen(trig_args) + 1; fk_table = trig_args + strlen(trig_args) + 1;
pkt_text = getClientTableName(conn, pk_table, &pkt_alloced); pkt_text = getClientTableName(conn, schema_needed, pk_table, &pkt_alloced);
#else #else
pkt_text = pk_table; pkt_text = pk_table;
#endif /* MULTIBYTE */ #endif /* MULTIBYTE */
...@@ -3315,7 +3461,7 @@ PGAPI_ForeignKeys( ...@@ -3315,7 +3461,7 @@ PGAPI_ForeignKeys(
} }
} }
keyresult = PGAPI_PrimaryKeys(hpkey_stmt, NULL, 0, NULL, 0, pkt_text, SQL_NTS); keyresult = PGAPI_PrimaryKeys(hpkey_stmt, NULL, 0, schema_needed, SQL_NTS, pkt_text, SQL_NTS);
if (keyresult != SQL_SUCCESS) if (keyresult != SQL_SUCCESS)
{ {
stmt->errornumber = STMT_NO_MEMORY_ERROR; stmt->errornumber = STMT_NO_MEMORY_ERROR;
...@@ -3341,7 +3487,7 @@ PGAPI_ForeignKeys( ...@@ -3341,7 +3487,7 @@ PGAPI_ForeignKeys(
break; break;
} }
#ifdef MULTIBYTE #ifdef MULTIBYTE
pkey_text = getClientColumnName(conn, pk_table, pkey_ptr, &pkey_alloced); pkey_text = getClientColumnName(conn, schema_needed, pk_table, pkey_ptr, &pkey_alloced);
#else #else
pkey_text = pkey_ptr; pkey_text = pkey_ptr;
#endif /* MULTIBYTE */ #endif /* MULTIBYTE */
...@@ -3409,21 +3555,21 @@ PGAPI_ForeignKeys( ...@@ -3409,21 +3555,21 @@ PGAPI_ForeignKeys(
row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField)); row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
#ifdef MULTIBYTE #ifdef MULTIBYTE
pkey_text = getClientColumnName(conn, pk_table, pkey_ptr, &pkey_alloced); pkey_text = getClientColumnName(conn, schema_needed, pk_table, pkey_ptr, &pkey_alloced);
fkey_text = getClientColumnName(conn, fk_table, fkey_ptr, &fkey_alloced); fkey_text = getClientColumnName(conn, schema_needed, fk_table, fkey_ptr, &fkey_alloced);
#else #else
pkey_text = pkey_ptr; pkey_text = pkey_ptr;
fkey_text = fkey_ptr; fkey_text = fkey_ptr;
#endif /* MULTIBYTE */ #endif /* MULTIBYTE */
mylog("%s: pk_table = '%s', pkey_ptr = '%s'\n", func, pkt_text, pkey_text); mylog("%s: pk_table = '%s', pkey_ptr = '%s'\n", func, pkt_text, pkey_text);
set_tuplefield_null(&row->tuple[0]); set_tuplefield_null(&row->tuple[0]);
set_tuplefield_string(&row->tuple[1], ""); set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(schema_needed));
set_tuplefield_string(&row->tuple[2], pkt_text); set_tuplefield_string(&row->tuple[2], pkt_text);
set_tuplefield_string(&row->tuple[3], pkey_text); set_tuplefield_string(&row->tuple[3], pkey_text);
mylog("%s: fk_table_needed = '%s', fkey_ptr = '%s'\n", func, fk_table_needed, fkey_text); mylog("%s: fk_table_needed = '%s', fkey_ptr = '%s'\n", func, fk_table_needed, fkey_text);
set_tuplefield_null(&row->tuple[4]); set_tuplefield_null(&row->tuple[4]);
set_tuplefield_string(&row->tuple[5], ""); set_tuplefield_string(&row->tuple[5], GET_SCHEMA_NAME(schema_needed));
set_tuplefield_string(&row->tuple[6], fk_table_needed); set_tuplefield_string(&row->tuple[6], fk_table_needed);
set_tuplefield_string(&row->tuple[7], fkey_text); set_tuplefield_string(&row->tuple[7], fkey_text);
...@@ -3472,7 +3618,43 @@ PGAPI_ForeignKeys( ...@@ -3472,7 +3618,43 @@ PGAPI_ForeignKeys(
*/ */
else if (pk_table_needed[0] != '\0') else if (pk_table_needed[0] != '\0')
{ {
sprintf(tables_query, "SELECT pg_trigger.tgargs, " if (conn->schema_support)
{
schema_strcat(schema_needed, "%.*s", szPkTableOwner, cbPkTableOwner, szPkTableName, cbPkTableName);
sprintf(tables_query, "SELECT pg_trigger.tgargs, "
" pg_trigger.tgnargs, "
" pg_trigger.tgdeferrable, "
" pg_trigger.tginitdeferred, "
" pg_proc.proname, "
" pg_proc_1.proname "
"FROM pg_class pg_class, "
" pg_class pg_class_1, "
" pg_class pg_class_2, "
" pg_proc pg_proc, "
" pg_proc pg_proc_1, "
" pg_trigger pg_trigger, "
" pg_trigger pg_trigger_1, "
" pg_trigger pg_trigger_2 "
"WHERE pg_trigger.tgconstrrelid = pg_class.oid "
" AND pg_trigger.tgrelid = pg_class_1.oid "
" AND pg_trigger_1.tgfoid = pg_proc_1.oid "
" AND pg_trigger_1.tgconstrrelid = pg_class_1.oid "
" AND pg_trigger_2.tgconstrrelid = pg_class_2.oid "
" AND pg_trigger_2.tgfoid = pg_proc.oid "
" AND pg_class_2.oid = pg_trigger.tgrelid "
" AND ("
" (pg_class.relname='%s') "
" AND (pg_namespace.oid = pg_class.relnamespace) "
" AND (pg_namespace.nspname = '%s') "
" AND (pg_proc.proname Like '%%upd') "
" AND (pg_proc_1.proname Like '%%del')"
" AND (pg_trigger_1.tgrelid = pg_trigger.tgconstrrelid) "
" AND (pg_trigger_2.tgrelid = pg_trigger.tgconstrrelid) "
" )",
pk_table_needed, schema_needed);
}
else
sprintf(tables_query, "SELECT pg_trigger.tgargs, "
" pg_trigger.tgnargs, " " pg_trigger.tgnargs, "
" pg_trigger.tgdeferrable, " " pg_trigger.tgdeferrable, "
" pg_trigger.tginitdeferred, " " pg_trigger.tginitdeferred, "
...@@ -3641,7 +3823,7 @@ PGAPI_ForeignKeys( ...@@ -3641,7 +3823,7 @@ PGAPI_ForeignKeys(
fk_table += strlen(fk_table) + 1; fk_table += strlen(fk_table) + 1;
#ifdef MULTIBYTE #ifdef MULTIBYTE
pk_table = fk_table + strlen(fk_table) + 1; pk_table = fk_table + strlen(fk_table) + 1;
fkt_text = getClientTableName(conn, fk_table, &fkt_alloced); fkt_text = getClientTableName(conn, schema_needed, fk_table, &fkt_alloced);
#else #else
fkt_text = fk_table; fkt_text = fk_table;
#endif /* MULTIBYTE */ #endif /* MULTIBYTE */
...@@ -3654,8 +3836,8 @@ PGAPI_ForeignKeys( ...@@ -3654,8 +3836,8 @@ PGAPI_ForeignKeys(
for (k = 0; k < num_keys; k++) for (k = 0; k < num_keys; k++)
{ {
#ifdef MULTIBYTE #ifdef MULTIBYTE
pkey_text = getClientColumnName(conn, pk_table, pkey_ptr, &pkey_alloced); pkey_text = getClientColumnName(conn, schema_needed, pk_table, pkey_ptr, &pkey_alloced);
fkey_text = getClientColumnName(conn, fk_table, fkey_ptr, &fkey_alloced); fkey_text = getClientColumnName(conn, schema_needed, fk_table, fkey_ptr, &fkey_alloced);
#else #else
pkey_text = pkey_ptr; pkey_text = pkey_ptr;
fkey_text = fkey_ptr; fkey_text = fkey_ptr;
...@@ -3666,13 +3848,13 @@ PGAPI_ForeignKeys( ...@@ -3666,13 +3848,13 @@ PGAPI_ForeignKeys(
mylog("pk_table_needed = '%s', pkey_ptr = '%s'\n", pk_table_needed, pkey_text); mylog("pk_table_needed = '%s', pkey_ptr = '%s'\n", pk_table_needed, pkey_text);
set_tuplefield_null(&row->tuple[0]); set_tuplefield_null(&row->tuple[0]);
set_tuplefield_string(&row->tuple[1], ""); set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(schema_needed));
set_tuplefield_string(&row->tuple[2], pk_table_needed); set_tuplefield_string(&row->tuple[2], pk_table_needed);
set_tuplefield_string(&row->tuple[3], pkey_text); set_tuplefield_string(&row->tuple[3], pkey_text);
mylog("fk_table = '%s', fkey_ptr = '%s'\n", fkt_text, fkey_text); mylog("fk_table = '%s', fkey_ptr = '%s'\n", fkt_text, fkey_text);
set_tuplefield_null(&row->tuple[4]); set_tuplefield_null(&row->tuple[4]);
set_tuplefield_string(&row->tuple[5], ""); set_tuplefield_string(&row->tuple[5], GET_SCHEMA_NAME(schema_needed));
set_tuplefield_string(&row->tuple[6], fkt_text); set_tuplefield_string(&row->tuple[6], fkt_text);
set_tuplefield_string(&row->tuple[7], fkey_text); set_tuplefield_string(&row->tuple[7], fkey_text);
...@@ -3688,7 +3870,7 @@ PGAPI_ForeignKeys( ...@@ -3688,7 +3870,7 @@ PGAPI_ForeignKeys(
set_tuplefield_string(&row->tuple[13], trig_args); set_tuplefield_string(&row->tuple[13], trig_args);
#if (ODBCVER >= 0x0300) #if (ODBCVER >= 0x0300)
mylog("defer_type = '%s'", defer_type); mylog(" defer_type = %d\n", defer_type);
set_tuplefield_int2(&row->tuple[14], defer_type); set_tuplefield_int2(&row->tuple[14], defer_type);
#endif /* ODBCVER >= 0x0300 */ #endif /* ODBCVER >= 0x0300 */
...@@ -3783,7 +3965,7 @@ PGAPI_Procedures( ...@@ -3783,7 +3965,7 @@ PGAPI_Procedures(
char proc_query[INFO_INQUIRY_LEN]; char proc_query[INFO_INQUIRY_LEN];
QResultClass *res; QResultClass *res;
mylog("%s: entering...\n", func); mylog("%s: entering... scnm=%x len=%d\n", func, szProcOwner, cbProcOwner);
if (PG_VERSION_LT(conn, 6.5)) if (PG_VERSION_LT(conn, 6.5))
{ {
...@@ -3798,12 +3980,26 @@ PGAPI_Procedures( ...@@ -3798,12 +3980,26 @@ PGAPI_Procedures(
/* /*
* The following seems the simplest implementation * The following seems the simplest implementation
*/ */
strcpy(proc_query, "select '' as " "PROCEDURE_CAT" ", '' as " "PROCEDURE_SCHEM" "," if (conn->schema_support)
strcpy(proc_query, "select '' as " "PROCEDURE_CAT" ", case when nspname = 'PUBLIC' then ''::text else nspname end as " "PROCEDURE_SCHEM" ","
" proname as " "PROCEDURE_NAME" ", '' as " "NUM_INPUT_PARAMS" "," " proname as " "PROCEDURE_NAME" ", '' as " "NUM_INPUT_PARAMS" ","
" '' as " "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" "," " '' as " "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
" '' as " "REMARKS" "," " '' as " "REMARKS" ","
" case when prorettype = 0 then 1::int2 else 2::int2 end as " "PROCEDURE_TYPE" " from pg_proc"); " case when prorettype = 0 then 1::int2 else 2::int2 end as " "PROCEDURE_TYPE" " from pg_namespace, pg_proc where");
my_strcat(proc_query, " where proname like '%.*s'", szProcName, cbProcName); else
strcpy(proc_query, "select '' as " "PROCEDURE_CAT" ", '' as " "PROCEDURE_SCHEM" ","
" proname as " "PROCEDURE_NAME" ", '' as " "NUM_INPUT_PARAMS" ","
" '' as " "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
" '' as " "REMARKS" ","
" case when prorettype = 0 then 1::int2 else 2::int2 end as " "PROCEDURE_TYPE" " from pg_proc where");
if (conn->schema_support)
{
strcat(proc_query, " pg_proc.namespace = pg_namespace.oid");
schema_strcat(proc_query, " and nspname like '%.*s'", szProcOwner, cbProcOwner, szProcName, cbProcName);
my_strcat(proc_query, " and proname like '%.*s'", szProcName, cbProcName);
}
else
my_strcat(proc_query, " proname like '%.*s'", szProcName, cbProcName);
if (res = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !res) if (res = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !res)
{ {
...@@ -3895,9 +4091,9 @@ PGAPI_TablePrivileges( ...@@ -3895,9 +4091,9 @@ PGAPI_TablePrivileges(
int tablecount, usercount, i, j, k; int tablecount, usercount, i, j, k;
BOOL grpauth, sys, su; BOOL grpauth, sys, su;
char (*useracl)[ACLMAX], *acl, *user, *delim, *auth; char (*useracl)[ACLMAX], *acl, *user, *delim, *auth;
char *reln, *owner, *priv; char *reln, *owner, *priv, *schnm;
mylog("%s: entering...\n", func); mylog("%s: entering... scnm=%x len-%d\n", func, szTableOwner, cbTableOwner);
if (!SC_recycle_statement(stmt)) if (!SC_recycle_statement(stmt))
return SQL_ERROR; return SQL_ERROR;
...@@ -3930,17 +4126,33 @@ PGAPI_TablePrivileges( ...@@ -3930,17 +4126,33 @@ PGAPI_TablePrivileges(
stmt->currTuple = -1; stmt->currTuple = -1;
stmt->rowset_start = -1; stmt->rowset_start = -1;
stmt->current_col = -1; stmt->current_col = -1;
strncpy_null(proc_query, "select relname, usename, relacl from pg_class , pg_user where", sizeof(proc_query)); if (conn->schema_support)
if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0) strncpy_null(proc_query, "select relname, usename, relacl, nspname from pg_namespace, pg_class , pg_user where", sizeof(proc_query));
else
strncpy_null(proc_query, "select relname, usename, relacl from pg_class , pg_user where", sizeof(proc_query));
if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0)
{
if (conn->schema_support)
{
schema_strcat(proc_query, " nspname = '%.*s' and", szTableOwner, cbTableOwner, szTableName, cbTableName);
}
my_strcat(proc_query, " relname = '%.*s' and", szTableName, cbTableName); my_strcat(proc_query, " relname = '%.*s' and", szTableName, cbTableName);
}
else else
{ {
char esc_table_name[MAX_TABLE_LEN * 2]; char esc_table_name[MAX_TABLE_LEN * 2];
int escTbnamelen; int escTbnamelen;
if (conn->schema_support)
{
escTbnamelen = reallyEscapeCatalogEscapes(szTableOwner, cbTableOwner, esc_table_name, sizeof(esc_table_name), conn->ccsc);
schema_strcat(proc_query, " nspname like '%.*s' and", esc_table_name, escTbnamelen, szTableName, cbTableName);
}
escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name), conn->ccsc); escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name), conn->ccsc);
my_strcat(proc_query, " relname like '%.*s' and", esc_table_name, escTbnamelen); my_strcat(proc_query, " relname like '%.*s' and", esc_table_name, escTbnamelen);
} }
if (conn->schema_support)
strcat(proc_query, " pg_namespace.oid = relnamespace and");
strcat(proc_query, " pg_user.usesysid = relowner"); strcat(proc_query, " pg_user.usesysid = relowner");
if (res = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !res) if (res = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !res)
{ {
...@@ -4029,6 +4241,8 @@ mylog("guid=%s\n", uid); ...@@ -4029,6 +4241,8 @@ mylog("guid=%s\n", uid);
} }
reln = QR_get_value_backend_row(res, i, 0); reln = QR_get_value_backend_row(res, i, 0);
owner = QR_get_value_backend_row(res, i, 1); owner = QR_get_value_backend_row(res, i, 1);
if (conn->schema_support)
schnm = QR_get_value_backend_row(res, i, 3);
/* The owner has all privileges */ /* The owner has all privileges */
useracl_upd(useracl, allures, owner, ALL_PRIVILIGES); useracl_upd(useracl, allures, owner, ALL_PRIVILIGES);
for (j = 0; j < usercount; j++) for (j = 0; j < usercount; j++)
...@@ -4051,7 +4265,10 @@ mylog("guid=%s\n", uid); ...@@ -4051,7 +4265,10 @@ mylog("guid=%s\n", uid);
} }
row = (TupleNode *) malloc(sizeof(TupleNode) + (7 - 1) *sizeof(TupleField)); row = (TupleNode *) malloc(sizeof(TupleNode) + (7 - 1) *sizeof(TupleField));
set_tuplefield_string(&row->tuple[0], ""); set_tuplefield_string(&row->tuple[0], "");
set_tuplefield_string(&row->tuple[1], ""); if (conn->schema_support)
set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(schnm));
else
set_tuplefield_string(&row->tuple[1], "");
set_tuplefield_string(&row->tuple[2], reln); set_tuplefield_string(&row->tuple[2], reln);
if (su || sys) if (su || sys)
set_tuplefield_string(&row->tuple[3], "_SYSTEM"); set_tuplefield_string(&row->tuple[3], "_SYSTEM");
......
...@@ -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,14 +724,14 @@ parse_statement(StatementClass *stmt) ...@@ -702,14 +724,14 @@ 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; if (delim == ',')
if (delim == ',') {
{ out_table = TRUE;
out_table = TRUE; 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