From 01d10c233df6a83597f89e66b5481636bdcf8f3c Mon Sep 17 00:00:00 2001 From: Hiroshi Inoue Date: Tue, 6 Jan 2004 09:58:22 +0000 Subject: [PATCH] 1) Correct the handling of SQL_C_ULONG (for *nix). 2) Prevent plan deallocation errors when the transaction is in abort status. 3) Avoid a connection failure when notice message arrives. 4) Improve the handling of mutex(critical section). 5) Correct the cursor open check. 6) Change the Unicode driver to set the NULL terminator of SQL_C_WCHAR type data properly. 7) Add some m(re)alloc error check. 8) Add proper cleanup steps for some functions. 9) Return proper min & max scale for timestamp data type. 10) Return proper scale for timestamp data fields. 11) Fix the bug that .009 numeric generates .9 output. (George A.J) --- configure.ac | 6 +- connection.c | 97 +++++++++-- connection.h | 55 ++++++- convert.c | 72 +++++--- dlg_specific.c | 2 + execute.c | 2 +- info.c | 438 ++++++++++++++++++++++++------------------------- odbcapi.c | 96 ++++++++--- odbcapi30w.c | 2 +- options.c | 5 +- pgtypes.c | 68 ++++++++ pgtypes.h | 2 + qresult.c | 124 ++++++++------ qresult.h | 34 +++- results.c | 40 ++--- socket.c | 6 + statement.c | 80 ++++----- statement.h | 21 ++- version.h | 6 +- win_unicode.c | 4 +- 20 files changed, 737 insertions(+), 423 deletions(-) diff --git a/configure.ac b/configure.ac index 45251b3..4ef4253 100644 --- a/configure.ac +++ b/configure.ac @@ -37,7 +37,7 @@ AC_MSG_RESULT([$with_odbcver]) AM_CONDITIONAL(with_unixodbc, [test $with_unixodbc = yes]) AM_CONDITIONAL(with_iodbc, [test $with_iodbc = yes]) -AC_CHECK_FUNCS(strtoll) +AC_CHECK_FUNCS(strtoul strtoll) AC_CHECK_LIB(socket, socket) # to implement the thread-safe driver @@ -89,5 +89,9 @@ AC_CHECK_HEADERS([sys/un.h]) AC_CHECK_TYPES(uint8) PGAC_VAR_INT_TIMEZONE +AC_C_CONST +AC_TYPE_SIZE_T +AC_STRUCT_TM + AC_CONFIG_FILES([Makefile]) AC_OUTPUT diff --git a/connection.c b/connection.c index c39fb54..324b3d9 100644 --- a/connection.c +++ b/connection.c @@ -308,7 +308,8 @@ CC_Constructor() rv->client_encoding = NULL; rv->server_encoding = NULL; rv->current_schema = NULL; - + rv->num_discardp = 0; + rv->discardp = NULL; /* Initialize statement options to defaults */ /* Statements under this conn will inherit these options */ @@ -550,8 +551,6 @@ CC_cleanup(ConnectionClass *self) /* Free cached table info */ if (self->col_info) { - int i; - for (i = 0; i < self->ntables; i++) { if (self->col_info[i]->result) /* Free the SQLColumns result structure */ @@ -565,6 +564,18 @@ CC_cleanup(ConnectionClass *self) self->col_info = NULL; } self->ntables = 0; + if (self->num_discardp > 0 && self->discardp) + { + for (i = 0; i < self->num_discardp; i++) + free(self->discardp[i]); + self->num_discardp = 0; + } + if (self->discardp) + { + free(self->discardp); + self->discardp = NULL; + } + mylog("exit CC_Cleanup\n"); return TRUE; } @@ -950,7 +961,9 @@ another_version_retry: mylog("sending an empty query...\n"); res = CC_send_query(self, " ", NULL, CLEAR_RESULT_ON_ABORT); - if (res == NULL || QR_get_status(res) != PGRES_EMPTY_QUERY) + if (res == NULL || + (QR_get_status(res) != PGRES_EMPTY_QUERY && + QR_command_nonfatal(res))) { mylog("got no result from the empty query. (probably database does not exist)\n"); CC_set_error(self, CONNECTION_NO_SUCH_DATABASE, "The database does not exist on the server\nor user authentication failed."); @@ -1086,9 +1099,11 @@ CC_remove_statement(ConnectionClass *self, StatementClass *stmt) { int i; + if (stmt->status == STMT_EXECUTING) + return FALSE; for (i = 0; i < self->num_stmts; i++) { - if (self->stmts[i] == stmt && stmt->status != STMT_EXECUTING) + if (self->stmts[i] == stmt) { self->stmts[i] = NULL; return TRUE; @@ -1221,9 +1236,14 @@ void CC_on_commit(ConnectionClass *conn) } conn->result_uncommitted = 0; CC_clear_cursors(conn, TRUE); + CC_discard_marked_plans(conn); } void CC_on_abort(ConnectionClass *conn, UDWORD opt) { + BOOL set_no_trans = FALSE; + + if (0 != (opt & CONN_DEAD)) + opt |= NO_TRANS; if (CC_is_in_trans(conn)) { #ifdef DRIVER_CURSOR_IMPLEMENT @@ -1234,8 +1254,10 @@ void CC_on_abort(ConnectionClass *conn, UDWORD opt) { CC_set_no_trans(conn); CC_set_no_manual_trans(conn); + set_no_trans = TRUE; } } + CC_clear_cursors(conn, TRUE); if (0 != (opt & CONN_DEAD)) { conn->status = CONN_DOWN; @@ -1245,8 +1267,9 @@ void CC_on_abort(ConnectionClass *conn, UDWORD opt) conn->sock = NULL; } } + else if (set_no_trans) + CC_discard_marked_plans(conn); conn->result_uncommitted = 0; - CC_clear_cursors(conn, TRUE); } /* @@ -1273,13 +1296,13 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) int maxlen, empty_reqs; BOOL msg_truncated, - ReadyToReturn, + ReadyToReturn = FALSE, query_completed = FALSE, before_64 = PG_VERSION_LT(self, 6.4), aborted = FALSE, used_passed_result_object = FALSE; UDWORD abort_opt; - int entered; + int func_cs_count = 0; /* ERROR_MSG_LENGTH is suffcient */ char msgbuffer[ERROR_MSG_LENGTH + 1]; @@ -1315,13 +1338,14 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) return NULL; } - ENTER_INNER_CONN_CS(self, entered); +#define return DONT_CALL_RETURN_FROM_HERE??? + ENTER_INNER_CONN_CS(self, func_cs_count); SOCK_put_char(sock, 'Q'); if (SOCK_get_errcode(sock) != 0) { CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query to backend"); CC_on_abort(self, NO_TRANS | CONN_DEAD); - RETURN_AFTER_LEAVE_CS(entered, self, NULL); + goto cleanup; } if (issue_begin) @@ -1333,12 +1357,11 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) { CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query to backend"); CC_on_abort(self, NO_TRANS | CONN_DEAD); - RETURN_AFTER_LEAVE_CS(entered, self, NULL); + goto cleanup; } mylog("send_query: done sending query\n"); - ReadyToReturn = FALSE; empty_reqs = 0; for (wq = query; isspace((UCHAR) *wq); wq++) ; @@ -1353,7 +1376,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) if (!cmdres) { CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query."); - RETURN_AFTER_LEAVE_CS(entered, self, NULL); + goto cleanup; } } res = cmdres; @@ -1522,7 +1545,11 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) abort_opt = NO_TRANS | CONN_DEAD; } else + { CC_set_errornumber(self, CONNECTION_SERVER_REPORTED_WARNING); + if (CC_is_in_trans(self)) + CC_set_in_error_trans(self); + } CC_on_abort(self, abort_opt); QR_set_status(res, PGRES_FATAL_ERROR); QR_set_message(res, msgbuffer); @@ -1629,6 +1656,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) } } +cleanup: + CLEANUP_FUNC_CONN_CS(func_cs_count, self); /* * Break before being ready to return. */ @@ -1677,7 +1706,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag) } } } - RETURN_AFTER_LEAVE_CS(entered, self, retres); +#undef return + return retres; } @@ -1762,6 +1792,8 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_ case 'E': SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH); CC_set_errormsg(self, msgbuffer); + if (CC_is_in_trans(self)) + CC_set_in_error_trans(self); CC_on_abort(self, 0); mylog("send_function(V): 'E' - %s\n", CC_get_errormsg(self)); @@ -2247,3 +2279,40 @@ CC_send_cancel_request(const ConnectionClass *conn) return ret; } + +int CC_mark_a_plan_to_discard(ConnectionClass *conn, const char *plan) +{ + int cnt = conn->num_discardp + 1; + char *pname; + + CC_REALLOC_return_with_error(conn->discardp, char *, + (cnt * sizeof(char *)), conn, "Couldn't alloc discardp.", -1) + CC_MALLOC_return_with_error(pname, char, (strlen(plan) + 1), + conn, "Couldn't alloc discardp mem.", -1) + strcpy(pname, plan); + conn->discardp[conn->num_discardp++] = pname; + return 1; +} +int CC_discard_marked_plans(ConnectionClass *conn) +{ + int i, cnt; + QResultClass *res; + char cmd[32]; + + if ((cnt = conn->num_discardp) <= 0) + return 0; + for (i = cnt - 1; i >= 0; i--) + { + sprintf(cmd, "DEALLOCATE \"%s\"", conn->discardp[i]); + res = CC_send_query(conn, cmd, NULL, CLEAR_RESULT_ON_ABORT); + if (res) + { + QR_Destructor(res); + free(conn->discardp[i]); + conn->num_discardp--; + } + else + return -1; + } + return 1; +} diff --git a/connection.h b/connection.h index f2e1317..5eb0023 100644 --- a/connection.h +++ b/connection.h @@ -66,6 +66,7 @@ typedef enum #define CONN_IN_AUTOCOMMIT 1L #define CONN_IN_TRANSACTION (1L<<1) #define CONN_IN_MANUAL_TRANSACTION (1L<<2) +#define CONN_IN_ERROR_BEFORE_IDLE (1L<<3) /* AutoCommit functions */ #define CC_set_autocommit_off(x) (x->transact_status &= ~CONN_IN_AUTOCOMMIT) @@ -74,7 +75,7 @@ typedef enum /* Transaction in/not functions */ #define CC_set_in_trans(x) (x->transact_status |= CONN_IN_TRANSACTION) -#define CC_set_no_trans(x) (x->transact_status &= ~CONN_IN_TRANSACTION) +#define CC_set_no_trans(x) (x->transact_status &= ~(CONN_IN_TRANSACTION | CONN_IN_ERROR_BEFORE_IDLE)) #define CC_is_in_trans(x) (x->transact_status & CONN_IN_TRANSACTION) /* Manual transaction in/not functions */ @@ -82,16 +83,38 @@ typedef enum #define CC_set_no_manual_trans(x) (x->transact_status &= ~CONN_IN_MANUAL_TRANSACTION) #define CC_is_in_manual_trans(x) (x->transact_status & CONN_IN_MANUAL_TRANSACTION) +/* Error waiting for ROLLBACK */ +#define CC_set_in_error_trans(x) (x->transact_status |= CONN_IN_ERROR_BEFORE_IDLE) +#define CC_set_no_error_trans(x) (x->transact_status &= ~CONN_IN_ERROR_BEFORE_IDLE) +#define CC_is_in_error_trans(x) (x->transact_status & CONN_IN_ERROR_BEFORE_IDLE) + #define CC_get_errornumber(x) (x->__error_number) #define CC_get_errormsg(x) (x->__error_message) #define CC_set_errornumber(x, n) (x->__error_number = n) +#define CC_MALLOC_return_with_error(t, tp, s, x, m, ret) \ + { \ + if (t = malloc(s), NULL == t) \ + { \ + CC_set_error(x, CONN_NO_MEMORY_ERROR, m); \ + return ret; \ + } \ + } +#define CC_REALLOC_return_with_error(t, tp, s, x, m, ret) \ + { \ + if (t = (tp *) realloc(t, s), NULL == t) \ + { \ + CC_set_error(x, CONN_NO_MEMORY_ERROR, m); \ + return ret; \ + } \ + } + /* For Multi-thread */ #if defined(WIN_MULTITHREAD_SUPPORT) #define INIT_CONN_CS(x) InitializeCriticalSection(&((x)->cs)) #define ENTER_CONN_CS(x) EnterCriticalSection(&((x)->cs)) #define ENTER_INNER_CONN_CS(x, entered) \ - { EnterCriticalSection(&((x)->cs)); entered = 1; } + { EnterCriticalSection(&((x)->cs)); entered++; } #define LEAVE_CONN_CS(x) LeaveCriticalSection(&((x)->cs)) #define DELETE_CONN_CS(x) DeleteCriticalSection(&((x)->cs)) #elif defined(POSIX_THREADMUTEX_SUPPORT) @@ -102,27 +125,37 @@ typedef enum if (getMutexAttr()) \ { \ if (pthread_mutex_lock(&((x)->cs)) == 0) \ - entered = 1; \ + entered++; \ else \ - entered = -1; \ + -1; \ } \ else \ - entered = 0; \ + 0; \ } #define LEAVE_CONN_CS(x) pthread_mutex_unlock(&((x)->cs)) #define DELETE_CONN_CS(x) pthread_mutex_destroy(&((x)->cs)) #else #define INIT_CONN_CS(x) #define ENTER_CONN_CS(x) -#define ENTER_INNER_CONN_CS(x, entered) {entered = 0;} +#define ENTER_INNER_CONN_CS(x, entered) (0) #define LEAVE_CONN_CS(x) #define DELETE_CONN_CS(x) #endif /* WIN_MULTITHREAD_SUPPORT */ #define LEAVE_INNER_CONN_CS(entered, conn) \ - { if (entered > 0) LEAVE_CONN_CS(conn); } -#define RETURN_AFTER_LEAVE_CS(entered, conn, ret) \ - { if (entered > 0) LEAVE_CONN_CS(conn); return ret; } + { \ + if (entered > 0) \ + { \ + LEAVE_CONN_CS(conn); \ + entered--; \ + } \ + } +#define CLEANUP_FUNC_CONN_CS(entered, conn) \ + while (entered > 0) \ + { \ + LEAVE_CONN_CS(conn); \ + entered--; \ + } /* Authentication types */ #define AUTH_REQ_OK 0 @@ -351,6 +384,8 @@ struct ConnectionClass_ int be_key; /* auth code needed to send cancel */ UInt4 isolation; char *current_schema; + int num_discardp; + char **discardp; #if (ODBCVER >= 0x0300) int num_descs; DescriptorClass **descs; @@ -412,6 +447,8 @@ void CC_on_commit(ConnectionClass *conn); void CC_on_abort(ConnectionClass *conn, UDWORD opt); void ProcessRollback(ConnectionClass *conn, BOOL undo); const char *CC_get_current_schema(ConnectionClass *conn); +int CC_mark_a_plan_to_discard(ConnectionClass *conn, const char *plannm); +int CC_discard_marked_plans(ConnectionClass *conn); /* CC_send_query options */ #define CLEAR_RESULT_ON_ABORT 1L diff --git a/convert.c b/convert.c index c9e61bf..5332be1 100644 --- a/convert.c +++ b/convert.c @@ -156,6 +156,17 @@ static int pg_bin2hex(UCHAR *src, UCHAR *dst, int length); */ +/* + * Macros for unsigned long handling. + */ +#ifdef WIN32 +#define ATOI32U atol +#elif defined(HAVE_STRTOUL) +#define ATOI32U(val) strtoul(val, NULL, 10) +#else /* HAVE_STRTOUL */ +#define ATOI32U atol +#endif /* WIN32 */ + /* * Macros for BIGINT handling. */ @@ -186,7 +197,7 @@ timestamp2stime(const char *str, SIMPLE_TIME *st, BOOL *bZone, int *zone) *ptr; int scnt, i; -#if defined(WIN32) || defined(HAVE_INT_TIMEZONE) +#ifdef TIMEZONE_GLOBAL long timediff; #endif BOOL withZone = *bZone; @@ -195,7 +206,8 @@ timestamp2stime(const char *str, SIMPLE_TIME *st, BOOL *bZone, int *zone) *zone = 0; st->fr = 0; st->infinity = 0; - if ((scnt = sscanf(str, "%4d-%2d-%2d %2d:%2d:%2d%s", &st->y, &st->m, &st->d, &st->hh, &st->mm, &st->ss, rest)) < 6) + rest[0] = '\0'; + if ((scnt = sscanf(str, "%4d-%2d-%2d %2d:%2d:%2d%32s", &st->y, &st->m, &st->d, &st->hh, &st->mm, &st->ss, rest)) < 6) return FALSE; else if (scnt == 6) return TRUE; @@ -237,7 +249,7 @@ timestamp2stime(const char *str, SIMPLE_TIME *st, BOOL *bZone, int *zone) } if (!withZone || !*bZone || st->y < 1970) return TRUE; -#if defined(WIN32) || defined(HAVE_INT_TIMEZONE) +#ifdef TIMEZONE_GLOBAL if (!tzname[0] || !tzname[0][0]) { *bZone = FALSE; @@ -283,7 +295,7 @@ timestamp2stime(const char *str, SIMPLE_TIME *st, BOOL *bZone, int *zone) *bZone = TRUE; } } -#endif /* WIN32 */ +#endif /* TIMEZONE_GLOBAL */ return TRUE; } @@ -316,7 +328,7 @@ stime2timestamp(const SIMPLE_TIME *st, char *str, BOOL bZone, BOOL precision) } } zonestr[0] = '\0'; -#if defined(WIN32) || defined(HAVE_INT_TIMEZONE) +#ifdef TIMEZONE_GLOBAL if (bZone && tzname[0] && tzname[0][0] && st->y >= 1970) { long zoneint; @@ -342,7 +354,7 @@ stime2timestamp(const SIMPLE_TIME *st, char *str, BOOL bZone, BOOL precision) else sprintf(zonestr, "+%02d", -(int) zoneint / 3600); } -#endif /* WIN32 */ +#endif /* TIMEZONE_GLOBAL */ sprintf(str, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d%s%s", st->y, st->m, st->d, st->hh, st->mm, st->ss, precstr, zonestr); return TRUE; } @@ -853,8 +865,16 @@ inolog("2stime fr=%d\n", std_time.fr); if (cbValueMax > 0) { - copy_len = (len >= cbValueMax) ? cbValueMax - 1 : len; + BOOL already_copied = FALSE; + copy_len = (len >= cbValueMax) ? cbValueMax - 1 : len; +#ifdef WIN_UNICODE_SUPPORT + if (fCType == SQL_C_WCHAR) + { + copy_len /= 2; + copy_len *= 2; + } +#endif /* WIN_UNICODE_SUPPORT */ #ifdef HAVE_LOCALE_H switch (field_type) { @@ -866,7 +886,7 @@ inolog("2stime fr=%d\n", std_time.fr); char *new_string; int i, j; - new_string = malloc( cbValueMax ); + new_string = malloc(cbValueMax); lc = localeconv(); for (i = 0, j = 0; ptr[i]; i++) if (ptr[i] == '.') @@ -879,17 +899,21 @@ inolog("2stime fr=%d\n", std_time.fr); new_string[j] = '\0'; strncpy_null(rgbValueBindRow, new_string, copy_len + 1); free(new_string); + already_copied = TRUE; break; } - default: - /* Copy the data */ - strncpy_null(rgbValueBindRow, ptr, copy_len + 1); - } -#else /* HAVE_LOCALE_H */ - /* Copy the data */ - memcpy(rgbValueBindRow, ptr, copy_len); - rgbValueBindRow[copy_len] = '\0'; + } #endif /* HAVE_LOCALE_H */ + if (!already_copied) + { + /* Copy the data */ + memcpy(rgbValueBindRow, ptr, copy_len); + rgbValueBindRow[copy_len] = '\0'; + } +#ifdef WIN_UNICODE_SUPPORT + if (fCType == SQL_C_WCHAR) + rgbValueBindRow[copy_len + 1] = '\0'; +#endif /* WIN_UNICODE_SUPPORT */ /* Adjust data_left for next time */ if (stmt->current_col >= 0) @@ -1192,9 +1216,9 @@ inolog("2stime fr=%d\n", std_time.fr); case SQL_C_ULONG: len = 4; if (bind_size > 0) - *((UDWORD *) rgbValueBindRow) = atol(neut_str); + *((UDWORD *) rgbValueBindRow) = ATOI32U(neut_str); else - *((UDWORD *) rgbValue + bind_row) = atol(neut_str); + *((UDWORD *) rgbValue + bind_row) = ATOI32U(neut_str); break; #if (ODBCVER >= 0x0300) && defined(ODBCINT64) @@ -1242,7 +1266,7 @@ inolog("2stime fr=%d\n", std_time.fr); /* The following is for SQL_C_VARBOOKMARK */ else if (PG_TYPE_INT4 == field_type) { - UInt4 ival = atol(neut_str); + UInt4 ival = ATOI32U(neut_str); inolog("SQL_C_VARBOOKMARK value=%d\n", ival); if (pcbValue) @@ -1818,7 +1842,7 @@ Prepare_and_convert(StatementClass *stmt, QueryParse *qp, QueryBuild *qb) new_statement = qb->query_statement; qb->flags = FLGB_BUILDING_PREPARE_STATEMENT; - sprintf(new_statement, "PREPARE _PLAN%0x", stmt); + sprintf(new_statement, "PREPARE \"_PLAN%0x\"", stmt); qb->npos = strlen(new_statement); if (SQL_SUCCESS != PGAPI_NumParams(stmt, &marker_count)) { @@ -1854,7 +1878,7 @@ Prepare_and_convert(StatementClass *stmt, QueryParse *qp, QueryBuild *qb) CVT_APPEND_CHAR(qb, ';'); /* build the execute statement */ exe_statement = malloc(30 + 2 * marker_count); - sprintf(exe_statement, "EXECUTE _PLAN%0x", stmt); + sprintf(exe_statement, "EXECUTE \"_PLAN%0x\"", stmt); if (marker_count > 0) { elen = strlen(exe_statement); @@ -2410,7 +2434,9 @@ ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform) newlen = 0; if (0 == ns->sign) chrform[newlen++] = '-'; - for (i = len - 1; i >= ns->scale; i--) + if (i = len - 1, i < ns->scale) + i = ns->scale; + for (; i >= ns->scale; i--) chrform[newlen++] = calv[i] + '0'; if (ns->scale > 0) { @@ -3875,7 +3901,7 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue, } } - oid = atoi(value); + oid = ATOI32U(value); stmt->lobj_fd = lo_open(conn, oid, INV_READ); if (stmt->lobj_fd < 0) { diff --git a/dlg_specific.c b/dlg_specific.c index 9627a30..0845161 100644 --- a/dlg_specific.c +++ b/dlg_specific.c @@ -140,6 +140,8 @@ makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len) flag |= BIT_PROTOCOL_64; else if (strncmp(ci->protocol, PG63, strlen(PG63)) == 0) flag |= BIT_PROTOCOL_63; + else if (strncmp(ci->protocol, "7.4", 3) == 0) + flag |= (BIT_PROTOCOL_63 | BIT_PROTOCOL_64); switch (ci->drivers.unknown_sizes) { case UNKNOWNS_AS_DONTKNOW: diff --git a/execute.c b/execute.c index 5024368..2e1933d 100644 --- a/execute.c +++ b/execute.c @@ -140,7 +140,7 @@ PGAPI_ExecDirect( mylog("%s: entering...\n", func); - if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result) + if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result) return result; /* diff --git a/info.c b/info.c index 107de75..e0676d5 100644 --- a/info.c +++ b/info.c @@ -801,7 +801,7 @@ PGAPI_GetTypeInfo( mylog("%s: entering...fSqlType = %d\n", func, fSqlType); - if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result) + if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result) return result; stmt->manual_result = TRUE; @@ -855,7 +855,8 @@ PGAPI_GetTypeInfo( for (cnt = 0; cnt < pgtcount; cnt ++) { - row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) * sizeof(TupleField)); + SC_MALLOC_return_with_error(row, TupleNode, (sizeof(TupleNode) + (result_cols - 1) * sizeof(TupleField)), + stmt, "Couldn't alloc row", SQL_ERROR) /* These values can't be NULL */ if (1 == cnt) @@ -895,8 +896,8 @@ inolog("serial in\n"); set_nullfield_int2(&row->tuple[9], pgtype_unsigned(stmt, pgType)); set_nullfield_int2(&row->tuple[11], pgtype_auto_increment(stmt, pgType)); } - set_nullfield_int2(&row->tuple[13], pgtype_scale(stmt, pgType, PG_STATIC)); - set_nullfield_int2(&row->tuple[14], pgtype_scale(stmt, pgType, PG_STATIC)); + set_nullfield_int2(&row->tuple[13], pgtype_min_decimal_digits(stmt, pgType)); + set_nullfield_int2(&row->tuple[14], pgtype_max_decimal_digits(stmt, pgType)); #if (ODBCVER >=0x0300) set_nullfield_int2(&row->tuple[15], pgtype_to_sqldesctype(stmt, pgType, PG_STATIC)); set_nullfield_int2(&row->tuple[16], pgtype_to_datetime_sub(stmt, pgType)); @@ -1293,7 +1294,7 @@ PGAPI_Tables( QResultClass *res; TupleNode *row; HSTMT htbl_stmt; - RETCODE result; + RETCODE ret = SQL_ERROR, result; char *tableType; char tables_query[INFO_INQUIRY_LEN]; char table_name[MAX_INFO_STRING], @@ -1320,7 +1321,7 @@ PGAPI_Tables( mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner); - if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result) + if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result) return result; stmt->manual_result = TRUE; @@ -1345,24 +1346,27 @@ PGAPI_Tables( { /* view is represented by its relkind since 7.1 */ strcpy(tables_query, "select relname, nspname, relkind" - " from pg_catalog.pg_class, pg_catalog.pg_namespace"); + " from pg_catalog.pg_class c, pg_catalog.pg_namespace n"); 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"); + " from pg_class c, pg_user u"); strcat(tables_query, " where relkind in ('r', 'v')"); } else { - strcpy(tables_query, "select relname, usename, relhasrules from pg_class, pg_user"); + strcpy(tables_query, "select relname, usename, relhasrules from pg_class c, pg_user u"); strcat(tables_query, " where relkind = 'r'"); } if (conn->schema_support) + { schema_strcat1(tables_query, " and nspname %s '%.*s'", likeeq, szTableOwner, cbTableOwner, szTableName, cbTableName, conn); + strcat(tables_query, " and pg_catalog.pg_table_is_visible(c.oid)"); + } else my_strcat1(tables_query, " and usename %s '%.*s'", likeeq, szTableOwner, cbTableOwner); my_strcat1(tables_query, " and relname %s '%.*s'", likeeq, szTableName, cbTableName); @@ -1457,7 +1461,7 @@ PGAPI_Tables( strcat(tables_query, " and relname !~ '^xinv[0-9]+'"); if (conn->schema_support) - strcat(tables_query, " and pg_namespace.oid = relnamespace order by nspname, relname"); + strcat(tables_query, " and n.oid = relnamespace order by nspname, relname"); else strcat(tables_query, " and usesysid = relowner order by relname"); @@ -1465,9 +1469,7 @@ PGAPI_Tables( if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_full_error_copy(stmt, htbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } #ifdef UNICODE_SUPPORT @@ -1479,9 +1481,7 @@ PGAPI_Tables( if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 2, internal_asis_type, @@ -1489,26 +1489,20 @@ PGAPI_Tables( if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type, relkind_or_hasrules, MAX_INFO_STRING, NULL); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } if (res = QR_Constructor(), !res) { SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Tables result."); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } SC_set_Result(stmt, res); @@ -1580,7 +1574,7 @@ PGAPI_Tables( (view && show_views) || (regular_table && show_regular_tables)) { - row = (TupleNode *) malloc(sizeof(TupleNode) + (5 - 1) *sizeof(TupleField)); + SC_MALLOC_return_with_error(row, TupleNode, (sizeof(TupleNode) + (5 - 1) * sizeof(TupleField)), stmt, "Couldn't alloc row", SQL_ERROR) /*set_tuplefield_string(&row->tuple[0], "");*/ set_tuplefield_null(&row->tuple[0]); @@ -1612,25 +1606,29 @@ PGAPI_Tables( if (result != SQL_NO_DATA_FOUND) { SC_full_error_copy(stmt, htbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } + ret = SQL_SUCCESS; +cleanup: /* * also, things need to think that this statement is finished so the * results can be retrieved. */ stmt->status = STMT_FINISHED; + if (SQL_ERROR == ret) + SC_log_error(func, "", stmt); /* set up the current tuple pointer for SQLFetch */ stmt->currTuple = -1; stmt->rowset_start = -1; SC_set_current_col(stmt, -1); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - mylog("%s: EXIT, stmt=%u\n", func, stmt); - return SQL_SUCCESS; + if (htbl_stmt) + PGAPI_FreeStmt(htbl_stmt, SQL_DROP); + + mylog("%s: EXIT, stmt=%u, ret=%d\n", func, stmt, ret); + return ret; } @@ -1717,7 +1715,7 @@ PGAPI_Columns( table_name[MAX_INFO_STRING], field_name[MAX_INFO_STRING], field_type_name[MAX_INFO_STRING]; - Int2 field_number, sqltype, + Int2 field_number, sqltype, concise_type, reserved_cols, result_cols, decimal_digits; @@ -1727,7 +1725,7 @@ PGAPI_Columns( mod_length, column_size, ordinal; - char useStaticPrecision; + char useStaticPrecision, useStaticScale; char not_null[MAX_INFO_STRING], relhasrules[MAX_INFO_STRING], relkind[8]; BOOL relisaview; @@ -1738,7 +1736,7 @@ PGAPI_Columns( mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner); - if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result) + if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result) return result; stmt->manual_result = TRUE; @@ -2012,8 +2010,9 @@ PGAPI_Columns( { /* For OID fields */ the_type = PG_TYPE_OID; - row = (TupleNode *) malloc(sizeof(TupleNode) + - (result_cols - 1) *sizeof(TupleField)); + SC_MALLOC_return_with_error(row, TupleNode, + (sizeof(TupleNode) + (result_cols - 1) * sizeof(TupleField)), + stmt, "Couldn't alloc row", SQL_ERROR) set_tuplefield_string(&row->tuple[0], ""); /* see note in SQLTables() */ @@ -2052,9 +2051,9 @@ PGAPI_Columns( while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) { - row = (TupleNode *) malloc(sizeof(TupleNode) + - (result_cols - 1) *sizeof(TupleField)); - + SC_MALLOC_return_with_error(row, TupleNode, + (sizeof(TupleNode) + (result_cols - 1) * sizeof(TupleField)), + stmt, "Couldn't alloc row", SQL_ERROR) sqltype = SQL_TYPE_NULL; /* unspecified */ set_tuplefield_string(&row->tuple[0], ""); @@ -2065,8 +2064,6 @@ PGAPI_Columns( 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, -1); - set_tuplefield_int2(&row->tuple[4], sqltype); set_tuplefield_string(&row->tuple[5], field_type_name); @@ -2087,6 +2084,7 @@ PGAPI_Columns( table_name, field_name, field_type, field_type_name); useStaticPrecision = TRUE; + useStaticScale = TRUE; if (field_type == PG_TYPE_NUMERIC) { @@ -2096,6 +2094,7 @@ PGAPI_Columns( if (mod_length >= 0) { useStaticPrecision = FALSE; + useStaticScale = FALSE; column_size = (mod_length >> 16) & 0xffff; decimal_digits = mod_length & 0xffff; @@ -2111,6 +2110,16 @@ PGAPI_Columns( set_tuplefield_int4(&row->tuple[reserved_cols], column_size + 2); /* sign+dec.point */ } } + else if ((field_type == PG_TYPE_DATETIME) || + (field_type == PG_TYPE_TIMESTAMP_NO_TMZONE)) + { + if (PG_VERSION_GE(conn, 7.2)) + { + useStaticScale = FALSE; + + set_nullfield_int2(&row->tuple[8], (Int2) mod_length); + } + } if ((field_type == PG_TYPE_VARCHAR) || (field_type == PG_TYPE_BPCHAR)) @@ -2132,8 +2141,6 @@ PGAPI_Columns( set_tuplefield_int4(&row->tuple[6], mod_length); set_tuplefield_int4(&row->tuple[7], mod_length); - set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, field_type, PG_STATIC)); - set_tuplefield_int2(&row->tuple[13], sqltype); #if (ODBCVER >= 0x0300) set_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, field_type, PG_STATIC, PG_STATIC)); #endif /* ODBCVER */ @@ -2146,18 +2153,23 @@ PGAPI_Columns( set_tuplefield_int4(&row->tuple[6], pgtype_column_size(stmt, field_type, PG_STATIC, PG_STATIC)); set_tuplefield_int4(&row->tuple[7], pgtype_buffer_length(stmt, field_type, PG_STATIC, PG_STATIC)); - set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, field_type, PG_STATIC)); #if (ODBCVER >= 0x0300) set_tuplefield_null(&row->tuple[15]); #endif /* ODBCVER */ set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, field_type, PG_STATIC, PG_STATIC)); } + if (useStaticScale) + { + set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, field_type, PG_STATIC)); + } if (SQL_TYPE_NULL == sqltype) { sqltype = pgtype_to_concise_type(stmt, field_type, PG_STATIC); - set_tuplefield_int2(&row->tuple[13], pgtype_to_sqldesctype(stmt, field_type, PG_STATIC)); + concise_type = pgtype_to_sqldesctype(stmt, field_type, PG_STATIC); } + else + concise_type = sqltype; set_tuplefield_int2(&row->tuple[4], sqltype); set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, field_type)); @@ -2165,6 +2177,7 @@ PGAPI_Columns( set_tuplefield_string(&row->tuple[11], ""); #if (ODBCVER >= 0x0300) set_tuplefield_null(&row->tuple[12]); + set_tuplefield_int2(&row->tuple[13], concise_type); set_nullfield_int2(&row->tuple[14], pgtype_to_datetime_sub(stmt, field_type)); set_tuplefield_int4(&row->tuple[16], ordinal); set_tuplefield_null(&row->tuple[17]); @@ -2194,8 +2207,8 @@ PGAPI_Columns( /* For Row Versioning fields */ the_type = PG_TYPE_INT4; - row = (TupleNode *) malloc(sizeof(TupleNode) + - (result_cols - 1) *sizeof(TupleField)); + SC_MALLOC_return_with_error(row, TupleNode, (sizeof(TupleNode) + (result_cols - 1) * sizeof(TupleField)), + stmt, "Couldn't alloc row", SQL_ERROR) set_tuplefield_string(&row->tuple[0], ""); if (conn->schema_support) @@ -2274,7 +2287,7 @@ PGAPI_SpecialColumns( mylog("%s: entering...stmt=%u scnm=%x len=%d colType=%d\n", func, stmt, szTableOwner, cbTableOwner, fColType); - if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result) + if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result) return result; conn = SC_get_conn(stmt); ci = &(conn->connInfo); @@ -2393,7 +2406,8 @@ PGAPI_SpecialColumns( { Int2 the_type = PG_TYPE_TID; - row = (TupleNode *) malloc(sizeof(TupleNode) + (8 - 1) *sizeof(TupleField)); + SC_MALLOC_return_with_error(row, TupleNode, (sizeof(TupleNode) + (8 - 1) * sizeof(TupleField)), + stmt, "Couldn't alloc row", SQL_ERROR) set_tuplefield_null(&row->tuple[0]); set_tuplefield_string(&row->tuple[1], "ctid"); @@ -2415,7 +2429,8 @@ inolog("Add ctid\n"); { if (relhasoids[0] != '1') return SQL_NO_DATA_FOUND; - row = (TupleNode *) malloc(sizeof(TupleNode) + (8 - 1) *sizeof(TupleField)); + SC_MALLOC_return_with_error(row, TupleNode, (sizeof(TupleNode) + (8 - 1) *sizeof(TupleField)), + stmt, "Couldn't alloc row", SQL_ERROR) set_tuplefield_int2(&row->tuple[0], SQL_SCOPE_SESSION); set_tuplefield_string(&row->tuple[1], "oid"); @@ -2435,7 +2450,9 @@ inolog("Add ctid\n"); if (atoi(ci->row_versioning)) { - row = (TupleNode *) malloc(sizeof(TupleNode) + (8 - 1) *sizeof(TupleField)); + SC_MALLOC_return_with_error(row, TupleNode, + (sizeof(TupleNode) + (8 - 1) * sizeof(TupleField)), + stmt, "Couldn't alloc row", SQL_ERROR) set_tuplefield_null(&row->tuple[0]); set_tuplefield_string(&row->tuple[1], "xmin"); @@ -2478,9 +2495,9 @@ PGAPI_Statistics( ConnectionClass *conn; QResultClass *res; char index_query[INFO_INQUIRY_LEN]; - HSTMT hindx_stmt; - RETCODE result; - char *table_name; + HSTMT hcol_stmt = NULL, hindx_stmt = NULL; + RETCODE ret = SQL_ERROR, result; + char *table_name = NULL; char index_name[MAX_INFO_STRING]; short fields_vector[INDEX_KEYS_STORAGE_COUNT]; char isunique[10], @@ -2490,23 +2507,21 @@ PGAPI_Statistics( fields_vector_len; TupleNode *row; int i; - HSTMT hcol_stmt; StatementClass *col_stmt, *indx_stmt; char column_name[MAX_INFO_STRING], table_qualifier[MAX_INFO_STRING], relhasrules[10], relkind[8]; - char **column_names = 0; + char **column_names = NULL; SQLINTEGER column_name_len; int total_columns = 0; - char error = TRUE; ConnInfo *ci; char buf[256]; SWORD internal_asis_type = SQL_C_CHAR; mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner); - if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result) + if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result) return result; stmt->manual_result = TRUE; @@ -2574,7 +2589,7 @@ PGAPI_Statistics( if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in PGAPI_Statistics for columns."); - goto SEEYA; + goto cleanup; } col_stmt = (StatementClass *) hcol_stmt; @@ -2594,16 +2609,14 @@ PGAPI_Statistics( if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, col_stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - goto SEEYA; + goto cleanup; } result = PGAPI_BindCol(hcol_stmt, 4, internal_asis_type, column_name, sizeof(column_name), &column_name_len); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, col_stmt); - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - goto SEEYA; + goto cleanup; } @@ -2615,8 +2628,9 @@ PGAPI_Statistics( column_names = (char **) realloc(column_names, total_columns * sizeof(char *)); - column_names[total_columns - 1] = - (char *) malloc(strlen(column_name) + 1); + SC_MALLOC_return_with_error(column_names[total_columns - 1], + char, (strlen(column_name) + 1), stmt, + "Couldn't alloc column_name", SQL_ERROR) strcpy(column_names[total_columns - 1], column_name); mylog("%s: column_name = '%s'\n", func, column_name); @@ -2624,24 +2638,26 @@ PGAPI_Statistics( result = PGAPI_Fetch(hcol_stmt); } - if (result != SQL_NO_DATA_FOUND || total_columns == 0) + PGAPI_FreeStmt(hcol_stmt, SQL_DROP); + hcol_stmt = NULL; + if (result != SQL_NO_DATA_FOUND) { - SC_full_error_copy(stmt, col_stmt); /* "Couldn't get column - * names in - * SQLStatistics."; */ - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - goto SEEYA; - + SC_full_error_copy(stmt, col_stmt); + goto cleanup; + } + if (total_columns == 0) + { + /* Couldn't get column names in SQLStatistics.; */ + ret = SQL_SUCCESS; + goto cleanup; } - - PGAPI_FreeStmt(hcol_stmt, SQL_DROP); /* get a list of indexes on this table */ result = PGAPI_AllocStmt(stmt->hdbc, &hindx_stmt); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in SQLStatistics for indices."); - goto SEEYA; + goto cleanup; } indx_stmt = (StatementClass *) hindx_stmt; @@ -2683,8 +2699,7 @@ PGAPI_Statistics( * SQLStatistics."; */ SC_full_error_copy(stmt, indx_stmt); - PGAPI_FreeStmt(hindx_stmt, SQL_DROP); - goto SEEYA; + goto cleanup; } /* bind the index name column */ @@ -2694,8 +2709,7 @@ PGAPI_Statistics( { SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column * in SQLStatistics."; */ - PGAPI_FreeStmt(hindx_stmt, SQL_DROP); - goto SEEYA; + goto cleanup; } /* bind the vector column */ @@ -2705,8 +2719,7 @@ PGAPI_Statistics( { SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column * in SQLStatistics."; */ - PGAPI_FreeStmt(hindx_stmt, SQL_DROP); - goto SEEYA; + goto cleanup; } /* bind the "is unique" column */ @@ -2716,8 +2729,7 @@ PGAPI_Statistics( { SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column * in SQLStatistics."; */ - PGAPI_FreeStmt(hindx_stmt, SQL_DROP); - goto SEEYA; + goto cleanup; } /* bind the "is clustered" column */ @@ -2727,8 +2739,7 @@ PGAPI_Statistics( { SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column * * in SQLStatistics."; */ - PGAPI_FreeStmt(hindx_stmt, SQL_DROP); - goto SEEYA; + goto cleanup; } @@ -2739,8 +2750,7 @@ PGAPI_Statistics( { SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column * * in SQLStatistics."; */ - PGAPI_FreeStmt(hindx_stmt, SQL_DROP); - goto SEEYA; + goto cleanup; } @@ -2749,8 +2759,7 @@ PGAPI_Statistics( if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, indx_stmt); - PGAPI_FreeStmt(hindx_stmt, SQL_DROP); - goto SEEYA; + goto cleanup; } relhasrules[0] = '0'; @@ -2860,41 +2869,50 @@ PGAPI_Statistics( { /* "SQLFetch failed in SQLStatistics."; */ SC_full_error_copy(stmt, indx_stmt); - PGAPI_FreeStmt(hindx_stmt, SQL_DROP); - goto SEEYA; + goto cleanup; } - PGAPI_FreeStmt(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->rowset_start = -1; - SC_set_current_col(stmt, -1); + ret = SQL_SUCCESS; - error = FALSE; +cleanup: + /* + * also, things need to think that this statement is finished so the + * results can be retrieved. + */ + stmt->status = STMT_FINISHED; -SEEYA: + if (SQL_ERROR == ret) + SC_log_error(func, "", stmt); + if (hcol_stmt) + PGAPI_FreeStmt(hcol_stmt, SQL_DROP); + if (hindx_stmt) + PGAPI_FreeStmt(hindx_stmt, SQL_DROP); /* These things should be freed on any error ALSO! */ - free(table_name); - for (i = 0; i < total_columns; i++) - free(column_names[i]); - free(column_names); - - mylog("%s: EXIT, %s, stmt=%u\n", func, error ? "error" : "success", stmt); + if (table_name) + free(table_name); + if (column_names) + { + for (i = 0; i < total_columns; i++) + free(column_names[i]); + free(column_names); + } - if (error) + if (SQL_SUCCESS == ret) { - SC_log_error(func, "", stmt); - return SQL_ERROR; + /* set up the current tuple pointer for SQLFetch */ + stmt->currTuple = -1; + stmt->rowset_start = -1; + SC_set_current_col(stmt, -1); } - else - return SQL_SUCCESS; + mylog("%s: EXIT, stmt=%u, ret=%d\n", func, stmt, ret); + + return ret; } @@ -2918,7 +2936,7 @@ PGAPI_ColumnPrivileges( /* Neither Access or Borland care about this. */ - if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result) + if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result) return result; SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "not implemented"); SC_log_error(func, "Function not implemented", stmt); @@ -2946,9 +2964,9 @@ PGAPI_PrimaryKeys( QResultClass *res; ConnectionClass *conn; TupleNode *row; - RETCODE result; + RETCODE ret = SQL_ERROR, result; int seq = 0; - HSTMT htbl_stmt; + HSTMT htbl_stmt = NULL; StatementClass *tbl_stmt; char tables_query[INFO_INQUIRY_LEN]; char attname[MAX_INFO_STRING]; @@ -2962,7 +2980,7 @@ PGAPI_PrimaryKeys( mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner); - if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result) + if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result) return result; stmt->manual_result = TRUE; stmt->errormsg_created = TRUE; @@ -3013,9 +3031,7 @@ PGAPI_PrimaryKeys( if (pktab[0] == '\0') { SC_set_error(stmt, STMT_INTERNAL_ERROR, "No Table specified to PGAPI_PrimaryKeys."); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } pkscm[0] = '\0'; if (conn->schema_support) @@ -3026,9 +3042,7 @@ PGAPI_PrimaryKeys( if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } if (PG_VERSION_LE(conn, 6.4)) @@ -3111,9 +3125,7 @@ PGAPI_PrimaryKeys( if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_full_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_Fetch(htbl_stmt); @@ -3149,27 +3161,29 @@ PGAPI_PrimaryKeys( if (result != SQL_NO_DATA_FOUND) { SC_full_error_copy(stmt, htbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } + ret = SQL_SUCCESS; - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - - +cleanup: /* * also, things need to think that this statement is finished so the * results can be retrieved. */ stmt->status = STMT_FINISHED; + if (SQL_ERROR == ret) + SC_log_error(func, "", stmt); + if (htbl_stmt) + PGAPI_FreeStmt(htbl_stmt, SQL_DROP); + /* set up the current tuple pointer for SQLFetch */ stmt->currTuple = -1; stmt->rowset_start = -1; SC_set_current_col(stmt, -1); - mylog("%s: EXIT, stmt=%u\n", func, stmt); - return SQL_SUCCESS; + mylog("%s: EXIT, stmt=%u, ret=%d\n", func, stmt, ret); + return ret; } @@ -3423,11 +3437,9 @@ PGAPI_ForeignKeys( StatementClass *stmt = (StatementClass *) hstmt; QResultClass *res; TupleNode *row; - HSTMT htbl_stmt, - hpkey_stmt; + HSTMT htbl_stmt = NULL, hpkey_stmt = NULL; StatementClass *tbl_stmt; - RETCODE result, - keyresult; + RETCODE ret = SQL_ERROR, result, keyresult; char tables_query[INFO_INQUIRY_LEN]; char trig_deferrable[2]; char trig_initdeferred[2]; @@ -3466,7 +3478,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; mylog("%s: entering...stmt=%u\n", func, stmt); - if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result) + if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result) return result; stmt->manual_result = TRUE; @@ -3641,9 +3653,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_full_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 1, SQL_C_BINARY, @@ -3651,9 +3661,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 2, SQL_C_SHORT, @@ -3661,9 +3669,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type, @@ -3671,9 +3677,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 4, internal_asis_type, @@ -3681,9 +3685,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 5, internal_asis_type, @@ -3691,9 +3693,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 6, internal_asis_type, @@ -3701,9 +3701,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 7, SQL_C_ULONG, @@ -3711,27 +3709,21 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 8, SQL_C_ULONG, &relid2, sizeof(relid2), NULL); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 9, internal_asis_type, pk_table_fetched, TABLE_NAME_STORAGE_LEN, NULL); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } if (conn->schema_support) @@ -3741,30 +3733,28 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } } result = PGAPI_Fetch(htbl_stmt); if (result == SQL_NO_DATA_FOUND) - return SQL_SUCCESS; + { + ret = SQL_SUCCESS; + goto cleanup; + } if (result != SQL_SUCCESS) { SC_full_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } keyresult = PGAPI_AllocStmt(stmt->hdbc, &hpkey_stmt); if ((keyresult != SQL_SUCCESS) && (keyresult != SQL_SUCCESS_WITH_INFO)) { SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result."); - SC_log_error(func, "", stmt); - return SQL_ERROR; + goto cleanup; } keyresult = PGAPI_BindCol(hpkey_stmt, 4, internal_asis_type, @@ -3772,9 +3762,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if (keyresult != SQL_SUCCESS) { SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result."); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(hpkey_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } while (result == SQL_SUCCESS) @@ -3799,9 +3787,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if (keyresult != SQL_SUCCESS) { SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't get primary keys for PGAPI_ForeignKeys result."); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(hpkey_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } @@ -3925,6 +3911,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; result = PGAPI_Fetch(htbl_stmt); } PGAPI_FreeStmt(hpkey_stmt, SQL_DROP); + hpkey_stmt = NULL; } /* @@ -4014,9 +4001,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 1, SQL_C_BINARY, @@ -4024,9 +4009,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 2, SQL_C_SHORT, @@ -4034,9 +4017,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type, @@ -4044,9 +4025,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 4, internal_asis_type, @@ -4054,9 +4033,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 5, internal_asis_type, @@ -4064,9 +4041,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 6, internal_asis_type, @@ -4074,9 +4049,7 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 7, SQL_C_ULONG, @@ -4084,27 +4057,21 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 8, SQL_C_ULONG, &relid2, sizeof(relid2), NULL); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } result = PGAPI_BindCol(htbl_stmt, 9, internal_asis_type, fk_table_fetched, TABLE_NAME_STORAGE_LEN, NULL); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } if (conn->schema_support) @@ -4114,22 +4081,21 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) { SC_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } } result = PGAPI_Fetch(htbl_stmt); if (result == SQL_NO_DATA_FOUND) - return SQL_SUCCESS; + { + ret = SQL_SUCCESS; + goto cleanup; + } if (result != SQL_SUCCESS) { SC_full_error_copy(stmt, tbl_stmt); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } while (result == SQL_SUCCESS) @@ -4240,19 +4206,35 @@ char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1]; else { SC_set_error(stmt, STMT_INTERNAL_ERROR, "No tables specified to PGAPI_ForeignKeys."); - SC_log_error(func, "", stmt); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); - return SQL_ERROR; + goto cleanup; } + ret = SQL_SUCCESS; +cleanup: + /* + * also, things need to think that this statement is finished so the + * results can be retrieved. + */ + stmt->status = STMT_FINISHED; + + if (SQL_ERROR == ret) + SC_log_error(func, "", stmt); if (pkey_alloced) free(pkey_text); if (fkey_alloced) free(fkey_text); - PGAPI_FreeStmt(htbl_stmt, SQL_DROP); + if (htbl_stmt) + PGAPI_FreeStmt(htbl_stmt, SQL_DROP); + if (hpkey_stmt) + PGAPI_FreeStmt(hpkey_stmt, SQL_DROP); - mylog("PGAPI_ForeignKeys(): EXIT, stmt=%u\n", stmt); - return SQL_SUCCESS; + /* set up the current tuple pointer for SQLFetch */ + stmt->currTuple = -1; + stmt->rowset_start = -1; + SC_set_current_col(stmt, -1); + + mylog("%s(): EXIT, stmt=%u, ret=%d\n", func, stmt, ret); + return ret; } @@ -4288,7 +4270,7 @@ PGAPI_ProcedureColumns( SC_log_error(func, "Function not implemented", stmt); return SQL_ERROR; } - if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result) + if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result) return result; if (conn->schema_support) { @@ -4474,7 +4456,7 @@ PGAPI_Procedures( SC_log_error(func, "Function not implemented", stmt); return SQL_ERROR; } - if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result) + if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result) return result; /* @@ -4597,7 +4579,7 @@ PGAPI_TablePrivileges( const char *likeeq = "like"; mylog("%s: entering... scnm=%x len-%d\n", func, szTableOwner, cbTableOwner); - if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result) + if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result) return result; /* diff --git a/odbcapi.c b/odbcapi.c index a760c10..d191b82 100644 --- a/odbcapi.c +++ b/odbcapi.c @@ -110,15 +110,19 @@ SQLColumns(HSTMT StatementHandle, SQLCHAR *TableName, SQLSMALLINT NameLength3, SQLCHAR *ColumnName, SQLSMALLINT NameLength4) { + CSTR func = "SQLColumns"; RETCODE ret; StatementClass *stmt = (StatementClass *) StatementHandle; SQLCHAR *ctName = CatalogName, *scName = SchemaName, *tbName = TableName, *clName = ColumnName; - mylog("[SQLColumns]"); + mylog("[%s]", func); ENTER_STMT_CS(stmt); SC_clear_error(stmt); - ret = PGAPI_Columns(StatementHandle, ctName, NameLength1, + if (SC_opencheck(stmt, func)) + ret = SQL_ERROR; + else + ret = PGAPI_Columns(StatementHandle, ctName, NameLength1, scName, NameLength2, tbName, NameLength3, clName, NameLength4, 0); if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) @@ -306,13 +310,17 @@ RETCODE SQL_API SQLExecDirect(HSTMT StatementHandle, SQLCHAR *StatementText, SQLINTEGER TextLength) { + CSTR func = "SQLExecDirect"; RETCODE ret; StatementClass *stmt = (StatementClass *) StatementHandle; - mylog("[SQLExecDirect]"); + mylog("[%s]", func); ENTER_STMT_CS(stmt); SC_clear_error(stmt); - ret = PGAPI_ExecDirect(StatementHandle, StatementText, TextLength, 0); + if (SC_opencheck(stmt, func)) + ret = SQL_ERROR; + else + ret = PGAPI_ExecDirect(StatementHandle, StatementText, TextLength, 0); LEAVE_STMT_CS(stmt); return ret; } @@ -524,13 +532,17 @@ RETCODE SQL_API SQLGetTypeInfo(HSTMT StatementHandle, SQLSMALLINT DataType) { + CSTR func = "SQLGetTypeInfo"; RETCODE ret; StatementClass *stmt = (StatementClass *) StatementHandle; - mylog("[SQLGetTypeInfo]"); + mylog("[%s]", func); ENTER_STMT_CS(stmt); SC_clear_error(stmt); - ret = PGAPI_GetTypeInfo(StatementHandle, DataType); + if (SC_opencheck(stmt, func)) + ret = SQL_ERROR; + else + ret = PGAPI_GetTypeInfo(StatementHandle, DataType); LEAVE_STMT_CS(stmt); return ret; } @@ -685,14 +697,18 @@ SQLSpecialColumns(HSTMT StatementHandle, SQLSMALLINT NameLength3, SQLUSMALLINT Scope, SQLUSMALLINT Nullable) { + CSTR func = "SQLSpecialColumns"; RETCODE ret; StatementClass *stmt = (StatementClass *) StatementHandle; SQLCHAR *ctName = CatalogName, *scName = SchemaName, *tbName = TableName; - mylog("[SQLSpecialColumns]"); + mylog("[%s]", func); ENTER_STMT_CS(stmt); SC_clear_error(stmt); - ret = PGAPI_SpecialColumns(StatementHandle, IdentifierType, ctName, + if (SC_opencheck(stmt, func)) + ret = SQL_ERROR; + else + ret = PGAPI_SpecialColumns(StatementHandle, IdentifierType, ctName, NameLength1, scName, NameLength2, tbName, NameLength3, Scope, Nullable); if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) @@ -742,14 +758,18 @@ SQLStatistics(HSTMT StatementHandle, SQLCHAR *TableName, SQLSMALLINT NameLength3, SQLUSMALLINT Unique, SQLUSMALLINT Reserved) { + CSTR func = "SQLStatistics"; RETCODE ret; StatementClass *stmt = (StatementClass *) StatementHandle; SQLCHAR *ctName = CatalogName, *scName = SchemaName, *tbName = TableName; - mylog("[SQLStatistics]"); + mylog("[%s]", func); ENTER_STMT_CS(stmt); SC_clear_error(stmt); - ret = PGAPI_Statistics(StatementHandle, ctName, NameLength1, + if (SC_opencheck(stmt, func)) + ret = SQL_ERROR; + else + ret = PGAPI_Statistics(StatementHandle, ctName, NameLength1, scName, NameLength2, tbName, NameLength3, Unique, Reserved); if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) @@ -799,14 +819,18 @@ SQLTables(HSTMT StatementHandle, SQLCHAR *TableName, SQLSMALLINT NameLength3, SQLCHAR *TableType, SQLSMALLINT NameLength4) { + CSTR func = "SQLTables"; RETCODE ret; StatementClass *stmt = (StatementClass *) StatementHandle; SQLCHAR *ctName = CatalogName, *scName = SchemaName, *tbName = TableName; - mylog("[SQLTables]"); + mylog("[%s]", func); ENTER_STMT_CS(stmt); SC_clear_error(stmt); - ret = PGAPI_Tables(StatementHandle, ctName, NameLength1, + if (SC_opencheck(stmt, func)) + ret = SQL_ERROR; + else + ret = PGAPI_Tables(StatementHandle, ctName, NameLength1, scName, NameLength2, tbName, NameLength3, TableType, NameLength4); if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) @@ -904,15 +928,19 @@ SQLColumnPrivileges( SQLCHAR *szColumnName, SQLSMALLINT cbColumnName) { + CSTR func = "SQLColumnPrivileges"; RETCODE ret; StatementClass *stmt = (StatementClass *) hstmt; SQLCHAR *ctName = szCatalogName, *scName = szSchemaName, *tbName = szTableName, *clName = szColumnName; - mylog("[SQLColumnPrivileges]"); + mylog("[%s]", func); ENTER_STMT_CS(stmt); SC_clear_error(stmt); - ret = PGAPI_ColumnPrivileges(hstmt, ctName, cbCatalogName, + if (SC_opencheck(stmt, func)) + ret = SQL_ERROR; + else + ret = PGAPI_ColumnPrivileges(hstmt, ctName, cbCatalogName, scName, cbSchemaName, tbName, cbTableName, clName, cbColumnName); if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) @@ -1019,16 +1047,20 @@ SQLForeignKeys( SQLCHAR *szFkTableName, SQLSMALLINT cbFkTableName) { + CSTR func = "SQLForeignKeys"; RETCODE ret; StatementClass *stmt = (StatementClass *) hstmt; SQLCHAR *pkctName = szPkCatalogName, *pkscName = szPkSchemaName, *pktbName = szPkTableName, *fkctName = szFkCatalogName, *fkscName = szFkSchemaName, *fktbName = szFkTableName; - mylog("[SQLForeignKeys]"); + mylog("[%s]", func); ENTER_STMT_CS(stmt); SC_clear_error(stmt); - ret = PGAPI_ForeignKeys(hstmt, pkctName, cbPkCatalogName, + if (SC_opencheck(stmt, func)) + ret = SQL_ERROR; + else + ret = PGAPI_ForeignKeys(hstmt, pkctName, cbPkCatalogName, pkscName, cbPkSchemaName, pktbName, cbPkTableName, fkctName, cbFkCatalogName, fkscName, cbFkSchemaName, fktbName, cbFkTableName); @@ -1173,15 +1205,19 @@ SQLPrimaryKeys( SQLCHAR *szTableName, SQLSMALLINT cbTableName) { + CSTR func = "SQLPrimaryKeys"; RETCODE ret; StatementClass *stmt = (StatementClass *) hstmt; SQLCHAR *ctName = szCatalogName, *scName = szSchemaName, *tbName = szTableName; - mylog("[SQLPrimaryKeys]"); + mylog("[%s]", func); ENTER_STMT_CS(stmt); SC_clear_error(stmt); - ret = PGAPI_PrimaryKeys(hstmt, ctName, cbCatalogName, + if (SC_opencheck(stmt, func)) + ret = SQL_ERROR; + else + ret = PGAPI_PrimaryKeys(hstmt, ctName, cbCatalogName, scName, cbSchemaName, tbName, cbTableName); if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) { @@ -1234,15 +1270,19 @@ SQLProcedureColumns( SQLCHAR *szColumnName, SQLSMALLINT cbColumnName) { + CSTR func = "SQLProcedureColumns"; RETCODE ret; StatementClass *stmt = (StatementClass *) hstmt; SQLCHAR *ctName = szCatalogName, *scName = szSchemaName, *prName = szProcName, *clName = szColumnName; - mylog("[SQLProcedureColumns]"); + mylog("[%s]", func); ENTER_STMT_CS(stmt); SC_clear_error(stmt); - ret = PGAPI_ProcedureColumns(hstmt, ctName, cbCatalogName, + if (SC_opencheck(stmt, func)) + ret = SQL_ERROR; + else + ret = PGAPI_ProcedureColumns(hstmt, ctName, cbCatalogName, scName, cbSchemaName, prName, cbProcName, clName, cbColumnName); if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) @@ -1302,15 +1342,19 @@ SQLProcedures( SQLCHAR *szProcName, SQLSMALLINT cbProcName) { + CSTR func = "SQLProcedures"; RETCODE ret; StatementClass *stmt = (StatementClass *) hstmt; SQLCHAR *ctName = szCatalogName, *scName = szSchemaName, *prName = szProcName; - mylog("[SQLProcedures]"); + mylog("[%s]", func); ENTER_STMT_CS(stmt); SC_clear_error(stmt); - ret = PGAPI_Procedures(hstmt, ctName, cbCatalogName, + if (SC_opencheck(stmt, func)) + ret = SQL_ERROR; + else + ret = PGAPI_Procedures(hstmt, ctName, cbCatalogName, scName, cbSchemaName, prName, cbProcName); if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) { @@ -1379,15 +1423,19 @@ SQLTablePrivileges( SQLCHAR *szTableName, SQLSMALLINT cbTableName) { + CSTR func = "SQLTablePrivileges"; RETCODE ret; StatementClass *stmt = (StatementClass *) hstmt; SQLCHAR *ctName = szCatalogName, *scName = szSchemaName, *tbName = szTableName; - mylog("[SQLTablePrivileges]"); + mylog("[%s]", func); ENTER_STMT_CS(stmt); SC_clear_error(stmt); - ret = PGAPI_TablePrivileges(hstmt, ctName, cbCatalogName, + if (SC_opencheck(stmt, func)) + ret = SQL_ERROR; + else + ret = PGAPI_TablePrivileges(hstmt, ctName, cbCatalogName, scName, cbSchemaName, tbName, cbTableName, 0); if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt))) { diff --git a/odbcapi30w.c b/odbcapi30w.c index b82fcaf..6ac15a9 100644 --- a/odbcapi30w.c +++ b/odbcapi30w.c @@ -306,7 +306,7 @@ RETCODE SQL_API SQLGetDiagFieldW( SQLSMALLINT *rgbL, blen, bMax; char *rgbD = NULL; - mylog("[[SQLGetDiagField]] Handle=(%u,%x) Rec=%d Id=%d\n", fHandleType, + mylog("[[SQLGetDiagFieldW]] Handle=(%u,%x) Rec=%d Id=%d\n", fHandleType, handle, iRecord, fDiagField); switch (fDiagField) { diff --git a/options.c b/options.c index 0a8a4d9..3bf5519 100644 --- a/options.c +++ b/options.c @@ -249,8 +249,9 @@ set_statement_option(ConnectionClass *conn, conn->stmtOptions.use_bookmarks = vParam; break; - case 1227: - case 1228: + case 1204: /* SQL_COPT_SS_PRESERVE_CURSORS ? */ + case 1227: /* SQL_SOPT_SS_HIDDEN_COLUMNS ? */ + case 1228: /* SQL_SOPT_SS_NOBROWSETABLE ? */ if (stmt) { SC_set_error(stmt, STMT_OPTION_NOT_FOR_THE_DRIVER, "The option may be for MS SQL Server(Set)"); diff --git a/pgtypes.c b/pgtypes.c index ca634de..773982c 100644 --- a/pgtypes.c +++ b/pgtypes.c @@ -755,6 +755,16 @@ getCharColumnSize(StatementClass *stmt, Int4 type, int col, int handle_unknown_s return -1; } +static Int2 +getTimestampMaxDecimalDigits(StatementClass *stmt, Int4 type) +{ + ConnectionClass *conn = SC_get_conn(stmt); + + if (PG_VERSION_LT(conn, 7.2)) + return 0; + return 6; +} + static Int2 getTimestampDecimalDigits(StatementClass *stmt, Int4 type, int col) { @@ -1122,6 +1132,64 @@ pgtype_transfer_octet_length(StatementClass *stmt, Int4 type, int col, int handl return -1; } +/* + * corrsponds to "min_scale" in ODBC 2.x. + */ +Int2 +pgtype_min_decimal_digits(StatementClass *stmt, Int4 type) +{ + switch (type) + { + case PG_TYPE_INT2: + case PG_TYPE_OID: + case PG_TYPE_XID: + case PG_TYPE_INT4: + case PG_TYPE_INT8: + case PG_TYPE_FLOAT4: + case PG_TYPE_FLOAT8: + case PG_TYPE_MONEY: + case PG_TYPE_BOOL: + case PG_TYPE_ABSTIME: + case PG_TYPE_TIMESTAMP: + case PG_TYPE_DATETIME: + case PG_TYPE_TIMESTAMP_NO_TMZONE: + case PG_TYPE_NUMERIC: + return 0; + default: + return -1; + } +} + +/* + * corrsponds to "max_scale" in ODBC 2.x. + */ +Int2 +pgtype_max_decimal_digits(StatementClass *stmt, Int4 type) +{ + switch (type) + { + case PG_TYPE_INT2: + case PG_TYPE_OID: + case PG_TYPE_XID: + case PG_TYPE_INT4: + case PG_TYPE_INT8: + case PG_TYPE_FLOAT4: + case PG_TYPE_FLOAT8: + case PG_TYPE_MONEY: + case PG_TYPE_BOOL: + case PG_TYPE_ABSTIME: + case PG_TYPE_TIMESTAMP: + return 0; + case PG_TYPE_DATETIME: + case PG_TYPE_TIMESTAMP_NO_TMZONE: + return getTimestampMaxDecimalDigits(stmt, type); + case PG_TYPE_NUMERIC: + return 38; + default: + return -1; + } +} + /* * corrsponds to "scale" in ODBC 2.x. */ diff --git a/pgtypes.h b/pgtypes.h index 1148cb5..140d893 100644 --- a/pgtypes.h +++ b/pgtypes.h @@ -88,6 +88,8 @@ Int4 pgtype_desclength(StatementClass *stmt, Int4 type, int col, int handle_unk Int4 pgtype_transfer_octet_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as); Int2 pgtype_decimal_digits(StatementClass *stmt, Int4 type, int col); /* corresponds to "scale" in ODBC 2.x */ +Int2 pgtype_min_decimal_digits(StatementClass *stmt, Int4 type); /* corresponds to "min_scale" in ODBC 2.x */ +Int2 pgtype_max_decimal_digits(StatementClass *stmt, Int4 type); /* corresponds to "max_scale" in ODBC 2.x */ Int2 pgtype_scale(StatementClass *stmt, Int4 type, int col); /* ODBC 3.x " */ Int2 pgtype_radix(StatementClass *stmt, Int4 type); Int2 pgtype_nullable(StatementClass *stmt, Int4 type); diff --git a/qresult.c b/qresult.c index 19c458c..72005bf 100644 --- a/qresult.c +++ b/qresult.c @@ -145,6 +145,8 @@ QR_Constructor() void QR_Destructor(QResultClass *self) { + ConnectionClass *conn = self->conn; + if (!self) return; mylog("QResult: in DESTRUCTOR\n"); @@ -159,7 +161,7 @@ QR_Destructor(QResultClass *self) * If conn is defined, then we may have used "backend_tuples", so in * case we need to, free it up. Also, close the cursor. */ - if (self->conn && self->conn->sock && CC_is_in_trans(self->conn)) + if (conn && conn->sock && CC_is_in_trans(conn)) { if (!QR_close(self)) /* close the cursor if there is one */ { @@ -248,11 +250,10 @@ QR_set_notice(QResultClass *self, const char *msg) void QR_free_memory(QResultClass *self) { - register int lf, - row; - register TupleField *tuple = self->backend_tuples; - int num_backend_rows = self->num_backend_rows; - int num_fields = self->num_fields; + int lf, row; + TupleField *tuple = self->backend_tuples; + int num_backend_rows = self->num_backend_rows; + int num_fields = self->num_fields; mylog("QResult: free memory in, fcount=%d\n", num_backend_rows); @@ -278,18 +279,30 @@ QR_free_memory(QResultClass *self) } if (self->keyset) { + ConnectionClass *conn = self->conn; + free(self->keyset); self->keyset = NULL; self->count_keyset_allocated = 0; - if (self->reload_count > 0 && self->conn) + if (self->reload_count > 0 && conn && conn->sock) { - QResultClass *res; - char cmd[64]; + char plannm[32]; + + sprintf(plannm, "_KEYSET_%x", self); + if (CC_is_in_error_trans(conn)) + { + CC_mark_a_plan_to_discard(conn, plannm); + } + else + { + QResultClass *res; + char cmd[64]; - sprintf(cmd, "DEALLOCATE \"_KEYSET_%x\"", self); - res = CC_send_query(self->conn, cmd, NULL, CLEAR_RESULT_ON_ABORT); - if (res) - QR_Destructor(res); + sprintf(cmd, "DEALLOCATE \"%s\"", plannm); + res = CC_send_query(conn, cmd, NULL, CLEAR_RESULT_ON_ABORT); + if (res) + QR_Destructor(res); + } } self->reload_count = 0; } @@ -386,13 +399,12 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor) self->count_backend_allocated = self->count_keyset_allocated = 0; if (self->num_fields > 0) { - self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * tuple_size); - if (!self->backend_tuples) - { - self->status = PGRES_FATAL_ERROR; - QR_set_message(self, "Could not get memory for tuple cache."); - return FALSE; - } + QR_MALLOC_return_with_error(self->backend_tuples, + TupleField, + (self->num_fields * sizeof(TupleField) * tuple_size), + self, PGRES_FATAL_ERROR, + "Could not get memory for tuple cache.", + FALSE) self->count_backend_allocated = tuple_size; } if (self->haskeyset) @@ -442,29 +454,35 @@ int QR_close(QResultClass *self) { QResultClass *res; + ConnectionClass *conn = self->conn; + int ret = TRUE; - if (self->conn && self->cursor && self->conn->connInfo.drivers.use_declarefetch) + if (conn && self->cursor && conn->connInfo.drivers.use_declarefetch) { - char buf[64]; + if (!CC_is_in_error_trans(conn)) + { + char buf[64]; - sprintf(buf, "close %s", self->cursor); - mylog("QResult: closing cursor: '%s'\n", buf); + sprintf(buf, "close %s", self->cursor); + mylog("QResult: closing cursor: '%s'\n", buf); - res = CC_send_query(self->conn, buf, NULL, CLEAR_RESULT_ON_ABORT); + res = CC_send_query(conn, buf, NULL, CLEAR_RESULT_ON_ABORT); + if (NULL == res) + { + QR_set_status(self, PGRES_FATAL_ERROR); + QR_set_message(self, "Error closing cursor."); + ret = FALSE; + } + QR_Destructor(res); + } self->inTuples = FALSE; self->currTuple = -1; free(self->cursor); self->cursor = NULL; - - if (res == NULL) - { - self->status = PGRES_FATAL_ERROR; - QR_set_message(self, "Error closing cursor."); - return FALSE; - } - QR_Destructor(res); + if (!ret) + return ret; /* End the transaction if there are no cursors left on this conn */ if (CC_is_in_autocommit(self->conn) && CC_cursor_count(self->conn) == 0) @@ -475,12 +493,12 @@ QR_close(QResultClass *self) { self->status = PGRES_FATAL_ERROR; QR_set_message(self, "Error ending transaction."); - return FALSE; + ret = FALSE; } } } - return TRUE; + return ret; } @@ -599,21 +617,18 @@ inolog("clear obsolete %d tuples\n", num_backend_rows); self->count_backend_allocated = 0; if (self->num_fields > 0) { - self->backend_tuples = (TupleField *) realloc(self->backend_tuples, - self->num_fields * sizeof(TupleField) * self->cache_size); - if (!self->backend_tuples) - { - self->status = PGRES_FATAL_ERROR; - QR_set_message(self, "Out of memory while reading tuples."); - return FALSE; - } + QR_REALLOC_return_with_error(self->backend_tuples, TupleField, + (self->num_fields * sizeof(TupleField) * self->cache_size), + self, "Out of memory while reading tuples.", FALSE) self->count_backend_allocated = self->cache_size; } } if (self->haskeyset && (!self->keyset || self->cache_size > self->count_keyset_allocated)) { self->count_keyset_allocated = 0; - self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * self->cache_size); + QR_REALLOC_return_with_error(self->keyset, KeySet, + (sizeof(KeySet) * self->cache_size), + self, "Out of memory while reading tuples.", FALSE) self->count_keyset_allocated = self->cache_size; } sprintf(fetch, "fetch %d in %s", fetch_size, self->cursor); @@ -709,14 +724,9 @@ inolog("clear obsolete %d tuples\n", num_backend_rows); mylog("REALLOC: old_count = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size); tuple_size *= 2; - self->backend_tuples = (TupleField *) realloc(self->backend_tuples, - tuple_size * self->num_fields * sizeof(TupleField)); - if (!self->backend_tuples) - { - self->status = PGRES_FATAL_ERROR; - QR_set_message(self, "Out of memory while reading tuples."); - return FALSE; - } + QR_REALLOC_return_with_error(self->backend_tuples, TupleField, + (tuple_size * self->num_fields * sizeof(TupleField)), + self, "Out of memory while reading tuples.", FALSE) self->count_backend_allocated = tuple_size; } if (self->haskeyset && @@ -724,7 +734,9 @@ inolog("clear obsolete %d tuples\n", num_backend_rows); { int tuple_size = self->count_keyset_allocated; tuple_size *= 2; - self->keyset = (KeySet *) realloc(self->keyset, sizeof(KeySet) * tuple_size); + QR_REALLOC_return_with_error(self->keyset, KeySet, + (sizeof(KeySet) * tuple_size), + self, "Out of memory while reading tuples.", FALSE) self->count_keyset_allocated = tuple_size; } } @@ -875,7 +887,11 @@ QR_read_tuple(QResultClass *self, char binary) if (field_lf >= effective_cols) buffer = tidoidbuf; else - buffer = (char *) malloc(len + 1); + QR_MALLOC_return_with_error(buffer, char, + (len + 1), self, + PGRES_FATAL_ERROR, + "Couldn't allocate buffer", + FALSE); SOCK_get_n_char(sock, buffer, len); buffer[len] = '\0'; diff --git a/qresult.h b/qresult.h index 9f433e3..0a1a55f 100644 --- a/qresult.h +++ b/qresult.h @@ -110,10 +110,10 @@ struct QResultClass_ #define QR_set_field_info(self, field_num, name, adtid, adtsize) (CI_set_field_info(self->fields, field_num, name, adtid, adtsize, -1)) /* status macros */ -#define QR_command_successful(self) ( !(self->status == PGRES_BAD_RESPONSE || self->status == PGRES_NONFATAL_ERROR || self->status == PGRES_FATAL_ERROR)) +#define QR_command_successful(self) ( !(self->status == PGRES_BAD_RESPONSE || self->status == PGRES_NONFATAL_ERROR || self->status == PGRES_FATAL_ERROR)) #define QR_command_maybe_successful(self) ( !(self->status == PGRES_BAD_RESPONSE || self->status == PGRES_FATAL_ERROR)) -#define QR_command_nonfatal(self) ( self->status == PGRES_NONFATAL_ERROR) -#define QR_end_tuples(self) ( self->status == PGRES_END_TUPLES) +#define QR_command_nonfatal(self) ( self->status == PGRES_NONFATAL_ERROR) +#define QR_end_tuples(self) ( self->status == PGRES_END_TUPLES) #define QR_set_status(self, condition) ( self->status = condition ) #define QR_set_aborted(self, aborted_) ( self->aborted = aborted_) #define QR_set_haskeyset(self) (self->haskeyset = TRUE) @@ -126,6 +126,34 @@ struct QResultClass_ #define QR_aborted(self) (!self || self->aborted) +#define QR_MALLOC_return_with_error(t, tp, s, self, n, m, r) \ + { \ + if (t = (tp *) malloc(s), NULL == t) \ + { \ + QR_set_status(self, n); \ + QR_set_message(self, m); \ + return r; \ + } \ + } +#define QR_REALLOC_return_with_error(t, tp, s, self, m, r) \ + { \ + if (t = (tp *) realloc(t, s), NULL == t) \ + { \ + QR_set_status(self, PGRES_FATAL_ERROR); \ + QR_set_message(self, m); \ + return r; \ + } \ + } +#define QR_MALLOC_exit_if_error(t, tp, s, self, n, m) \ + { \ + if (t = (tp *) malloc(s), NULL == t) \ + { \ + self->status = n; \ + QR_set_message(self, m); \ + goto MALLOC_exit; \ + } \ + } + /* Core Functions */ QResultClass *QR_Constructor(void); void QR_Destructor(QResultClass *self); diff --git a/results.c b/results.c index 23cb323..43616e3 100644 --- a/results.c +++ b/results.c @@ -736,7 +736,7 @@ inolog("COLUMN_TYPE=%d\n", value); value = (fi && !fi->name[0] && !fi->alias[0]) ? SQL_UNNAMED : SQL_NAMED; break; #endif /* ODBCVER */ - case 1212: + case 1212: /* SQL_CA_SS_COLUMN_KEY ? */ SC_set_error(stmt, STMT_OPTION_NOT_FOR_THE_DRIVER, "this request may be for MS SQL Server"); return SQL_ERROR; default: @@ -1820,9 +1820,15 @@ positioned_load(StatementClass *stmt, UInt4 flag, UInt4 oid, const char *tidval) len = strlen(stmt->load_statement); if (tidval) - { len += 100; - selstr = malloc(len); + else if ((flag & USE_INSERTED_TID) != 0) + len += 50; + else + len += 20; + SC_MALLOC_return_with_error(selstr, char, len, stmt, + "Couldn't alloc selstr", NULL) + if (tidval) + { if (latest) { if (stmt->ti[0]->schema[0]) @@ -1836,17 +1842,9 @@ positioned_load(StatementClass *stmt, UInt4 flag, UInt4 oid, const char *tidval) sprintf(selstr, "%s where ctid = '%s' and oid = %u", stmt->load_statement, tidval, oid); } else if ((flag & USE_INSERTED_TID) != 0) - { - len += 50; - selstr = malloc(len); sprintf(selstr, "%s where ctid = currtid(0, '(,)') and oid = %u", stmt->load_statement, oid); - } else - { - len += 20; - selstr = malloc(len); sprintf(selstr, "%s where oid = %u", stmt->load_statement, oid); - } mylog("selstr=%s\n", selstr); qres = CC_send_query(SC_get_conn(stmt), selstr, NULL, CLEAR_RESULT_ON_ABORT); @@ -1945,7 +1943,7 @@ SC_pos_reload(StatementClass *stmt, UDWORD global_ridx, UWORD *count, BOOL logCh return ret; } -static const int ahead_fetch_count = 32; +static const int pre_fetch_count = 32; static int LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per_fetch, int limitrow) { ConnectionClass *conn = SC_get_conn(stmt); @@ -2040,8 +2038,8 @@ static int LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per int j; QResultClass *qres; - if (rows_per_fetch >= ahead_fetch_count * 2) - keys_per_fetch = ahead_fetch_count; + if (rows_per_fetch >= pre_fetch_count * 2) + keys_per_fetch = pre_fetch_count; else keys_per_fetch = rows_per_fetch; lodlen = strlen(stmt->load_statement); @@ -2050,7 +2048,8 @@ static int LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per 3 + 4 * keys_per_fetch + 1 + 1 + 2 + lodlen + 20 + 4 * keys_per_fetch + 1; - qval = malloc(allen); + SC_MALLOC_return_with_error(qval, char, allen, + stmt, "Couldn't alloc qval", -1) sprintf(qval, "PREPARE \"%s\"", planname); sval = strchr(qval, '\0'); for (j = 0; j < keys_per_fetch; j++) @@ -2074,7 +2073,10 @@ static int LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per strcpy(sval, ")"); qres = CC_send_query(conn, qval, NULL, CLEAR_RESULT_ON_ABORT); if (qres) + { res->reload_count = keys_per_fetch; + QR_Destructor(qres); + } else { SC_set_error(stmt, STMT_EXEC_ERROR, "Prepare for Data Load Error"); @@ -2083,15 +2085,15 @@ static int LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per } } allen = 25 + 23 * keys_per_fetch; - qval = realloc(qval, allen); } else { - keys_per_fetch = ahead_fetch_count; + keys_per_fetch = pre_fetch_count; lodlen = strlen(stmt->load_statement); allen = lodlen + 20 + 23 * keys_per_fetch; - qval = malloc(allen); } + SC_REALLOC_return_with_error(qval, char, allen, + stmt, "Couldn't alloc qval", -1) } if (res->reload_count > 0) { @@ -2156,7 +2158,7 @@ SC_pos_reload_needed(StatementClass *stmt, UDWORD flag) } if (create_from_scratch) { - rows_per_fetch = ((ahead_fetch_count - 1) / res->rowset_size + 1) * res->rowset_size; + rows_per_fetch = ((pre_fetch_count - 1) / res->rowset_size + 1) * res->rowset_size; limitrow = RowIdx2GIdx(rows_per_fetch, stmt); } else diff --git a/socket.c b/socket.c index 1bef35d..1c3801d 100644 --- a/socket.c +++ b/socket.c @@ -184,6 +184,12 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname) #ifdef HAVE_UNIX_SOCKETS { un = (struct sockaddr_un *) malloc(sizeof(struct sockaddr_un)); + if (!un) + { + self->errornumber = SOCKET_COULD_NOT_CREATE_SOCKET; + self->errormsg = "coulnd't allocate memory for un."; + return 0; + } un->sun_family = family = AF_UNIX; /* passing NULL means that this only suports the pg default "/tmp" */ UNIXSOCK_PATH(un, port, ((char *) NULL)); diff --git a/statement.c b/statement.c index 2246bc2..ef4e246 100644 --- a/statement.c +++ b/statement.c @@ -422,15 +422,26 @@ SC_set_prepared(StatementClass *stmt, BOOL prepared) if (!prepared) { ConnectionClass *conn = SC_get_conn(stmt); - if (CONN_CONNECTED == conn->status) + + if (conn && CONN_CONNECTED == conn->status) { - QResultClass *res; - char dealloc_stmt[128]; + char plannm[32]; + + sprintf(plannm, "_PLAN%0x", stmt); + if (CC_is_in_error_trans(conn)) + { + CC_mark_a_plan_to_discard(conn, plannm); + } + else + { + QResultClass *res; + char dealloc_stmt[128]; - sprintf(dealloc_stmt, "DEALLOCATE _PLAN%0x", stmt); - res = CC_send_query(conn, dealloc_stmt, NULL, 0); - if (res) - QR_Destructor(res); + sprintf(dealloc_stmt, "DEALLOCATE \"%s\"", plannm); + res = CC_send_query(conn, dealloc_stmt, NULL, 0); + if (res) + QR_Destructor(res); + } } } stmt->prepared = prepared; @@ -457,7 +468,7 @@ SC_initialize_stmts(StatementClass *self, BOOL initializeOriginal) self->execute_statement = NULL; } self->prepare = FALSE; - SC_set_prepared(self,FALSE); + SC_set_prepared(self, FALSE); self->statement_type = STMT_TYPE_UNKNOWN; } if (self->stmt_with_params) @@ -474,38 +485,31 @@ SC_initialize_stmts(StatementClass *self, BOOL initializeOriginal) return 0; } -BOOL SC_is_open(const StatementClass *self) +BOOL SC_opencheck(StatementClass *self, const char *func) { QResultClass *res; + if (self->status == STMT_EXECUTING) + { + SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction."); + return TRUE; + } if (res = SC_get_Curres(self), NULL != res) { if (res->backend_tuples) + { + SC_set_error(self, STMT_SEQUENCE_ERROR, "The cursor is open."); + SC_log_error(func, "", self); return TRUE; + } } return FALSE; } RETCODE -SC_initialize_ifclosed(StatementClass *self, const char *func) +SC_initialize_and_recycle(StatementClass *self) { - if (!self) - { - SC_log_error(func, "", NULL); - return SQL_INVALID_HANDLE; - } - if (self->status == STMT_EXECUTING) - { - SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction."); - return FALSE; - } - if (SC_is_open(self)) - { - SC_set_error(self, STMT_INVALID_CURSOR_STATE_ERROR, "The cursor is open"); - SC_log_error(func, "", self); - return SQL_ERROR; - } SC_initialize_stmts(self, TRUE); if (!SC_recycle_statement(self)) return SQL_ERROR; @@ -1031,6 +1035,7 @@ SC_fetch(StatementClass *self) return result; } +#define return DONT_CALL_RETURN_FROM_HERE??? RETCODE SC_execute(StatementClass *self) @@ -1046,7 +1051,7 @@ SC_execute(StatementClass *self) ConnInfo *ci; UDWORD qflag = 0; BOOL auto_begin = FALSE, is_in_trans; - int entered; + int func_cs_count = 0; conn = SC_get_conn(self); @@ -1062,13 +1067,12 @@ SC_execute(StatementClass *self) * 2) we are in autocommit off state and the statement isn't of type * OTHER. */ - ENTER_INNER_CONN_CS(conn, entered); + ENTER_INNER_CONN_CS(conn, func_cs_count); if (CONN_EXECUTING == conn->status) { SC_set_error(self, STMT_SEQUENCE_ERROR, "Connection is already in use."); - SC_log_error(func, "", self); mylog("%s: problem with connection\n", func); - RETURN_AFTER_LEAVE_CS(entered, conn, SQL_ERROR); + goto cleanup; } is_in_trans = CC_is_in_trans(conn); if (!self->internal && !is_in_trans && @@ -1082,8 +1086,7 @@ SC_execute(StatementClass *self) else if (!CC_begin(conn)) { SC_set_error(self, STMT_EXEC_ERROR, "Could not begin a transaction"); - SC_log_error(func, "", self); - RETURN_AFTER_LEAVE_CS(entered, conn, SQL_ERROR); + goto cleanup; } } @@ -1161,7 +1164,7 @@ SC_execute(StatementClass *self) if (CONN_DOWN != conn->status) conn->status = oldstatus; self->status = STMT_FINISHED; - LEAVE_INNER_CONN_CS(entered, conn); + LEAVE_INNER_CONN_CS(func_cs_count, conn); /* Check the status of the result */ if (res) @@ -1203,8 +1206,7 @@ SC_execute(StatementClass *self) { QR_Destructor(res); SC_set_error(self, STMT_NO_MEMORY_ERROR,"Could not get enough free memory to store the binding information"); - SC_log_error(func, "", self); - return SQL_ERROR; + goto cleanup; } } } @@ -1270,6 +1272,9 @@ SC_execute(StatementClass *self) SC_set_error(self, STMT_EXEC_ERROR, "SC_fetch to get a Procedure return failed."); } } +#undef return +cleanup: + CLEANUP_FUNC_CONN_CS(func_cs_count, conn); if (SC_get_errornumber(self) == STMT_OK) return SQL_SUCCESS; else if (SC_get_errornumber(self) == STMT_INFO_ONLY) @@ -1288,9 +1293,10 @@ int enqueueNeedDataCallback(StatementClass *stmt, NeedDataCallfunc func, void *d { if (stmt->num_callbacks >= stmt->allocated_callbacks) { - stmt->callbacks = (NeedDataCallback *) realloc(stmt->callbacks, + SC_REALLOC_return_with_error(stmt->callbacks, NeedDataCallback, sizeof(NeedDataCallback) * (stmt->allocated_callbacks + - CALLBACK_ALLOC_ONCE)); + CALLBACK_ALLOC_ONCE), stmt, + "Couldn't alloc callbacks", -1) stmt->allocated_callbacks += CALLBACK_ALLOC_ONCE; } stmt->callbacks[stmt->num_callbacks].func = func; diff --git a/statement.h b/statement.h index 0f9f494..04588a3 100644 --- a/statement.h +++ b/statement.h @@ -263,6 +263,23 @@ struct StatementClass_ #define SC_is_lower_case(a, b) (b->connInfo.lower_case_identifier) #endif /* ODBCVER */ +#define SC_MALLOC_return_with_error(t, tp, s, a, m, r) \ + { \ + if (t = (tp *) malloc(s), NULL == t) \ + { \ + SC_set_error(a, STMT_NO_MEMORY_ERROR, m); \ + return r; \ + } \ + } +#define SC_REALLOC_return_with_error(t, tp, s, a, m, r) \ + { \ + if (t = (tp *) realloc(t, s), NULL == t) \ + { \ + SC_set_error(a, STMT_NO_MEMORY_ERROR, m); \ + return r; \ + } \ + } + /* options for SC_free_params() */ #define STMT_FREE_PARAMS_ALL 0 #define STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY 1 @@ -299,8 +316,8 @@ struct StatementClass_ StatementClass *SC_Constructor(void); void InitializeStatementOptions(StatementOptions *opt); char SC_Destructor(StatementClass *self); -BOOL SC_is_open(const StatementClass *self); -RETCODE SC_initialize_ifclosed(StatementClass *self, const char *func); +BOOL SC_opencheck(StatementClass *self, const char *func); +RETCODE SC_initialize_and_recycle(StatementClass *self); int statement_type(const char *statement); char parse_statement(StatementClass *stmt); void SC_pre_execute(StatementClass *self); diff --git a/version.h b/version.h index 800ab3c..bfe57ee 100644 --- a/version.h +++ b/version.h @@ -9,8 +9,8 @@ #ifndef __VERSION_H__ #define __VERSION_H__ -#define POSTGRESDRIVERVERSION "07.03.0205" -#define POSTGRES_RESOURCE_VERSION "07.03.0205\0" -#define PG_DRVFILE_VERSION 7,3,2,05 +#define POSTGRESDRIVERVERSION "07.03.0207" +#define POSTGRES_RESOURCE_VERSION "07.03.0207\0" +#define PG_DRVFILE_VERSION 7,3,2,07 #endif diff --git a/win_unicode.c b/win_unicode.c index a106ef1..e3ab7f8 100644 --- a/win_unicode.c +++ b/win_unicode.c @@ -94,7 +94,7 @@ UInt4 utf8_to_ucs2_lf(const char *utf8str, Int4 ilen, BOOL lfconv, SQLWCHAR *ucs const UCHAR *str; /*mylog("utf8_to_ucs2 ilen=%d bufcount=%d", ilen, bufcount);*/ - if (!utf8str || !ilen) + if (!utf8str) return 0; /*mylog(" string=%s\n", utf8str);*/ if (!bufcount) @@ -146,7 +146,7 @@ UInt4 utf8_to_ucs2_lf(const char *utf8str, Int4 ilen, BOOL lfconv, SQLWCHAR *ucs str += 2; } } - if (ocount && ocount < bufcount && ucs2str) + if (ocount < bufcount && ucs2str) ucs2str[ocount] = 0; /*mylog(" ocount=%d\n", ocount);*/ return ocount; -- 2.39.5