summaryrefslogtreecommitdiff
path: root/src/interfaces/odbc/info.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/odbc/info.c')
-rw-r--r--src/interfaces/odbc/info.c723
1 files changed, 471 insertions, 252 deletions
diff --git a/src/interfaces/odbc/info.c b/src/interfaces/odbc/info.c
index b87efbd33d5..ae6c6074f75 100644
--- a/src/interfaces/odbc/info.c
+++ b/src/interfaces/odbc/info.c
@@ -1,20 +1,20 @@
-
-/* Module: info.c
- *
- * Description: This module contains routines related to
- * ODBC informational functions.
- *
- * Classes: n/a
- *
- * API functions: SQLGetInfo, SQLGetTypeInfo, SQLGetFunctions,
- * SQLTables, SQLColumns, SQLStatistics, SQLSpecialColumns,
- * SQLPrimaryKeys, SQLForeignKeys,
- * SQLProcedureColumns(NI), SQLProcedures(NI),
- * SQLTablePrivileges(NI), SQLColumnPrivileges(NI)
- *
- * Comments: See "notice.txt" for copyright and license information.
- *
- */
+
+/* Module: info.c
+ *
+ * Description: This module contains routines related to
+ * ODBC informational functions.
+ *
+ * Classes: n/a
+ *
+ * API functions: SQLGetInfo, SQLGetTypeInfo, SQLGetFunctions,
+ * SQLTables, SQLColumns, SQLStatistics, SQLSpecialColumns,
+ * SQLPrimaryKeys, SQLForeignKeys,
+ * SQLProcedureColumns(NI), SQLProcedures(NI),
+ * SQLTablePrivileges(NI), SQLColumnPrivileges(NI)
+ *
+ * Comments: See "notice.txt" for copyright and license information.
+ *
+ */
#include <string.h>
#include <stdio.h>
@@ -33,6 +33,9 @@
#include "misc.h"
#include "pgtypes.h"
+
+extern GLOBAL_VALUES globals;
+
// - - - - - - - - -
RETCODE SQL_API SQLGetInfo(
@@ -192,7 +195,10 @@ char *p;
// this tag doesn't seem to be in ODBC 2.0, and it conflicts
// with a valid tag (SQL_TIMEDATE_ADD_INTERVALS).
- p = CC_get_database(conn);
+ /* Returning the database name causes problems in MS Query.
+ It generates query like: "SELECT DISTINCT a FROM byronncrap3 crap3"
+ */
+ p = ""; // CC_get_database(conn);
if (pcbInfoValue) *pcbInfoValue = strlen(p);
strncpy_null((char *)rgbInfoValue, p, (size_t)cbInfoValueMax);
break;
@@ -224,8 +230,6 @@ char *p;
break;
case SQL_DRIVER_ODBC_VER:
- /* I think we should return 02.00--at least, that is the version of the */
- /* spec I'm currently referring to. */
if (pcbInfoValue) *pcbInfoValue = 5;
strncpy_null((char *)rgbInfoValue, "02.00", (size_t)cbInfoValueMax);
break;
@@ -245,12 +249,11 @@ char *p;
case SQL_FETCH_DIRECTION: /* ODBC 1.0 */
// which fetch directions are supported? (bitmask)
- // I guess these apply to SQLExtendedFetch?
- *((DWORD *)rgbInfoValue) = SQL_FETCH_NEXT ||
- SQL_FETCH_FIRST ||
- SQL_FETCH_LAST ||
- SQL_FETCH_PRIOR ||
- SQL_FETCH_ABSOLUTE;
+ *((DWORD *)rgbInfoValue) = globals.use_declarefetch ? 0 : (SQL_FD_FETCH_NEXT |
+ SQL_FD_FETCH_FIRST |
+ SQL_FD_FETCH_LAST |
+ SQL_FD_FETCH_PRIOR |
+ SQL_FD_FETCH_ABSOLUTE);
if(pcbInfoValue) { *pcbInfoValue = 4; }
break;
@@ -326,7 +329,7 @@ char *p;
case SQL_MAX_COLUMN_NAME_LEN: /* ODBC 1.0 */
// maximum length of a column name
- *((WORD *)rgbInfoValue) = 0;
+ *((WORD *)rgbInfoValue) = 32;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break;
@@ -349,7 +352,6 @@ char *p;
break;
case SQL_MAX_COLUMNS_IN_SELECT: /* ODBC 2.0 */
- // I think you get the idea by now
*((WORD *)rgbInfoValue) = 0;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break;
@@ -360,7 +362,7 @@ char *p;
break;
case SQL_MAX_CURSOR_NAME_LEN: /* ODBC 1.0 */
- *((WORD *)rgbInfoValue) = 0;
+ *((WORD *)rgbInfoValue) = 32;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break;
@@ -395,7 +397,7 @@ char *p;
case SQL_MAX_ROW_SIZE_INCLUDES_LONG: /* ODBC 2.0 */
// does the preceding value include LONGVARCHAR and LONGVARBINARY
- // fields?
+ // fields? Well, it does include longvarchar, but not longvarbinary.
*pcbInfoValue = 1;
strncpy_null((char *)rgbInfoValue, "Y", (size_t)cbInfoValueMax);
break;
@@ -407,7 +409,7 @@ char *p;
break;
case SQL_MAX_TABLE_NAME_LEN: /* ODBC 1.0 */
- *((WORD *)rgbInfoValue) = 0;
+ *((WORD *)rgbInfoValue) = 32;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break;
@@ -424,7 +426,7 @@ char *p;
case SQL_MULT_RESULT_SETS: /* ODBC 1.0 */
// do we support multiple result sets?
if (pcbInfoValue) *pcbInfoValue = 1;
- strncpy_null((char *)rgbInfoValue, "Y", (size_t)cbInfoValueMax);
+ strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
break;
case SQL_MULTIPLE_ACTIVE_TXN: /* ODBC 1.0 */
@@ -434,7 +436,7 @@ char *p;
break;
case SQL_NEED_LONG_DATA_LEN: /* ODBC 2.0 */
- if (pcbInfoValue) *pcbInfoValue = 1;
+ if (pcbInfoValue) *pcbInfoValue = 1;
/* Dont need the length, SQLPutData can handle any size and multiple calls */
strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
break;
@@ -460,7 +462,7 @@ char *p;
break;
case SQL_ODBC_API_CONFORMANCE: /* ODBC 1.0 */
- *((WORD *)rgbInfoValue) = SQL_OAC_LEVEL1; /* well, almost */
+ *((WORD *)rgbInfoValue) = SQL_OAC_LEVEL1;
if(pcbInfoValue) { *pcbInfoValue = 2; }
break;
@@ -572,22 +574,23 @@ char *p;
break;
case SQL_ROW_UPDATES: /* ODBC 1.0 */
- // not quite sure what this means
+ // Driver doesn't support keyset-driven or mixed cursors, so
+ // not much point in saying row updates are supported
if (pcbInfoValue) *pcbInfoValue = 1;
- strncpy_null((char *)rgbInfoValue, "Y", (size_t)cbInfoValueMax);
+ strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
break;
case SQL_SCROLL_CONCURRENCY: /* ODBC 1.0 */
- // what concurrency options are supported? (bitmask)
- // taking a guess here
- *((DWORD *)rgbInfoValue) = SQL_SCCO_OPT_ROWVER;
+ // what concurrency options are supported BY THE CURSOR? (bitmask)
+ *((DWORD *)rgbInfoValue) = (SQL_SCCO_READ_ONLY);
if(pcbInfoValue) { *pcbInfoValue = 4; }
break;
case SQL_SCROLL_OPTIONS: /* ODBC 1.0 */
// what options are supported for scrollable cursors? (bitmask)
- // not too sure about this one, either...
- *((DWORD *)rgbInfoValue) = SQL_SO_KEYSET_DRIVEN;
+ // for declare/fetch, only FORWARD scrolling is allowed
+ // otherwise, the result set is STATIC (to SQLExtendedFetch for example)
+ *((DWORD *)rgbInfoValue) = globals.use_declarefetch ? SQL_SO_FORWARD_ONLY : (SQL_SO_FORWARD_ONLY | SQL_SO_STATIC);
if(pcbInfoValue) { *pcbInfoValue = 4; }
break;
@@ -623,8 +626,14 @@ char *p;
case SQL_STRING_FUNCTIONS: /* ODBC 1.0 */
// what string functions exist? (bitmask)
- // not sure if any of these exist, either
- *((DWORD *)rgbInfoValue) = 0;
+ *((DWORD *)rgbInfoValue) = (SQL_FN_STR_CONCAT |
+ SQL_FN_STR_LCASE |
+ SQL_FN_STR_LENGTH |
+ SQL_FN_STR_LOCATE |
+ SQL_FN_STR_LTRIM |
+ SQL_FN_STR_RTRIM |
+ SQL_FN_STR_SUBSTRING |
+ SQL_FN_STR_UCASE);
if(pcbInfoValue) { *pcbInfoValue = 4; }
break;
@@ -666,7 +675,7 @@ char *p;
case SQL_TIMEDATE_FUNCTIONS: /* ODBC 1.0 */
// what time and date functions are supported? (bitmask)
- *((DWORD *)rgbInfoValue) = 0;
+ *((DWORD *)rgbInfoValue) = (SQL_FN_TD_NOW);
if(pcbInfoValue) { *pcbInfoValue = 4; }
break;
@@ -751,30 +760,30 @@ Int4 type;
// cycle through the types
for(i=0, type = pgtypes_defined[0]; type; type = pgtypes_defined[++i]) {
- if(fSqlType == SQL_ALL_TYPES || fSqlType == pgtype_to_sqltype(type)) {
+ if(fSqlType == SQL_ALL_TYPES || fSqlType == pgtype_to_sqltype(stmt, type)) {
row = (TupleNode *)malloc(sizeof(TupleNode) + (15 - 1)*sizeof(TupleField));
/* These values can't be NULL */
- set_tuplefield_string(&row->tuple[0], pgtype_to_name(type));
- set_tuplefield_int2(&row->tuple[1], pgtype_to_sqltype(type));
- set_tuplefield_int2(&row->tuple[6], pgtype_nullable(type));
- set_tuplefield_int2(&row->tuple[7], pgtype_case_sensitive(type));
- set_tuplefield_int2(&row->tuple[8], pgtype_searchable(type));
- set_tuplefield_int2(&row->tuple[10], pgtype_money(type));
+ set_tuplefield_string(&row->tuple[0], pgtype_to_name(stmt, type));
+ set_tuplefield_int2(&row->tuple[1], pgtype_to_sqltype(stmt, type));
+ set_tuplefield_int2(&row->tuple[6], pgtype_nullable(stmt, type));
+ set_tuplefield_int2(&row->tuple[7], pgtype_case_sensitive(stmt, type));
+ set_tuplefield_int2(&row->tuple[8], pgtype_searchable(stmt, type));
+ set_tuplefield_int2(&row->tuple[10], pgtype_money(stmt, type));
/* Localized data-source dependent data type name (always NULL) */
set_tuplefield_null(&row->tuple[12]);
/* These values can be NULL */
- set_nullfield_int4(&row->tuple[2], pgtype_precision(type));
- set_nullfield_string(&row->tuple[3], pgtype_literal_prefix(type));
- set_nullfield_string(&row->tuple[4], pgtype_literal_suffix(type));
- set_nullfield_string(&row->tuple[5], pgtype_create_params(type));
- set_nullfield_int2(&row->tuple[9], pgtype_unsigned(type));
- set_nullfield_int2(&row->tuple[11], pgtype_auto_increment(type));
- set_nullfield_int2(&row->tuple[13], pgtype_scale(type));
- set_nullfield_int2(&row->tuple[14], pgtype_scale(type));
+ set_nullfield_int4(&row->tuple[2], pgtype_precision(stmt, type, PG_STATIC, PG_STATIC));
+ set_nullfield_string(&row->tuple[3], pgtype_literal_prefix(stmt, type));
+ set_nullfield_string(&row->tuple[4], pgtype_literal_suffix(stmt, type));
+ set_nullfield_string(&row->tuple[5], pgtype_create_params(stmt, type));
+ set_nullfield_int2(&row->tuple[9], pgtype_unsigned(stmt, type));
+ set_nullfield_int2(&row->tuple[11], pgtype_auto_increment(stmt, type));
+ set_nullfield_int2(&row->tuple[13], pgtype_scale(stmt, type));
+ set_nullfield_int2(&row->tuple[14], pgtype_scale(stmt, type));
QR_add_tuple(stmt->result, row);
}
@@ -782,6 +791,7 @@ Int4 type;
stmt->status = STMT_FINISHED;
stmt->currTuple = -1;
+ stmt->current_col = -1;
return SQL_SUCCESS;
}
@@ -826,12 +836,12 @@ RETCODE SQL_API SQLGetFunctions(
pfExists[SQL_API_SQLFREECONNECT] = TRUE;
pfExists[SQL_API_SQLFREEENV] = TRUE;
pfExists[SQL_API_SQLFREESTMT] = TRUE;
- pfExists[SQL_API_SQLGETCURSORNAME] = FALSE;
+ pfExists[SQL_API_SQLGETCURSORNAME] = TRUE;
pfExists[SQL_API_SQLNUMRESULTCOLS] = TRUE;
pfExists[SQL_API_SQLPREPARE] = TRUE; // complete?
pfExists[SQL_API_SQLROWCOUNT] = TRUE;
- pfExists[SQL_API_SQLSETCURSORNAME] = FALSE;
- pfExists[SQL_API_SQLSETPARAM] = FALSE;
+ pfExists[SQL_API_SQLSETCURSORNAME] = TRUE;
+ pfExists[SQL_API_SQLSETPARAM] = FALSE; // odbc 1.0
pfExists[SQL_API_SQLTRANSACT] = TRUE;
// ODBC level 1 functions
@@ -840,11 +850,9 @@ RETCODE SQL_API SQLGetFunctions(
pfExists[SQL_API_SQLDRIVERCONNECT] = TRUE;
pfExists[SQL_API_SQLGETCONNECTOPTION] = TRUE; // partial
pfExists[SQL_API_SQLGETDATA] = TRUE;
- pfExists[SQL_API_SQLGETFUNCTIONS] = TRUE; // sadly, I still
- // had to think about
- // this one
+ pfExists[SQL_API_SQLGETFUNCTIONS] = TRUE;
pfExists[SQL_API_SQLGETINFO] = TRUE;
- pfExists[SQL_API_SQLGETSTMTOPTION] = TRUE; // very partial
+ pfExists[SQL_API_SQLGETSTMTOPTION] = TRUE; // partial
pfExists[SQL_API_SQLGETTYPEINFO] = TRUE;
pfExists[SQL_API_SQLPARAMDATA] = TRUE;
pfExists[SQL_API_SQLPUTDATA] = TRUE;
@@ -858,11 +866,11 @@ RETCODE SQL_API SQLGetFunctions(
pfExists[SQL_API_SQLBROWSECONNECT] = FALSE;
pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
pfExists[SQL_API_SQLDATASOURCES] = FALSE; // only implemented by DM
- pfExists[SQL_API_SQLDESCRIBEPARAM] = FALSE;
- pfExists[SQL_API_SQLDRIVERS] = FALSE;
- pfExists[SQL_API_SQLEXTENDEDFETCH] = TRUE; // partial?
+ pfExists[SQL_API_SQLDESCRIBEPARAM] = TRUE;
+ pfExists[SQL_API_SQLDRIVERS] = FALSE; // only implemented by DM
+ pfExists[SQL_API_SQLEXTENDEDFETCH] = globals.use_declarefetch ? FALSE : TRUE;
pfExists[SQL_API_SQLFOREIGNKEYS] = TRUE;
- pfExists[SQL_API_SQLMORERESULTS] = TRUE;
+ pfExists[SQL_API_SQLMORERESULTS] = FALSE;
pfExists[SQL_API_SQLNATIVESQL] = TRUE;
pfExists[SQL_API_SQLNUMPARAMS] = TRUE;
pfExists[SQL_API_SQLPARAMOPTIONS] = FALSE;
@@ -870,7 +878,7 @@ RETCODE SQL_API SQLGetFunctions(
pfExists[SQL_API_SQLPROCEDURECOLUMNS] = FALSE;
pfExists[SQL_API_SQLPROCEDURES] = FALSE;
pfExists[SQL_API_SQLSETPOS] = FALSE;
- pfExists[SQL_API_SQLSETSCROLLOPTIONS] = FALSE;
+ pfExists[SQL_API_SQLSETSCROLLOPTIONS] = FALSE; // odbc 1.0
pfExists[SQL_API_SQLTABLEPRIVILEGES] = FALSE;
#endif
} else {
@@ -894,12 +902,12 @@ RETCODE SQL_API SQLGetFunctions(
case SQL_API_SQLFREECONNECT: *pfExists = TRUE; break;
case SQL_API_SQLFREEENV: *pfExists = TRUE; break;
case SQL_API_SQLFREESTMT: *pfExists = TRUE; break;
- case SQL_API_SQLGETCURSORNAME: *pfExists = FALSE; break;
+ case SQL_API_SQLGETCURSORNAME: *pfExists = TRUE; break;
case SQL_API_SQLNUMRESULTCOLS: *pfExists = TRUE; break;
case SQL_API_SQLPREPARE: *pfExists = TRUE; break;
case SQL_API_SQLROWCOUNT: *pfExists = TRUE; break;
- case SQL_API_SQLSETCURSORNAME: *pfExists = FALSE; break;
- case SQL_API_SQLSETPARAM: *pfExists = FALSE; break;
+ case SQL_API_SQLSETCURSORNAME: *pfExists = TRUE; break;
+ case SQL_API_SQLSETPARAM: *pfExists = FALSE; break; // odbc 1.0
case SQL_API_SQLTRANSACT: *pfExists = TRUE; break;
// ODBC level 1 functions
@@ -910,7 +918,7 @@ RETCODE SQL_API SQLGetFunctions(
case SQL_API_SQLGETDATA: *pfExists = TRUE; break;
case SQL_API_SQLGETFUNCTIONS: *pfExists = TRUE; break;
case SQL_API_SQLGETINFO: *pfExists = TRUE; break;
- case SQL_API_SQLGETSTMTOPTION: *pfExists = TRUE; break; // very partial
+ case SQL_API_SQLGETSTMTOPTION: *pfExists = TRUE; break; // partial
case SQL_API_SQLGETTYPEINFO: *pfExists = TRUE; break;
case SQL_API_SQLPARAMDATA: *pfExists = TRUE; break;
case SQL_API_SQLPUTDATA: *pfExists = TRUE; break;
@@ -924,11 +932,11 @@ RETCODE SQL_API SQLGetFunctions(
case SQL_API_SQLBROWSECONNECT: *pfExists = FALSE; break;
case SQL_API_SQLCOLUMNPRIVILEGES: *pfExists = FALSE; break;
case SQL_API_SQLDATASOURCES: *pfExists = FALSE; break; // only implemented by DM
- case SQL_API_SQLDESCRIBEPARAM: *pfExists = FALSE; break;
- case SQL_API_SQLDRIVERS: *pfExists = FALSE; break;
- case SQL_API_SQLEXTENDEDFETCH: *pfExists = TRUE; break; // partial?
+ case SQL_API_SQLDESCRIBEPARAM: *pfExists = TRUE; break;
+ case SQL_API_SQLDRIVERS: *pfExists = FALSE; break; // only implemented by DM
+ case SQL_API_SQLEXTENDEDFETCH: *pfExists = globals.use_declarefetch ? FALSE : TRUE; break;
case SQL_API_SQLFOREIGNKEYS: *pfExists = TRUE; break;
- case SQL_API_SQLMORERESULTS: *pfExists = TRUE; break;
+ case SQL_API_SQLMORERESULTS: *pfExists = FALSE; break;
case SQL_API_SQLNATIVESQL: *pfExists = TRUE; break;
case SQL_API_SQLNUMPARAMS: *pfExists = TRUE; break;
case SQL_API_SQLPARAMOPTIONS: *pfExists = FALSE; break;
@@ -936,7 +944,7 @@ RETCODE SQL_API SQLGetFunctions(
case SQL_API_SQLPROCEDURECOLUMNS: *pfExists = FALSE; break;
case SQL_API_SQLPROCEDURES: *pfExists = FALSE; break;
case SQL_API_SQLSETPOS: *pfExists = FALSE; break;
- case SQL_API_SQLSETSCROLLOPTIONS: *pfExists = FALSE; break;
+ case SQL_API_SQLSETSCROLLOPTIONS: *pfExists = FALSE; break; // odbc 1.0
case SQL_API_SQLTABLEPRIVILEGES: *pfExists = FALSE; break;
}
#endif
@@ -965,8 +973,14 @@ HSTMT htbl_stmt;
RETCODE result;
char *tableType;
char tables_query[MAX_STATEMENT_LEN];
-char table_name[MAX_INFO_STRING], table_owner[MAX_INFO_STRING];
-SDWORD table_name_len, table_owner_len;
+char table_name[MAX_INFO_STRING], table_owner[MAX_INFO_STRING], relhasrules[MAX_INFO_STRING];
+SDWORD table_name_len, table_owner_len, relhasrules_len;
+ConnInfo *ci;
+char *prefix[32], prefixes[MEDIUM_REGISTRY_LEN];
+char *table_type[32], table_types[MAX_INFO_STRING];
+char show_system_tables, show_regular_tables, show_views;
+char regular_table, view, systable;
+int i;
mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
@@ -976,6 +990,8 @@ mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
stmt->manual_result = TRUE;
stmt->errormsg_created = TRUE;
+ ci = &stmt->hdbc->connInfo;
+
result = SQLAllocStmt( stmt->hdbc, &htbl_stmt);
if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
stmt->errornumber = STMT_NO_MEMORY_ERROR;
@@ -988,20 +1004,72 @@ mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
// Create the query to find out the tables
// **********************************************************************
- strcpy(tables_query, "select relname, usename from pg_class, pg_user where relkind = 'r' ");
+ strcpy(tables_query, "select relname, usename, relhasrules from pg_class, pg_user where relkind = 'r' ");
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
+ strcpy(prefixes, globals.extra_systable_prefixes);
+ i = 0;
+ prefix[i] = strtok(prefixes, ";");
+ while (prefix[i] && i<32) {
+ prefix[++i] = strtok(NULL, ";");
+ }
+
+ /* Parse the desired table types to return */
+ show_system_tables = FALSE;
+ show_regular_tables = FALSE;
+ show_views = FALSE;
+
// make_string mallocs memory
tableType = make_string(szTableType, cbTableType, NULL);
- if (tableType && ! strstr(tableType, "SYSTEM TABLE")) // is SYSTEM TABLE not present?
- strcat(tables_query, " and relname not like '" POSTGRES_SYS_PREFIX "%' and relname not like '" INSIGHT_SYS_PREFIX "%'");
-
- if (tableType)
+ if (tableType) {
+ strcpy(table_types, tableType);
free(tableType);
+ i = 0;
+ table_type[i] = strtok(table_types, ",");
+ while (table_type[i] && i<32) {
+ table_type[++i] = strtok(NULL, ",");
+ }
- strcat(tables_query, " and relname !~ '^Inv[0-9]+' and int4out(usesysid) = int4out(relowner) order by relname");
+ /* Check for desired table types to return */
+ i = 0;
+ while (table_type[i]) {
+ if ( strstr(table_type[i], "SYSTEM TABLE"))
+ show_system_tables = TRUE;
+ else if ( strstr(table_type[i], "TABLE"))
+ show_regular_tables = TRUE;
+ else if ( strstr(table_type[i], "VIEW"))
+ show_views = TRUE;
+
+ i++;
+ }
+
+ }
+
+ /* If not interested in SYSTEM TABLES then filter them out
+ to save some time on the query. If treating system tables
+ as regular tables, then dont filter either.
+ */
+ if ( ! atoi(ci->show_system_tables) && ! show_system_tables) {
+ strcat(tables_query, " and relname !~ '^" POSTGRES_SYS_PREFIX);
+
+ /* Also filter out user-defined system table types */
+ i = 0;
+ while(prefix[i]) {
+ strcat(tables_query, "|^");
+ strcat(tables_query, prefix[i]);
+ i++;
+ }
+
+ strcat(tables_query, "'");
+ }
+
+
+ /* filter out large objects unconditionally (they are not system tables) and match users */
+ strcat(tables_query, " and relname !~ '^xinv[0-9]+' and int4out(usesysid) = int4out(relowner) order by relname");
// **********************************************************************
@@ -1030,6 +1098,14 @@ mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
SQLFreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
+ result = SQLBindCol(htbl_stmt, 3, SQL_C_CHAR,
+ relhasrules, MAX_INFO_STRING, &relhasrules_len);
+ if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
+ stmt->errormsg = tbl_stmt->errormsg;
+ stmt->errornumber = tbl_stmt->errornumber;
+ SQLFreeStmt(htbl_stmt, SQL_DROP);
+ return SQL_ERROR;
+ }
stmt->result = QR_Constructor();
if(!stmt->result) {
@@ -1054,33 +1130,63 @@ mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
// add the tuples
result = SQLFetch(htbl_stmt);
while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
- row = (TupleNode *)malloc(sizeof(TupleNode) + (5 - 1) * sizeof(TupleField));
- set_tuplefield_string(&row->tuple[0], "");
+ /* Determine if this table name is a system table.
+ If treating system tables as regular tables, then
+ no need to do this test.
+ */
+ systable = FALSE;
+ if( ! atoi(ci->show_system_tables)) {
+
+ if ( strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0)
+ systable = TRUE;
+
+ else { /* Check extra system table prefixes */
+ i = 0;
+ while (prefix[i]) {
+ mylog("table_name='%s', prefix[%d]='%s'\n", table_name, i, prefix[i]);
+ if (strncmp(table_name, prefix[i], strlen(prefix[i])) == 0) {
+ systable = TRUE;
+ break;
+ }
+ i++;
+ }
+ }
+ }
- // I have to hide the table owner from Access, otherwise it
- // insists on referring to the table as 'owner.table'.
- // (this is valid according to the ODBC SQL grammar, but
- // Postgres won't support it.)
- // set_tuplefield_string(&row->tuple[1], table_owner);
+ /* Determine if the table name is a view */
+ view = (relhasrules[0] == '1');
- set_tuplefield_string(&row->tuple[1], "");
- set_tuplefield_string(&row->tuple[2], table_name);
+ /* It must be a regular table */
+ regular_table = ( ! systable && ! view);
- mylog("SQLTables: table_name = '%s'\n", table_name);
- // careful: this is case-sensitive
- if(strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0 ||
- strncmp(table_name, INSIGHT_SYS_PREFIX, strlen(INSIGHT_SYS_PREFIX)) == 0) {
- set_tuplefield_string(&row->tuple[3], "SYSTEM TABLE");
- } else {
- set_tuplefield_string(&row->tuple[3], "TABLE");
- }
+ /* Include the row in the result set if meets all criteria */
+ /* NOTE: Unsupported table types (i.e., LOCAL TEMPORARY, ALIAS, etc)
+ will return nothing */
+ if ( (systable && show_system_tables) ||
+ (view && show_views) ||
+ (regular_table && show_regular_tables)) {
- set_tuplefield_string(&row->tuple[4], "");
+ row = (TupleNode *)malloc(sizeof(TupleNode) + (5 - 1) * sizeof(TupleField));
- QR_add_tuple(stmt->result, row);
+ set_tuplefield_string(&row->tuple[0], "");
+
+ // I have to hide the table owner from Access, otherwise it
+ // insists on referring to the table as 'owner.table'.
+ // (this is valid according to the ODBC SQL grammar, but
+ // Postgres won't support it.)
+ // set_tuplefield_string(&row->tuple[1], table_owner);
+
+ mylog("SQLTables: table_name = '%s'\n", table_name);
+
+ set_tuplefield_string(&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], "");
+ QR_add_tuple(stmt->result, row);
+ }
result = SQLFetch(htbl_stmt);
}
if(result != SQL_NO_DATA_FOUND) {
@@ -1096,6 +1202,7 @@ mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
// set up the current tuple pointer for SQLFetch
stmt->currTuple = -1;
+ stmt->current_col = -1;
SQLFreeStmt(htbl_stmt, SQL_DROP);
mylog("SQLTables(): EXIT, stmt=%u\n", stmt);
@@ -1125,6 +1232,9 @@ Int4 field_type;
SDWORD table_owner_len, table_name_len, field_name_len,
field_type_len, field_type_name_len, field_number_len,
field_length_len, mod_length_len;
+ConnInfo *ci;
+
+
mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
@@ -1133,13 +1243,15 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
stmt->manual_result = TRUE;
stmt->errormsg_created = TRUE;
-
+
+ ci = &stmt->hdbc->connInfo;
+
// **********************************************************************
// 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,t.typname, a.attnum, a.attlen, %s from pg_user u, pg_class c, pg_attribute a, pg_type t where "
- "int4out(u.usesysid) = int4out(c.relowner) and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)",
- PROTOCOL_62(&(stmt->hdbc->connInfo)) ? "a.attlen" : "a.atttypmod");
+ "int4out(u.usesysid) = int4out(c.relowner) and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)",
+ PROTOCOL_62(ci) ? "a.attlen" : "a.atttypmod");
my_strcat(columns_query, " and c.relname like '%.*s'", szTableName, cbTableName);
my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner);
@@ -1266,7 +1378,43 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
QR_set_field_info(stmt->result, 10, "NULLABLE", PG_TYPE_INT2, 2);
QR_set_field_info(stmt->result, 11, "REMARKS", PG_TYPE_TEXT, 254);
- result = SQLFetch(hcol_stmt);
+
+ result = SQLFetch(hcol_stmt);
+
+ /* Only show oid if option AND there are other columns AND
+ its not being called by SQLStatistics .
+ Always show OID if its a system table
+ */
+
+ if (result != SQL_ERROR && ! stmt->internal &&
+ (atoi(ci->show_oid_column) || strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0)) {
+
+ /* For OID fields */
+ row = (TupleNode *)malloc(sizeof(TupleNode) +
+ (12 - 1) * sizeof(TupleField));
+
+ set_tuplefield_string(&row->tuple[0], "");
+ // see note in SQLTables()
+ // set_tuplefield_string(&row->tuple[1], table_owner);
+ set_tuplefield_string(&row->tuple[1], "");
+ set_tuplefield_string(&row->tuple[2], table_name);
+ set_tuplefield_string(&row->tuple[3], "oid");
+ set_tuplefield_int2(&row->tuple[4], pgtype_to_sqltype(stmt, PG_TYPE_OID));
+ set_tuplefield_string(&row->tuple[5], "OID");
+
+ set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, PG_TYPE_OID, PG_STATIC,
+ PG_STATIC));
+ set_tuplefield_int4(&row->tuple[6], pgtype_precision(stmt, PG_TYPE_OID, PG_STATIC,
+ PG_STATIC));
+
+ set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, PG_TYPE_OID));
+ set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, PG_TYPE_OID));
+ set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS);
+ set_tuplefield_string(&row->tuple[11], "");
+
+ QR_add_tuple(stmt->result, row);
+ }
+
while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
row = (TupleNode *)malloc(sizeof(TupleNode) +
(12 - 1) * sizeof(TupleField));
@@ -1277,51 +1425,40 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
set_tuplefield_string(&row->tuple[1], "");
set_tuplefield_string(&row->tuple[2], table_name);
set_tuplefield_string(&row->tuple[3], field_name);
+ set_tuplefield_int2(&row->tuple[4], pgtype_to_sqltype(stmt, field_type));
+ set_tuplefield_string(&row->tuple[5], field_type_name);
- /* Replace an unknown postgres type with SQL_CHAR type */
- /* Leave the field_type_name with "unknown" */
- if (pgtype_to_sqltype(field_type) == PG_UNKNOWN)
- set_tuplefield_int2(&row->tuple[4], SQL_CHAR);
- else
- set_tuplefield_int2(&row->tuple[4], pgtype_to_sqltype(field_type));
- set_tuplefield_string(&row->tuple[5], field_type_name);
-
-
- /* Some Notes about Postgres Data Types:
-
- VARCHAR - the length is stored in the pg_attribute.atttypmod field
- BPCHAR - the length is also stored as varchar is
- NAME - the length is fixed and stored in pg_attribute.attlen field (32 on my system)
-
+ /* Some Notes about Postgres Data Types:
+
+ VARCHAR - the length is stored in the pg_attribute.atttypmod field
+ BPCHAR - the length is also stored as varchar is
+
*/
if((field_type == PG_TYPE_VARCHAR) ||
- (field_type == PG_TYPE_NAME) ||
(field_type == PG_TYPE_BPCHAR)) {
- if (field_type == PG_TYPE_NAME)
- mod_length = field_length; // the length is in attlen
- else if (mod_length >= 4)
+ if (mod_length >= 4)
mod_length -= 4; // the length is in atttypmod - 4
- if (mod_length > MAX_VARCHAR_SIZE || mod_length <= 0)
- mod_length = MAX_VARCHAR_SIZE;
+ if (mod_length > globals.max_varchar_size || mod_length <= 0)
+ mod_length = globals.max_varchar_size;
- mylog("SQLColumns: field type is VARCHAR,NAME: field_type = %d, mod_length = %d\n", field_type, mod_length);
+ mylog("SQLColumns: field type is VARCHAR,BPCHAR: field_type = %d, mod_length = %d\n", field_type, mod_length);
set_tuplefield_int4(&row->tuple[7], mod_length);
set_tuplefield_int4(&row->tuple[6], mod_length);
} else {
- mylog("SQLColumns: field type is OTHER: field_type = %d, pgtype_length = %d\n", field_type, pgtype_length(field_type));
+ mylog("SQLColumns: field type is OTHER: field_type = %d, pgtype_length = %d\n", field_type, pgtype_length(stmt, field_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[7], pgtype_length(field_type));
- set_tuplefield_int4(&row->tuple[6], pgtype_precision(field_type));
+ set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, field_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&row->tuple[6], pgtype_precision(stmt, field_type, PG_STATIC, PG_STATIC));
}
- set_nullfield_int2(&row->tuple[8], pgtype_scale(field_type));
- set_nullfield_int2(&row->tuple[9], pgtype_radix(field_type));
- set_tuplefield_int2(&row->tuple[10], pgtype_nullable(field_type));
+ set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, field_type));
+ set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, field_type));
+ set_tuplefield_int2(&row->tuple[10], pgtype_nullable(stmt, field_type));
set_tuplefield_string(&row->tuple[11], "");
QR_add_tuple(stmt->result, row);
@@ -1341,6 +1478,7 @@ mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
// set up the current tuple pointer for SQLFetch
stmt->currTuple = -1;
+ stmt->current_col = -1;
SQLFreeStmt(hcol_stmt, SQL_DROP);
mylog("SQLColumns(): EXIT, stmt=%u\n", stmt);
@@ -1383,16 +1521,15 @@ mylog("**** SQLSpecialColumns(): ENTER, stmt=%u\n", stmt);
/* use the oid value for the rowid */
if(fColType == SQL_BEST_ROWID) {
-
row = (TupleNode *)malloc(sizeof(TupleNode) + (8 - 1) * sizeof(TupleField));
set_tuplefield_int2(&row->tuple[0], SQL_SCOPE_SESSION);
set_tuplefield_string(&row->tuple[1], "oid");
- set_tuplefield_int2(&row->tuple[2], pgtype_to_sqltype(PG_TYPE_OID));
+ set_tuplefield_int2(&row->tuple[2], pgtype_to_sqltype(stmt, PG_TYPE_OID));
set_tuplefield_string(&row->tuple[3], "OID");
- set_tuplefield_int4(&row->tuple[4], pgtype_precision(PG_TYPE_OID));
- set_tuplefield_int4(&row->tuple[5], pgtype_length(PG_TYPE_OID));
- set_tuplefield_int2(&row->tuple[6], pgtype_scale(PG_TYPE_OID));
+ set_tuplefield_int4(&row->tuple[4], pgtype_precision(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&row->tuple[5], pgtype_length(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
+ set_tuplefield_int2(&row->tuple[6], pgtype_scale(stmt, PG_TYPE_OID));
set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO);
QR_add_tuple(stmt->result, row);
@@ -1405,6 +1542,7 @@ mylog("**** SQLSpecialColumns(): ENTER, stmt=%u\n", stmt);
stmt->status = STMT_FINISHED;
stmt->currTuple = -1;
+ stmt->current_col = -1;
mylog("SQLSpecialColumns(): EXIT, stmt=%u\n", stmt);
return SQL_SUCCESS;
@@ -1428,6 +1566,7 @@ RETCODE result;
char *table_name;
char index_name[MAX_INFO_STRING];
short fields_vector[8];
+char isunique[10], isclustered[10];
SDWORD index_name_len, fields_vector_len;
TupleNode *row;
int i;
@@ -1438,6 +1577,8 @@ char **column_names = 0;
Int4 column_name_len;
int total_columns = 0;
char error = TRUE;
+ConnInfo *ci;
+char buf[256];
mylog("**** SQLStatistics(): ENTER, stmt=%u\n", stmt);
@@ -1448,6 +1589,8 @@ mylog("**** SQLStatistics(): ENTER, stmt=%u\n", stmt);
stmt->manual_result = TRUE;
stmt->errormsg_created = TRUE;
+ ci = &stmt->hdbc->connInfo;
+
stmt->result = QR_Constructor();
if(!stmt->result) {
stmt->errormsg = "Couldn't allocate memory for SQLStatistics result.";
@@ -1475,114 +1618,178 @@ mylog("**** SQLStatistics(): ENTER, stmt=%u\n", stmt);
QR_set_field_info(stmt->result, 11, "PAGES", PG_TYPE_INT4, 4);
QR_set_field_info(stmt->result, 12, "FILTER_CONDITION", PG_TYPE_TEXT, MAX_INFO_STRING);
- // there are no unique indexes in postgres, so return nothing
- // if those are requested
- if(fUnique != SQL_INDEX_UNIQUE) {
- // only use the table name... the owner should be redundant, and
- // we never use qualifiers.
- table_name = make_string(szTableName, cbTableName, NULL);
- if ( ! table_name) {
- stmt->errormsg = "No table name passed to SQLStatistics.";
- stmt->errornumber = STMT_INTERNAL_ERROR;
- return SQL_ERROR;
- }
- // we need to get a list of the field names first,
- // so we can return them later.
- result = SQLAllocStmt( stmt->hdbc, &hcol_stmt);
- if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
- stmt->errormsg = "SQLAllocStmt failed in SQLStatistics for columns.";
- stmt->errornumber = STMT_NO_MEMORY_ERROR;
- goto SEEYA;
- }
+ // only use the table name... the owner should be redundant, and
+ // we never use qualifiers.
+ table_name = make_string(szTableName, cbTableName, NULL);
+ if ( ! table_name) {
+ stmt->errormsg = "No table name passed to SQLStatistics.";
+ stmt->errornumber = STMT_INTERNAL_ERROR;
+ return SQL_ERROR;
+ }
- col_stmt = (StatementClass *) hcol_stmt;
+ // we need to get a list of the field names first,
+ // so we can return them later.
+ result = SQLAllocStmt( stmt->hdbc, &hcol_stmt);
+ if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
+ stmt->errormsg = "SQLAllocStmt failed in SQLStatistics for columns.";
+ stmt->errornumber = STMT_NO_MEMORY_ERROR;
+ goto SEEYA;
+ }
- result = SQLColumns(hcol_stmt, "", 0, "", 0,
- table_name, (SWORD) strlen(table_name), "", 0);
- if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
- stmt->errormsg = col_stmt->errormsg; // "SQLColumns failed in SQLStatistics.";
- stmt->errornumber = col_stmt->errornumber; // STMT_EXEC_ERROR;
- SQLFreeStmt(hcol_stmt, SQL_DROP);
- goto SEEYA;
- }
- result = SQLBindCol(hcol_stmt, 4, SQL_C_CHAR,
- column_name, MAX_INFO_STRING, &column_name_len);
- if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
- stmt->errormsg = col_stmt->errormsg;
- stmt->errornumber = col_stmt->errornumber;
+ col_stmt = (StatementClass *) hcol_stmt;
+
+ /* "internal" prevents SQLColumns from returning the oid if it is being shown.
+ This would throw everything off.
+ */
+ col_stmt->internal = TRUE;
+ result = SQLColumns(hcol_stmt, "", 0, "", 0,
+ table_name, (SWORD) strlen(table_name), "", 0);
+ col_stmt->internal = FALSE;
+
+ if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
+ stmt->errormsg = col_stmt->errormsg; // "SQLColumns failed in SQLStatistics.";
+ stmt->errornumber = col_stmt->errornumber; // STMT_EXEC_ERROR;
SQLFreeStmt(hcol_stmt, SQL_DROP);
goto SEEYA;
+ }
+ result = SQLBindCol(hcol_stmt, 4, SQL_C_CHAR,
+ column_name, MAX_INFO_STRING, &column_name_len);
+ if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
+ stmt->errormsg = col_stmt->errormsg;
+ stmt->errornumber = col_stmt->errornumber;
+ SQLFreeStmt(hcol_stmt, SQL_DROP);
+ goto SEEYA;
- }
+ }
+
+ result = SQLFetch(hcol_stmt);
+ while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
+ total_columns++;
+
+ column_names =
+ (char **)realloc(column_names,
+ total_columns * sizeof(char *));
+ column_names[total_columns-1] =
+ (char *)malloc(strlen(column_name)+1);
+ strcpy(column_names[total_columns-1], column_name);
+
+ mylog("SQLStatistics: column_name = '%s'\n", column_name);
result = SQLFetch(hcol_stmt);
- while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
- total_columns++;
+ }
+ if(result != SQL_NO_DATA_FOUND || total_columns == 0) {
+ stmt->errormsg = SC_create_errormsg(hcol_stmt); // "Couldn't get column names in SQLStatistics.";
+ stmt->errornumber = col_stmt->errornumber;
+ SQLFreeStmt(hcol_stmt, SQL_DROP);
+ goto SEEYA;
- column_names =
- (char **)realloc(column_names,
- total_columns * sizeof(char *));
- column_names[total_columns-1] =
- (char *)malloc(strlen(column_name)+1);
- strcpy(column_names[total_columns-1], column_name);
+ }
+
+ SQLFreeStmt(hcol_stmt, SQL_DROP);
- result = SQLFetch(hcol_stmt);
- }
- if(result != SQL_NO_DATA_FOUND || total_columns == 0) {
- stmt->errormsg = SC_create_errormsg(hcol_stmt); // "Couldn't get column names in SQLStatistics.";
- stmt->errornumber = col_stmt->errornumber;
- SQLFreeStmt(hcol_stmt, SQL_DROP);
- goto SEEYA;
+ // get a list of indexes on this table
+ result = SQLAllocStmt( stmt->hdbc, &hindx_stmt);
+ if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
+ stmt->errormsg = "SQLAllocStmt failed in SQLStatistics for indices.";
+ stmt->errornumber = STMT_NO_MEMORY_ERROR;
+ goto SEEYA;
- }
-
- SQLFreeStmt(hcol_stmt, SQL_DROP);
+ }
+ indx_stmt = (StatementClass *) hindx_stmt;
- // get a list of indexes on this table
- result = SQLAllocStmt( stmt->hdbc, &hindx_stmt);
- if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
- stmt->errormsg = "SQLAllocStmt failed in SQLStatistics for indices.";
- stmt->errornumber = STMT_NO_MEMORY_ERROR;
- goto SEEYA;
+ sprintf(index_query, "select c.relname, i.indkey, i.indisunique, i.indisclustered from pg_index i, pg_class c, pg_class d where c.oid = i.indexrelid and d.relname = '%s' and d.oid = i.indrelid",
+ table_name);
- }
- indx_stmt = (StatementClass *) hindx_stmt;
+ result = SQLExecDirect(hindx_stmt, index_query, strlen(index_query));
+ if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
+ stmt->errormsg = SC_create_errormsg(hindx_stmt); // "Couldn't execute index query (w/SQLExecDirect) in SQLStatistics.";
+ stmt->errornumber = indx_stmt->errornumber;
+ SQLFreeStmt(hindx_stmt, SQL_DROP);
+ goto SEEYA;
+
+ }
+
+ // bind the index name column
+ result = SQLBindCol(hindx_stmt, 1, SQL_C_CHAR,
+ index_name, MAX_INFO_STRING, &index_name_len);
+ if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
+ stmt->errormsg = indx_stmt->errormsg; // "Couldn't bind column in SQLStatistics.";
+ stmt->errornumber = indx_stmt->errornumber;
+ SQLFreeStmt(hindx_stmt, SQL_DROP);
+ goto SEEYA;
- sprintf(index_query, "select c.relname, i.indkey from pg_index i, pg_class c, pg_class d where c.oid = i.indexrelid and d.relname = '%s' and d.oid = i.indrelid",
- table_name);
+ }
+ // bind the vector column
+ result = SQLBindCol(hindx_stmt, 2, SQL_C_DEFAULT,
+ fields_vector, 16, &fields_vector_len);
+ if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
+ stmt->errormsg = indx_stmt->errormsg; // "Couldn't bind column in SQLStatistics.";
+ stmt->errornumber = indx_stmt->errornumber;
+ SQLFreeStmt(hindx_stmt, SQL_DROP);
+ goto SEEYA;
- result = SQLExecDirect(hindx_stmt, index_query, strlen(index_query));
- if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
- stmt->errormsg = SC_create_errormsg(hindx_stmt); // "Couldn't execute index query (w/SQLExecDirect) in SQLStatistics.";
- stmt->errornumber = indx_stmt->errornumber;
- SQLFreeStmt(hindx_stmt, SQL_DROP);
- goto SEEYA;
+ }
+ // bind the "is unique" column
+ result = SQLBindCol(hindx_stmt, 3, SQL_C_CHAR,
+ isunique, sizeof(isunique), NULL);
+ if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
+ stmt->errormsg = indx_stmt->errormsg; // "Couldn't bind column in SQLStatistics.";
+ stmt->errornumber = indx_stmt->errornumber;
+ SQLFreeStmt(hindx_stmt, SQL_DROP);
+ goto SEEYA;
+ }
- }
+ // bind the "is clustered" column
+ result = SQLBindCol(hindx_stmt, 4, SQL_C_CHAR,
+ isclustered, sizeof(isclustered), NULL);
+ if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
+ stmt->errormsg = indx_stmt->errormsg; // "Couldn't bind column in SQLStatistics.";
+ stmt->errornumber = indx_stmt->errornumber;
+ SQLFreeStmt(hindx_stmt, SQL_DROP);
+ goto SEEYA;
- result = SQLBindCol(hindx_stmt, 1, SQL_C_CHAR,
- index_name, MAX_INFO_STRING, &index_name_len);
- if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
- stmt->errormsg = indx_stmt->errormsg; // "Couldn't bind column in SQLStatistics.";
- stmt->errornumber = indx_stmt->errornumber;
- SQLFreeStmt(hindx_stmt, SQL_DROP);
- goto SEEYA;
+ }
- }
- // bind the vector column
- result = SQLBindCol(hindx_stmt, 2, SQL_C_DEFAULT,
- fields_vector, 16, &fields_vector_len);
- if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
- stmt->errormsg = indx_stmt->errormsg; // "Couldn't bind column in SQLStatistics.";
- stmt->errornumber = indx_stmt->errornumber;
- SQLFreeStmt(hindx_stmt, SQL_DROP);
- goto SEEYA;
+ /* fake index of OID */
+ if (atoi(ci->show_oid_column) && atoi(ci->fake_oid_index)) {
+ row = (TupleNode *)malloc(sizeof(TupleNode) +
+ (13 - 1) * sizeof(TupleField));
- }
+ // 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[2], table_name);
- result = SQLFetch(hindx_stmt);
- while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
+ // non-unique index?
+ set_tuplefield_int2(&row->tuple[3], (Int2) (globals.unique_index ? FALSE : TRUE));
+
+ // no index qualifier
+ set_tuplefield_string(&row->tuple[4], "");
+
+ sprintf(buf, "%s_idx_fake_oid", table_name);
+ set_tuplefield_string(&row->tuple[5], buf);
+
+ // Clustered index? I think non-clustered should be type OTHER not HASHED
+ set_tuplefield_int2(&row->tuple[6], (Int2) SQL_INDEX_OTHER);
+ set_tuplefield_int2(&row->tuple[7], (Int2) 1);
+
+ set_tuplefield_string(&row->tuple[8], "oid");
+ set_tuplefield_string(&row->tuple[9], "A");
+ set_tuplefield_null(&row->tuple[10]);
+ set_tuplefield_null(&row->tuple[11]);
+ set_tuplefield_null(&row->tuple[12]);
+
+ QR_add_tuple(stmt->result, row);
+ }
+
+ result = SQLFetch(hindx_stmt);
+ while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
+
+ // If only requesting unique indexs, then just return those.
+ if (fUnique == SQL_INDEX_ALL ||
+ (fUnique == SQL_INDEX_UNIQUE && atoi(isunique))) {
i = 0;
// add a row in this table for each field in the index
while(i < 8 && fields_vector[i] != 0) {
@@ -1596,24 +1803,32 @@ mylog("**** SQLStatistics(): ENTER, stmt=%u\n", stmt);
set_tuplefield_string(&row->tuple[1], "");
set_tuplefield_string(&row->tuple[2], table_name);
- // Postgres95 indices always allow non-unique values.
- set_tuplefield_int2(&row->tuple[3], TRUE);
+ // non-unique index?
+ if (globals.unique_index)
+ set_tuplefield_int2(&row->tuple[3], (Int2) (atoi(isunique) ? FALSE : TRUE));
+ else
+ set_tuplefield_int2(&row->tuple[3], TRUE);
// no index qualifier
set_tuplefield_string(&row->tuple[4], "");
set_tuplefield_string(&row->tuple[5], index_name);
- // check this--what does it mean for an index
- // to be clustered? (none of mine seem to be--
- // we can and probably should find this out from
- // the pg_index table)
- set_tuplefield_int2(&row->tuple[6], SQL_INDEX_HASHED);
+ // Clustered index? I think non-clustered should be type OTHER not HASHED
+ set_tuplefield_int2(&row->tuple[6], (Int2) (atoi(isclustered) ? SQL_INDEX_CLUSTERED : SQL_INDEX_OTHER));
set_tuplefield_int2(&row->tuple[7], (Int2) (i+1));
- if(fields_vector[i] < 0 || fields_vector[i] > total_columns)
+ if(fields_vector[i] == OID_ATTNUM) {
+ set_tuplefield_string(&row->tuple[8], "oid");
+ mylog("SQLStatistics: column name = oid\n");
+ }
+ else if(fields_vector[i] < 0 || fields_vector[i] > total_columns) {
set_tuplefield_string(&row->tuple[8], "UNKNOWN");
- else
+ mylog("SQLStatistics: column name = UNKNOWN\n");
+ }
+ else {
set_tuplefield_string(&row->tuple[8], column_names[fields_vector[i]-1]);
+ mylog("SQLStatistics: column name = '%s'\n", column_names[fields_vector[i]-1]);
+ }
set_tuplefield_string(&row->tuple[9], "A");
set_tuplefield_null(&row->tuple[10]);
@@ -1622,26 +1837,27 @@ mylog("**** SQLStatistics(): ENTER, stmt=%u\n", stmt);
QR_add_tuple(stmt->result, row);
i++;
- }
-
- result = SQLFetch(hindx_stmt);
- }
- if(result != SQL_NO_DATA_FOUND) {
- stmt->errormsg = SC_create_errormsg(hindx_stmt); // "SQLFetch failed in SQLStatistics.";
- stmt->errornumber = indx_stmt->errornumber;
- SQLFreeStmt(hindx_stmt, SQL_DROP);
- goto SEEYA;
- }
+ }
+ }
+ result = SQLFetch(hindx_stmt);
+ }
+ if(result != SQL_NO_DATA_FOUND) {
+ stmt->errormsg = SC_create_errormsg(hindx_stmt); // "SQLFetch failed in SQLStatistics.";
+ stmt->errornumber = indx_stmt->errornumber;
SQLFreeStmt(hindx_stmt, SQL_DROP);
+ goto SEEYA;
}
+ SQLFreeStmt(hindx_stmt, SQL_DROP);
+
// also, things need to think that this statement is finished so
// the results can be retrieved.
stmt->status = STMT_FINISHED;
// set up the current tuple pointer for SQLFetch
stmt->currTuple = -1;
+ stmt->current_col = -1;
error = FALSE;
@@ -1672,6 +1888,7 @@ RETCODE SQL_API SQLColumnPrivileges(
UCHAR FAR * szColumnName,
SWORD cbColumnName)
{
+/* Neither Access or Borland care about this. */
return SQL_ERROR;
}
@@ -1702,7 +1919,7 @@ int nk = 0;
tbl_stmt = (StatementClass *) htbl_stmt;
tables_query[0] = '\0';
- if ( ! my_strcat(tables_query, "select distinct on attnum a2.attname, a2.attnum from pg_attribute a1, pg_attribute a2, pg_class c, pg_index i where c.relname = '%.*s_key' AND c.oid = i.indexrelid AND a1.attrelid = c.oid AND a2.attrelid = c.oid AND (i.indkey[0] = a1.attnum OR i.indkey[1] = a1.attnum OR i.indkey[2] = a1.attnum OR i.indkey[3] = a1.attnum OR i.indkey[4] = a1.attnum OR i.indkey[5] = a1.attnum OR i.indkey[6] = a1.attnum OR i.indkey[7] = a1.attnum) order by a2.attnum",
+ if ( ! my_strcat(tables_query, "select distinct on attnum a2.attname, a2.attnum from pg_attribute a1, pg_attribute a2, pg_class c, pg_index i where c.relname = '%.*s_pkey' AND c.oid = i.indexrelid AND a1.attrelid = c.oid AND a2.attrelid = c.oid AND (i.indkey[0] = a1.attnum OR i.indkey[1] = a1.attnum OR i.indkey[2] = a1.attnum OR i.indkey[3] = a1.attnum OR i.indkey[4] = a1.attnum OR i.indkey[5] = a1.attnum OR i.indkey[6] = a1.attnum OR i.indkey[7] = a1.attnum) order by a2.attnum",
szTableName, cbTableName)) {
stmt->errormsg = "No Table specified to getPrimaryKeyString.";
@@ -1883,6 +2100,7 @@ mylog("**** SQLPrimaryKeys(): ENTER, stmt=%u\n", stmt);
// set up the current tuple pointer for SQLFetch
stmt->currTuple = -1;
+ stmt->current_col = -1;
mylog("SQLPrimaryKeys(): EXIT, stmt=%u\n", stmt);
return SQL_SUCCESS;
@@ -2134,6 +2352,7 @@ mylog("**** SQLForeignKeys(): ENTER, stmt=%u\n", stmt);
// set up the current tuple pointer for SQLFetch
stmt->currTuple = -1;
+ stmt->current_col = -1;
mylog("SQLForeignKeys(): EXIT, stmt=%u\n", stmt);
return SQL_SUCCESS;