From: Hiroshi Inoue Date: Tue, 2 Apr 2002 10:50:50 +0000 (+0000) Subject: [HACKERS] Proposed patch for ODBC driver w/ C-a-n-c-e-l X-Git-Tag: REL9_0_0~18075 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=f8da3990b5437e47b7296a6770a3efd215b326d0;p=pg-rex%2Fsyncrep.git [HACKERS] Proposed patch for ODBC driver w/ C-a-n-c-e-l From: Bradley McLean 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 ... --- diff --git a/src/interfaces/odbc/connection.c b/src/interfaces/odbc/connection.c index d6b622a16d..7cee671e2b 100644 --- a/src/interfaces/odbc/connection.c +++ b/src/interfaces/odbc/connection.c @@ -19,6 +19,9 @@ #include #include #include +#ifndef WIN32 +#include +#endif /* WIN32 */ #include "environ.h" #include "socket.h" @@ -289,6 +292,7 @@ CC_Constructor() rv->ms_jet = 0; rv->unicode = 0; rv->result_uncommitted = 0; + rv->schema_support = 0; #ifdef MULTIBYTE rv->client_encoding = NULL; rv->server_encoding = NULL; @@ -882,8 +886,8 @@ another_version_retry: } break; case 'K': /* Secret key (6.4 protocol) */ - (void) SOCK_get_int(sock, 4); /* pid */ - (void) SOCK_get_int(sock, 4); /* key */ + self->be_pid = SOCK_get_int(sock, 4); /* pid */ + self->be_key = SOCK_get_int(sock, 4); /* key */ break; case 'Z': /* Backend is ready for new query (6.4) */ @@ -1960,6 +1964,8 @@ CC_lookup_pg_version(ConnectionClass *self) self->pg_version_minor = minor; } 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("Extracted PostgreSQL version number: '%1.1f'\n", self->pg_version_number); @@ -2019,3 +2025,64 @@ CC_get_max_query_len(const ConnectionClass *conn) 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 + return TRUE; +} diff --git a/src/interfaces/odbc/connection.h b/src/interfaces/odbc/connection.h index 5d01dacd21..849350d14d 100644 --- a/src/interfaces/odbc/connection.h +++ b/src/interfaces/odbc/connection.h @@ -126,6 +126,21 @@ typedef struct _StartupPacket6_2 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) @@ -273,11 +288,14 @@ struct ConnectionClass_ char ms_jet; char unicode; char result_uncommitted; + char schema_support; #ifdef MULTIBYTE char *client_encoding; char *server_encoding; #endif /* MULTIBYTE */ 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); void CC_initialize_pg_version(ConnectionClass *conn); void CC_log_error(const char *func, const char *desc, 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_abort(ConnectionClass *conn, BOOL set_no_trans); void ProcessRollback(ConnectionClass *conn, BOOL undo); diff --git a/src/interfaces/odbc/descriptor.h b/src/interfaces/odbc/descriptor.h index 5186810b21..fe90a2cbd3 100644 --- a/src/interfaces/odbc/descriptor.h +++ b/src/interfaces/odbc/descriptor.h @@ -5,7 +5,7 @@ * * 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 @@ typedef struct { COL_INFO *col_info; /* cached SQLColumns info for this table */ + char schema[MAX_TABLE_LEN + 1]; char name[MAX_TABLE_LEN + 1]; char alias[MAX_TABLE_LEN + 1]; } TABLE_INFO; diff --git a/src/interfaces/odbc/execute.c b/src/interfaces/odbc/execute.c index 11893321f8..14ed086e83 100644 --- a/src/interfaces/odbc/execute.c +++ b/src/interfaces/odbc/execute.c @@ -573,6 +573,7 @@ PGAPI_Cancel( { static char *func = "PGAPI_Cancel"; StatementClass *stmt = (StatementClass *) hstmt; + ConnectionClass *conn; RETCODE result; ConnInfo *ci; @@ -589,7 +590,8 @@ PGAPI_Cancel( SC_log_error(func, "", NULL); 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 @@ -598,6 +600,11 @@ PGAPI_Cancel( 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 * state: Because of what seems like a bug in the Odbc driver * manager, SQLCancel does not act like a SQLFreeStmt(CLOSE), as diff --git a/src/interfaces/odbc/info.c b/src/interfaces/odbc/info.c index a2aba6cf1e..39fdce1f32 100644 --- a/src/interfaces/odbc/info.c +++ b/src/interfaces/odbc/info.c @@ -1169,7 +1169,7 @@ PGAPI_Tables( systable; 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) { @@ -1196,7 +1196,13 @@ PGAPI_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 */ strcpy(tables_query, "select relname, usename, relkind from pg_class, pg_user"); @@ -1208,7 +1214,10 @@ PGAPI_Tables( 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); /* Parse the extra systable prefix */ @@ -1278,8 +1287,10 @@ PGAPI_Tables( /* filter out large objects in older versions */ strcat(tables_query, " and relname !~ '^xinv[0-9]+'"); - strcat(tables_query, " and usesysid = relowner"); - strcat(tables_query, " order by relname"); + if (conn->schema_support) + 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)); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) @@ -1404,7 +1415,6 @@ PGAPI_Tables( row = (TupleNode *) malloc(sizeof(TupleNode) + (5 - 1) *sizeof(TupleField)); /*set_tuplefield_string(&row->tuple[0], "");*/ - /*set_tuplefield_string(&row->tuple[0], "cat0");*/ set_tuplefield_null(&row->tuple[0]); /* @@ -1418,8 +1428,11 @@ PGAPI_Tables( mylog("%s: table_name = '%s'\n", func, table_name); - /* set_tuplefield_string(&row->tuple[1], ""); */ - set_tuplefield_null(&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_null(&row->tuple[1]); 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[4], "");*/ @@ -1561,7 +1574,7 @@ PGAPI_Columns( 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) { @@ -1579,7 +1592,15 @@ PGAPI_Columns( * Create the query to find out the columns (Note: pre 6.3 did not * 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" " from pg_user u, pg_class c, pg_attribute a, pg_type t" " where u.usesysid = c.relowner" @@ -1589,7 +1610,10 @@ PGAPI_Columns( if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0) { 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); } else @@ -1599,7 +1623,10 @@ PGAPI_Columns( 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 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); } @@ -1607,7 +1634,10 @@ PGAPI_Columns( * give the output in the order the columns were defined when the * 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); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) @@ -1815,8 +1845,10 @@ PGAPI_Columns( set_tuplefield_string(&row->tuple[0], ""); /* see note in SQLTables() */ - /* set_tuplefield_string(&row->tuple[1], table_owner); */ - 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[3], "oid"); sqltype = pgtype_to_concise_type(stmt, the_type); @@ -1854,8 +1886,10 @@ PGAPI_Columns( set_tuplefield_string(&row->tuple[0], ""); /* see note in SQLTables() */ - /* set_tuplefield_string(&row->tuple[1], table_owner); */ - 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[3], field_name); sqltype = pgtype_to_concise_type(stmt, field_type); @@ -1980,7 +2014,10 @@ PGAPI_Columns( (result_cols - 1) *sizeof(TupleField)); 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[3], "xmin"); sqltype = pgtype_to_concise_type(stmt, the_type); @@ -2040,6 +2077,7 @@ PGAPI_SpecialColumns( static char *func = "PGAPI_SpecialColumns"; TupleNode *row; StatementClass *stmt = (StatementClass *) hstmt; + ConnectionClass *conn; QResultClass *res; ConnInfo *ci; HSTMT hcol_stmt; @@ -2048,28 +2086,37 @@ PGAPI_SpecialColumns( RETCODE result; 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) { SC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } - ci = &(SC_get_conn(stmt)->connInfo); + conn = SC_get_conn(stmt); + ci = &(conn->connInfo); stmt->manual_result = TRUE; /* * 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 " "u.usesysid = c.relowner"); /* TableName cannot contain a string search pattern */ my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName); /* 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); @@ -2188,11 +2235,12 @@ PGAPI_Statistics( { static char *func = "PGAPI_Statistics"; StatementClass *stmt = (StatementClass *) hstmt; + ConnectionClass *conn; QResultClass *res; char index_query[INFO_INQUIRY_LEN]; HSTMT hindx_stmt; RETCODE result; - char *table_name; + char *table_name, *schema_name = NULL; char index_name[MAX_INFO_STRING]; short fields_vector[16]; char isunique[10], @@ -2206,7 +2254,8 @@ PGAPI_Statistics( StatementClass *col_stmt, *indx_stmt; char column_name[MAX_INFO_STRING], - relhasrules[MAX_INFO_STRING]; + table_qualifier[MAX_INFO_STRING], + relhasrules[10]; char **column_names = 0; SQLINTEGER column_name_len; int total_columns = 0; @@ -2214,7 +2263,7 @@ PGAPI_Statistics( ConnInfo *ci; 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) { @@ -2225,7 +2274,8 @@ PGAPI_Statistics( stmt->manual_result = TRUE; stmt->errormsg_created = TRUE; - ci = &(SC_get_conn(stmt)->connInfo); + conn = SC_get_conn(stmt); + ci = &(conn->connInfo); if (res = QR_Constructor(), !res) { @@ -2272,6 +2322,9 @@ PGAPI_Statistics( SC_log_error(func, "", stmt); 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 @@ -2295,8 +2348,8 @@ PGAPI_Statistics( /* * table_name parameter cannot contain a string search pattern. */ - result = PGAPI_Columns(hcol_stmt, "", 0, "", 0, - table_name, (SWORD) strlen(table_name), "", 0, PODBC_NOT_SEARCH_PATTERN); + result = PGAPI_Columns(hcol_stmt, "", 0, table_qualifier, SQL_NTS, + table_name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN); col_stmt->internal = FALSE; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) @@ -2308,7 +2361,7 @@ PGAPI_Statistics( goto SEEYA; } 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)) { stmt->errormsg = col_stmt->errormsg; @@ -2359,16 +2412,32 @@ PGAPI_Statistics( } 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" " from pg_index i, pg_class c, pg_class d, pg_am a" " where d.relname = '%s'" " and d.oid = i.indrelid" " and i.indexrelid = c.oid" - " and c.relam = a.oid" + " and c.relam = a.oid order by" ,table_name); 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)); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) @@ -2447,7 +2516,7 @@ PGAPI_Statistics( } 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)) { stmt->errormsg = indx_stmt->errormsg; @@ -2465,7 +2534,7 @@ PGAPI_Statistics( /* no table qualifier */ set_tuplefield_string(&row->tuple[0], ""); /* 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); /* non-unique index? */ @@ -2509,7 +2578,7 @@ PGAPI_Statistics( /* no table qualifier */ set_tuplefield_string(&row->tuple[0], ""); /* 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); /* non-unique index? */ @@ -2654,13 +2723,13 @@ PGAPI_PrimaryKeys( char tables_query[INFO_INQUIRY_LEN]; char attname[MAX_INFO_STRING]; SDWORD attname_len; - char pktab[MAX_TABLE_LEN + 1]; + char pktab[MAX_TABLE_LEN + 1], pkscm[MAX_TABLE_LEN + 1]; Int2 result_cols; int qno, qstart, 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) { @@ -2708,6 +2777,7 @@ PGAPI_PrimaryKeys( } tbl_stmt = (StatementClass *) htbl_stmt; + conn = SC_get_conn(stmt); pktab[0] = '\0'; make_string(szTableName, cbTableName, pktab); if (pktab[0] == '\0') @@ -2718,6 +2788,9 @@ PGAPI_PrimaryKeys( PGAPI_FreeStmt(htbl_stmt, SQL_DROP); 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, attname, MAX_INFO_STRING, &attname_len); @@ -2730,7 +2803,6 @@ PGAPI_PrimaryKeys( return SQL_ERROR; } - conn = SC_get_conn(stmt); if (PG_VERSION_LE(conn, 6.4)) qstart = 2; else @@ -2747,7 +2819,20 @@ PGAPI_PrimaryKeys( * possible index columns. Courtesy of Tom Lane - thomas * 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" " where c.relname = '%s'" " AND c.oid = i.indrelid" @@ -2762,7 +2847,19 @@ PGAPI_PrimaryKeys( /* * 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" " where c.relname = '%s_pkey'" " AND c.oid = i.indexrelid" @@ -2801,7 +2898,7 @@ PGAPI_PrimaryKeys( * valid according to the ODBC SQL grammar, but Postgres won't * 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[3], attname); set_tuplefield_int2(&row->tuple[4], (Int2) (++seq)); @@ -2859,7 +2956,7 @@ isMultibyte(const unsigned char *str) return FALSE; } static char * -getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloced) +getClientTableName(ConnectionClass *conn, const char *serverSchemaName, char *serverTableName, BOOL *nameAlloced) { char query[1024], saveoid[24], @@ -2886,7 +2983,10 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL); 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 (QR_get_num_tuples(res) > 0) @@ -2922,7 +3022,7 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc return ret; } 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], saveattrelid[24], @@ -2950,7 +3050,12 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL); 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 " "and attname = '%s'", serverTableName, serverColumnName); if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res) @@ -3025,6 +3130,7 @@ PGAPI_ForeignKeys( del_rule[MAX_TABLE_LEN]; char pk_table_needed[MAX_TABLE_LEN + 1]; char fk_table_needed[MAX_TABLE_LEN + 1]; + char schema_needed[MAX_TABLE_LEN + 1]; char *pkey_ptr, *pkey_text, *fkey_ptr, @@ -3034,12 +3140,12 @@ PGAPI_ForeignKeys( *fk_table, *fkt_text; + ConnectionClass *conn; #ifdef MULTIBYTE BOOL pkey_alloced, fkey_alloced, pkt_alloced, fkt_alloced; - ConnectionClass *conn; #endif /* MULTIBYTE */ int i, j, @@ -3081,7 +3187,11 @@ PGAPI_ForeignKeys( * a statement is actually executed, so we'll have to do this * ourselves. */ +#if (ODBCVER >= 0x0300) + result_cols = 15; +#else result_cols = 14; +#endif /* ODBCVER */ extend_column_bindings(SC_get_ARD(stmt), result_cols); /* set the field names */ @@ -3129,14 +3239,15 @@ PGAPI_ForeignKeys( pk_table_needed[0] = '\0'; fk_table_needed[0] = '\0'; + schema_needed[0] = '\0'; make_string(szPkTableName, cbPkTableName, pk_table_needed); make_string(szFkTableName, cbFkTableName, fk_table_needed); + conn = SC_get_conn(stmt); #ifdef MULTIBYTE pkey_text = fkey_text = pkt_text = fkt_text = NULL; pkey_alloced = fkey_alloced = pkt_alloced = fkt_alloced = FALSE; - conn = SC_get_conn(stmt); #endif /* MULTIBYTE */ /* @@ -3146,7 +3257,42 @@ PGAPI_ForeignKeys( if (fk_table_needed[0] != '\0') { 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.tgdeferrable, " " pt.tginitdeferred, " @@ -3300,7 +3446,7 @@ PGAPI_ForeignKeys( #ifdef MULTIBYTE 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 pkt_text = pk_table; #endif /* MULTIBYTE */ @@ -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) { stmt->errornumber = STMT_NO_MEMORY_ERROR; @@ -3341,7 +3487,7 @@ PGAPI_ForeignKeys( break; } #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 pkey_text = pkey_ptr; #endif /* MULTIBYTE */ @@ -3409,21 +3555,21 @@ PGAPI_ForeignKeys( row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField)); #ifdef MULTIBYTE - pkey_text = getClientColumnName(conn, pk_table, pkey_ptr, &pkey_alloced); - fkey_text = getClientColumnName(conn, fk_table, fkey_ptr, &fkey_alloced); + pkey_text = getClientColumnName(conn, schema_needed, pk_table, pkey_ptr, &pkey_alloced); + fkey_text = getClientColumnName(conn, schema_needed, fk_table, fkey_ptr, &fkey_alloced); #else pkey_text = pkey_ptr; fkey_text = fkey_ptr; #endif /* MULTIBYTE */ mylog("%s: pk_table = '%s', pkey_ptr = '%s'\n", func, pkt_text, pkey_text); 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[3], pkey_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_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[7], fkey_text); @@ -3472,7 +3618,43 @@ PGAPI_ForeignKeys( */ 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.tgdeferrable, " " pg_trigger.tginitdeferred, " @@ -3641,7 +3823,7 @@ PGAPI_ForeignKeys( fk_table += strlen(fk_table) + 1; #ifdef MULTIBYTE 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 fkt_text = fk_table; #endif /* MULTIBYTE */ @@ -3654,8 +3836,8 @@ PGAPI_ForeignKeys( for (k = 0; k < num_keys; k++) { #ifdef MULTIBYTE - pkey_text = getClientColumnName(conn, pk_table, pkey_ptr, &pkey_alloced); - fkey_text = getClientColumnName(conn, fk_table, fkey_ptr, &fkey_alloced); + pkey_text = getClientColumnName(conn, schema_needed, pk_table, pkey_ptr, &pkey_alloced); + fkey_text = getClientColumnName(conn, schema_needed, fk_table, fkey_ptr, &fkey_alloced); #else pkey_text = pkey_ptr; fkey_text = fkey_ptr; @@ -3666,13 +3848,13 @@ PGAPI_ForeignKeys( mylog("pk_table_needed = '%s', pkey_ptr = '%s'\n", pk_table_needed, pkey_text); 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[3], pkey_text); mylog("fk_table = '%s', fkey_ptr = '%s'\n", fkt_text, fkey_text); 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[7], fkey_text); @@ -3688,7 +3870,7 @@ PGAPI_ForeignKeys( set_tuplefield_string(&row->tuple[13], trig_args); #if (ODBCVER >= 0x0300) - mylog("defer_type = '%s'", defer_type); + mylog(" defer_type = %d\n", defer_type); set_tuplefield_int2(&row->tuple[14], defer_type); #endif /* ODBCVER >= 0x0300 */ @@ -3783,7 +3965,7 @@ PGAPI_Procedures( char proc_query[INFO_INQUIRY_LEN]; 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)) { @@ -3798,12 +3980,26 @@ PGAPI_Procedures( /* * 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" "," " '' 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"); - my_strcat(proc_query, " where proname like '%.*s'", szProcName, cbProcName); + " case when prorettype = 0 then 1::int2 else 2::int2 end as " "PROCEDURE_TYPE" " from pg_namespace, pg_proc where"); + 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) { @@ -3895,9 +4091,9 @@ PGAPI_TablePrivileges( int tablecount, usercount, i, j, k; BOOL grpauth, sys, su; 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)) return SQL_ERROR; @@ -3930,17 +4126,33 @@ PGAPI_TablePrivileges( stmt->currTuple = -1; stmt->rowset_start = -1; stmt->current_col = -1; - 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) + 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); + } else { char esc_table_name[MAX_TABLE_LEN * 2]; 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); 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"); if (res = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !res) { @@ -4029,6 +4241,8 @@ mylog("guid=%s\n", uid); } reln = QR_get_value_backend_row(res, i, 0); 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 */ useracl_upd(useracl, allures, owner, ALL_PRIVILIGES); for (j = 0; j < usercount; j++) @@ -4051,7 +4265,10 @@ mylog("guid=%s\n", uid); } row = (TupleNode *) malloc(sizeof(TupleNode) + (7 - 1) *sizeof(TupleField)); 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); if (su || sys) set_tuplefield_string(&row->tuple[3], "_SYSTEM"); diff --git a/src/interfaces/odbc/info30.c b/src/interfaces/odbc/info30.c index c1c2c63d06..f92c2ab6ff 100644 --- a/src/interfaces/odbc/info30.c +++ b/src/interfaces/odbc/info30.c @@ -171,10 +171,10 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, break; case SQL_CREATE_SCHEMA: len = 4; - if (PG_VERSION_LE(conn, 7.2)) - value = 0; + if (conn->schema_support) + value = SQL_CS_CREATE_SCHEMA | SQL_CS_AUTHORIZATION; else - value = SQL_CS_CREATE_SCHEMA | SQL_CS_AUTHORIZATION; /* hopefully */ + value = 0; break; case SQL_CREATE_TABLE: len = 4; @@ -218,10 +218,10 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, break; case SQL_DROP_SCHEMA: len = 4; - if (PG_VERSION_LE(conn, 7.2)) - value = 0; + if (conn->schema_support) + value = SQL_DS_DROP_SCHEMA | SQL_DS_RESTRICT | SQL_DS_CASCADE; else - value = SQL_DS_DROP_SCHEMA | SQL_DS_RESTRICT | SQL_DS_CASCADE; /* hopefully */ + value = 0; break; case SQL_DROP_TABLE: len = 4; diff --git a/src/interfaces/odbc/misc.c b/src/interfaces/odbc/misc.c index a7bcaca8d9..df99994175 100644 --- a/src/interfaces/odbc/misc.c +++ b/src/interfaces/odbc/misc.c @@ -279,6 +279,18 @@ my_strcat(char *buf, const char *fmt, const char *s, int len) 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 remove_newlines(char *string) diff --git a/src/interfaces/odbc/misc.h b/src/interfaces/odbc/misc.h index cba7f2bfed..fe946eebfa 100644 --- a/src/interfaces/odbc/misc.h +++ b/src/interfaces/odbc/misc.h @@ -89,6 +89,9 @@ char *strncpy_null(char *dst, const char *src, int len); char *trim(char *string); char *make_string(const char *s, int len, char *buf); 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 */ #define STRCPY_SUCCESS 1 diff --git a/src/interfaces/odbc/parse.c b/src/interfaces/odbc/parse.c index d86e62f85b..cb77fddd83 100644 --- a/src/interfaces/odbc/parse.c +++ b/src/interfaces/odbc/parse.c @@ -543,15 +543,21 @@ parse_statement(StatementClass *stmt) */ if (in_dot) { - irdflds->nfields--; - strcpy(fi[irdflds->nfields]->dot, fi[irdflds->nfields]->name); - strcpy(fi[irdflds->nfields]->name, token); - irdflds->nfields++; - in_dot = FALSE; + int ifld = irdflds->nfields - 1; + + if (fi[ifld]->dot[0]) + { + 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 == ',') { mylog("in_dot: got comma\n"); + in_dot = FALSE; in_field = FALSE; } continue; @@ -575,6 +581,7 @@ parse_statement(StatementClass *stmt) /* Function */ if (token[0] == '(') { + in_dot = FALSE; in_func = TRUE; blevel = 1; fi[irdflds->nfields - 1]->func = TRUE; @@ -594,6 +601,7 @@ parse_statement(StatementClass *stmt) continue; } + in_dot = FALSE; if (!stricmp(token, "as")) { in_as = TRUE; @@ -644,6 +652,7 @@ parse_statement(StatementClass *stmt) return FALSE; } + ti[stmt->ntab]->schema[0] = '\0'; ti[stmt->ntab]->alias[0] = '\0'; strcpy(ti[stmt->ntab]->name, token); @@ -680,6 +689,7 @@ parse_statement(StatementClass *stmt) in_table = TRUE; } stmt->ntab++; + in_dot = FALSE; continue; } @@ -689,9 +699,21 @@ parse_statement(StatementClass *stmt) out_table = TRUE; 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 || stricmp(token, "RIGHT") == 0 || @@ -702,14 +724,14 @@ parse_statement(StatementClass *stmt) in_table = FALSE; continue; } - } - 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); - in_table = FALSE; - if (delim == ',') - { - out_table = TRUE; - mylog("more than 1 tables\n"); + 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); + in_table = FALSE; + if (delim == ',') + { + out_table = TRUE; + mylog("more than 1 tables\n"); + } } } } /* in_from */ @@ -823,8 +845,8 @@ parse_statement(StatementClass *stmt) col_stmt = (StatementClass *) hcol_stmt; col_stmt->internal = TRUE; - result = PGAPI_Columns(hcol_stmt, "", 0, "", 0, - ti[i]->name, (SWORD) strlen(ti[i]->name), "", 0, PODBC_NOT_SEARCH_PATTERN); + result = PGAPI_Columns(hcol_stmt, "", 0, ti[i]->schema, + SQL_NTS, ti[i]->name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN); mylog(" Past PG_Columns\n"); if (result == SQL_SUCCESS) diff --git a/src/interfaces/odbc/psqlodbc.h b/src/interfaces/odbc/psqlodbc.h index 839c6e4876..f9bb1581d9 100644 --- a/src/interfaces/odbc/psqlodbc.h +++ b/src/interfaces/odbc/psqlodbc.h @@ -5,7 +5,7 @@ * * 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 $ * */ diff --git a/src/interfaces/odbc/socket.c b/src/interfaces/odbc/socket.c index 031a6779cb..7f56359274 100644 --- a/src/interfaces/odbc/socket.c +++ b/src/interfaces/odbc/socket.c @@ -107,7 +107,6 @@ char SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname) { struct hostent *host; - struct sockaddr_in sadr; unsigned long iaddr; if (self->socket != -1) @@ -117,7 +116,7 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname) 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. @@ -132,13 +131,13 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname) self->errormsg = "Could not resolve hostname."; return 0; } - memcpy(&(sadr.sin_addr), host->h_addr, host->h_length); + memcpy(&(self->sadr.sin_addr), host->h_addr, host->h_length); } 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; - sadr.sin_port = htons(port); + 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,8 +147,8 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname) return 0; } - if (connect(self->socket, (struct sockaddr *) & (sadr), - sizeof(sadr)) < 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 --git a/src/interfaces/odbc/socket.h b/src/interfaces/odbc/socket.h index c49d9fe88d..2337eb9a08 100644 --- a/src/interfaces/odbc/socket.h +++ b/src/interfaces/odbc/socket.h @@ -61,6 +61,7 @@ struct SocketClass_ char *errormsg; int errornumber; + struct sockaddr_in sadr; /* Used for handling connections for cancel */ char reverse; /* used to handle Postgres 6.2 protocol * (reverse byte order) */