diff options
Diffstat (limited to 'src/interfaces/odbc/connection.c')
-rw-r--r-- | src/interfaces/odbc/connection.c | 304 |
1 files changed, 178 insertions, 126 deletions
diff --git a/src/interfaces/odbc/connection.c b/src/interfaces/odbc/connection.c index 3d07474a560..44d7589496a 100644 --- a/src/interfaces/odbc/connection.c +++ b/src/interfaces/odbc/connection.c @@ -75,7 +75,8 @@ PGAPI_AllocConnect( return SQL_ERROR; } - *phdbc = (HDBC) conn; + if (phdbc) + *phdbc = (HDBC) conn; return SQL_SUCCESS; } @@ -228,6 +229,16 @@ PGAPI_FreeConnect( } +void +CC_conninfo_init(ConnInfo *conninfo) +{ + memset(conninfo, 0, sizeof(ConnInfo)); + conninfo->disallow_premature = -1; + conninfo->updatable_cursors = -1; + conninfo->lf_conversion = -1; + conninfo->true_is_minus1 = -1; + memcpy(&(conninfo->drivers), &globals, sizeof(globals)); +} /* * IMPLEMENTATION CONNECTION CLASS */ @@ -249,11 +260,7 @@ CC_Constructor() rv->status = CONN_NOT_CONNECTED; rv->transact_status = CONN_IN_AUTOCOMMIT; /* autocommit by default */ - memset(&rv->connInfo, 0, sizeof(ConnInfo)); -#ifdef DRIVER_CURSOR_IMPLEMENT - rv->connInfo.updatable_cursors = 1; -#endif /* DRIVER_CURSOR_IMPLEMENT */ - memcpy(&(rv->connInfo.drivers), &globals, sizeof(globals)); + CC_conninfo_init(&(rv->connInfo)); rv->sock = SOCK_Constructor(rv); if (!rv->sock) return NULL; @@ -280,6 +287,7 @@ CC_Constructor() rv->pg_version_major = 0; rv->pg_version_minor = 0; rv->ms_jet = 0; + rv->unicode = 0; #ifdef MULTIBYTE rv->client_encoding = NULL; rv->server_encoding = NULL; @@ -338,7 +346,7 @@ CC_cursor_count(ConnectionClass *self) for (i = 0; i < self->num_stmts; i++) { stmt = self->stmts[i]; - if (stmt && stmt->result && stmt->result->cursor) + if (stmt && SC_get_Result(stmt) && SC_get_Result(stmt)->cursor) count++; } @@ -366,18 +374,18 @@ CC_begin(ConnectionClass *self) char ret = TRUE; if (!CC_is_in_trans(self)) { - QResultClass *res = CC_send_query(self, "BEGIN", NULL); + QResultClass *res = CC_send_query(self, "BEGIN", NULL, TRUE); mylog("CC_begin: sending BEGIN!\n"); if (res != NULL) { - ret = (!QR_aborted(res) && QR_command_successful(res)); + ret = QR_command_successful(res); QR_Destructor(res); if (ret) CC_set_in_trans(self); } else - ret = FALSE; + return FALSE; } return ret; @@ -393,7 +401,7 @@ CC_commit(ConnectionClass *self) char ret = FALSE; if (CC_is_in_trans(self)) { - QResultClass *res = CC_send_query(self, "COMMIT", NULL); + QResultClass *res = CC_send_query(self, "COMMIT", NULL, TRUE); mylog("CC_commit: sending COMMIT!\n"); CC_set_no_trans(self); @@ -404,7 +412,7 @@ CC_commit(ConnectionClass *self) QR_Destructor(res); } else - ret = FALSE; + return FALSE; } return ret; @@ -419,7 +427,7 @@ CC_abort(ConnectionClass *self) { if (CC_is_in_trans(self)) { - QResultClass *res = CC_send_query(self, "ROLLBACK", NULL); + QResultClass *res = CC_send_query(self, "ROLLBACK", NULL, TRUE); mylog("CC_abort: sending ABORT!\n"); CC_set_no_trans(self); @@ -488,11 +496,7 @@ CC_cleanup(ConnectionClass *self) self->status = CONN_NOT_CONNECTED; self->transact_status = CONN_IN_AUTOCOMMIT; - memset(&self->connInfo, 0, sizeof(ConnInfo)); -#ifdef DRIVER_CURSOR_IMPLEMENT - self->connInfo.updatable_cursors = 1; -#endif /* DRIVER_CURSOR_IMPLEMENT */ - memcpy(&(self->connInfo.drivers), &globals, sizeof(globals)); + CC_conninfo_init(&(self->connInfo)); #ifdef MULTIBYTE if (self->client_encoding) free(self->client_encoding); @@ -578,12 +582,12 @@ md5_auth_send(ConnectionClass *self, const char *salt) { free(pwd1); return 1; - } + } if (!(pwd2 = malloc(MD5_PASSWD_LEN + 1))) { free(pwd1); return 1; - } + } if (!EncryptMD5(pwd1 + strlen("md5"), salt, 4, pwd2)) { free(pwd2); @@ -595,7 +599,7 @@ md5_auth_send(ConnectionClass *self, const char *salt) SOCK_put_n_char(sock, pwd2, strlen(pwd2) + 1); SOCK_flush_output(sock); free(pwd2); - return 0; + return 0; } char @@ -608,7 +612,7 @@ CC_connect(ConnectionClass *self, char do_password) ConnInfo *ci = &(self->connInfo); int areq = -1; int beresp; - char msgbuffer[ERROR_MSG_LENGTH]; + static char msgbuffer[ERROR_MSG_LENGTH]; char salt[5]; static char *func = "CC_connect"; @@ -651,15 +655,16 @@ CC_connect(ConnectionClass *self, char do_password) if (encoding && strcmp(encoding, "OTHER")) self->client_encoding = strdup(encoding); } + if (self->client_encoding) + self->ccsc = pg_CS_code(self->client_encoding); qlog(" extra_systable_prefixes='%s', conn_settings='%s' conn_encoding='%s'\n", ci->drivers.extra_systable_prefixes, ci->drivers.conn_settings, encoding ? encoding : ""); #else - qlog(" extra_systable_prefixes='%s', conn_settings='%s', protocol='%s'\n", + qlog(" extra_systable_prefixes='%s', conn_settings='%s'\n", ci->drivers.extra_systable_prefixes, - ci->drivers.conn_settings, - ci->protocol); + ci->drivers.conn_settings); #endif if (self->status != CONN_NOT_CONNECTED) @@ -914,7 +919,7 @@ another_version_retry: */ mylog("sending an empty query...\n"); - res = CC_send_query(self, " ", NULL); + res = CC_send_query(self, " ", NULL, TRUE); if (res == NULL || QR_get_status(res) != PGRES_EMPTY_QUERY) { mylog("got no result from the empty query. (probably database does not exist)\n"); @@ -942,13 +947,55 @@ another_version_retry: * function instead. */ CC_send_settings(self); - CC_lookup_lo(self); /* a hack to get the oid of our large - * object oid type */ -#ifdef MULTIBYTE
- CC_lookup_characterset(self);
-#endif
- CC_lookup_pg_version(self); /* Get PostgreSQL version for SQLGetInfo - * use */ + CC_lookup_lo(self); /* a hack to get the oid of + our large object oid type */ + CC_lookup_pg_version(self); /* Get PostgreSQL version for + SQLGetInfo use */ + + /* + * Multibyte handling is available ? + */ +#ifdef MULTIBYTE + if (PG_VERSION_GE(self, 7.0)) + { + CC_lookup_characterset(self); + if (self->errornumber != 0) + return 0; +#ifdef UNICODE_SUPPORT + if (self->unicode) + { + if (!self->client_encoding || + stricmp(self->client_encoding, "UNICODE")) + { + QResultClass *res; + if (PG_VERSION_LT(self, 7.1)) + { + self->errornumber = CONN_NOT_IMPLEMENTED_ERROR; + self->errormsg = "UTF-8 conversion isn't implemented before 7.1"; + return 0; + } + if (self->client_encoding) + free(self->client_encoding); + self->client_encoding = NULL; + if (res = CC_send_query(self, "set client_encoding to 'UTF8'", NULL, TRUE), res) + { + self->client_encoding = strdup("UNICODE"); + QR_Destructor(res); + + } + } + } +#endif /* UNICODE_SUPPORT */ + } +#ifdef UNICODE_SUPPORT + else if (self->unicode) + { + self->errornumber = CONN_NOT_IMPLEMENTED_ERROR; + self->errormsg = "Unicode isn't supported before 7.0"; + return 0; + } +#endif /* UNICODE_SUPPORT */ +#endif /* MULTIBYTE */ CC_clear_error(self); /* clear any initial command errors */ self->status = CONN_CONNECTED; @@ -1081,11 +1128,12 @@ CC_get_error(ConnectionClass *self, int *number, char **message) * 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements. */ QResultClass * -CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi) +CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, BOOL clear_result_on_abort) { QResultClass *result_in = NULL, - *res = NULL, - *retres = NULL; + *cmdres = NULL, + *retres = NULL, + *res = NULL; char swallow, *wq; int id; @@ -1094,9 +1142,9 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi) empty_reqs; BOOL msg_truncated, ReadyToReturn, - tuples_return = FALSE, query_completed = FALSE, before_64 = PG_VERSION_LT(self, 6.4), + aborted = FALSE, used_passed_result_object = FALSE; /* ERROR_MSG_LENGTH is suffcient */ @@ -1156,6 +1204,20 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi) ; if (*wq == '\0') empty_reqs = 1; + cmdres = qi ? qi->result_in : NULL; + if (cmdres) + used_passed_result_object = TRUE; + else + { + cmdres = QR_Constructor(); + if (!cmdres) + { + self->errornumber = CONNECTION_COULD_NOT_RECEIVE; + self->errormsg = "Could not create result info in send_query."; + return NULL; + } + } + res = cmdres; while (!ReadyToReturn) { /* what type of message is coming now ? */ @@ -1199,12 +1261,14 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi) { mylog("send_query: ok - 'C' - %s\n", cmdbuffer); - if (res == NULL) /* allow for "show" style info */ - res = QR_Constructor(); + if (query_completed) /* allow for "show" style notices */ + { + res->next = QR_Constructor(); + res = res->next; + } mylog("send_query: setting cmdbuffer = '%s'\n", cmdbuffer); - /* Only save the first command */ if (QR_command_successful(res)) QR_set_status(res, PGRES_COMMAND_OK); QR_set_command(res, cmdbuffer); @@ -1233,44 +1297,19 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi) if (empty_reqs == 0) { ReadyToReturn = TRUE; - if (res && QR_get_aborted(res)) - retres = res; - else if (tuples_return) - retres = result_in; - else if (query_completed) - retres = res; + if (aborted || query_completed) + retres = cmdres; else ReadyToReturn = FALSE; } break; - case 'N': /* INFO, NOTICE, WARNING */ + case 'N': /* NOTICE: */ msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH); - if (!res) - res = QR_Constructor(); if (QR_command_successful(res)) QR_set_status(res, PGRES_NONFATAL_ERROR); QR_set_notice(res, cmdbuffer); /* will dup this string */ -#ifdef MULTIBYTE
- if (strstr(cmdbuffer,"encoding is"))
- {
- if (strstr(cmdbuffer,"Current client encoding is"))
- strcpy(PG_CCSS, cmdbuffer + 36);
- if (strstr(cmdbuffer,"Current server encoding is"))
- strcpy(PG_SCSS, cmdbuffer + 36);
- mylog("~~~ WARNING: '%s'\n", cmdbuffer);
- qlog("WARNING from backend during send_query: '%s'\n ClientEncoding = %s\n ServerEncoding = %s\n", cmdbuffer, PG_CCSS, PG_SCSS);
-
- }
- else
- {
-
- mylog("~~~ WARNING: '%s'\n", cmdbuffer);
- qlog("WARNING from backend during send_query: '%s'\n", cmdbuffer);
- }
-#else
- mylog("~~~ WARNING: '%s'\n", cmdbuffer);
- qlog("WARNING from backend during send_query: '%s'\n", cmdbuffer);
-#endif + mylog("~~~ NOTICE: '%s'\n", cmdbuffer); + qlog("NOTICE from backend during send_query: '%s'\n", cmdbuffer); while (msg_truncated) msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH); @@ -1280,15 +1319,13 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi) case 'I': /* The server sends an empty query */ /* There is a closing '\0' following the 'I', so we eat it */ swallow = SOCK_get_char(sock); - if (!res) - res = QR_Constructor(); if ((swallow != '\0') || SOCK_get_errcode(sock) != 0) { self->errornumber = CONNECTION_BACKEND_CRAZY; self->errormsg = "Unexpected protocol character from backend (send_query - I)"; QR_set_status(res, PGRES_FATAL_ERROR); ReadyToReturn = TRUE; - retres = res; + retres = cmdres; break; } else @@ -1315,8 +1352,6 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi) qlog("ERROR from backend during send_query: '%s'\n", self->errormsg); /* We should report that an error occured. Zoltan */ - if (!res) - res = QR_Constructor(); if (!strncmp(self->errormsg, "FATAL", 5)) { @@ -1327,6 +1362,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi) self->errornumber = CONNECTION_SERVER_REPORTED_WARNING; QR_set_status(res, PGRES_FATAL_ERROR); QR_set_aborted(res, TRUE); + aborted = TRUE; while (msg_truncated) msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH); @@ -1337,13 +1373,11 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi) SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH); break; case 'T': /* Tuple results start here */ - result_in = qi ? qi->result_in : NULL; - - if (result_in == NULL) + if (query_completed) { - result_in = QR_Constructor(); - mylog("send_query: 'T' no result_in: res = %u\n", result_in); - if (!result_in) + res->next = QR_Constructor(); + mylog("send_query: 'T' no result_in: res = %u\n", res->next); + if (!res->next) { self->errornumber = CONNECTION_COULD_NOT_RECEIVE; self->errormsg = "Could not create result info in send_query."; @@ -1351,55 +1385,60 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi) retres = NULL; break; } + res = res->next; if (qi) - QR_set_cache_size(result_in, qi->row_size); - - if (!QR_fetch_tuples(result_in, self, qi ? qi->cursor : NULL)) + QR_set_cache_size(res, qi->row_size); + } + if (!used_passed_result_object) + { + if (!QR_fetch_tuples(res, self, qi ? qi->cursor : NULL)) { self->errornumber = CONNECTION_COULD_NOT_RECEIVE; - self->errormsg = QR_get_message(result_in); + self->errormsg = QR_get_message(res); ReadyToReturn = TRUE; retres = NULL; break; } + query_completed = TRUE; } else { /* next fetch, so reuse an existing result */ - used_passed_result_object = TRUE; /* * called from QR_next_tuple and must return * immediately. */ ReadyToReturn = TRUE; - if (!QR_fetch_tuples(result_in, NULL, NULL)) + if (!QR_fetch_tuples(res, NULL, NULL)) { self->errornumber = CONNECTION_COULD_NOT_RECEIVE; - self->errormsg = QR_get_message(result_in); + self->errormsg = QR_get_message(res); retres = NULL; break; } - retres = result_in; + retres = cmdres; } - - tuples_return = TRUE; break; case 'D': /* Copy in command began successfully */ - if (!res) - res = QR_Constructor(); - if (QR_command_successful(res)) - QR_set_status(res, PGRES_COPY_IN); + if (query_completed) + { + res->next = QR_Constructor(); + res = res->next; + } + QR_set_status(res, PGRES_COPY_IN); ReadyToReturn = TRUE; - retres = res; + retres = cmdres; break; case 'B': /* Copy out command began successfully */ - if (!res) - res = QR_Constructor(); - if (QR_command_successful(res)) - QR_set_status(res, PGRES_COPY_OUT); + if (query_completed) + { + res->next = QR_Constructor(); + res = res->next; + } + QR_set_status(res, PGRES_COPY_OUT); ReadyToReturn = TRUE; - retres = res; + retres = cmdres; break; default: self->errornumber = CONNECTION_BACKEND_CRAZY; @@ -1417,7 +1456,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi) */ if (before_64) { - if (empty_reqs == 0 && (query_completed || tuples_return)) + if (empty_reqs == 0 && query_completed) break; } } @@ -1426,34 +1465,44 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi) * Break before being ready to return. */ if (!ReadyToReturn) - { - if (res && QR_get_aborted(res)) - retres = res; - else if (tuples_return) - retres = result_in; - else - retres = res; - } + retres = cmdres; /* - * set notice message to result_in. + * Cleanup garbage results before returning. */ - if (result_in && res && retres == result_in) - { - if (QR_command_successful(result_in)) - QR_set_status(result_in, QR_get_status(res)); - QR_set_notice(result_in, QR_get_notice(res)); - } - + if (cmdres && retres != cmdres && !used_passed_result_object) + QR_Destructor(cmdres); /* - * Cleanup garbage results before returning. + * Cleanup the aborted result if specified */ - if (res && retres != res) - QR_Destructor(res); - if (result_in && retres != result_in) + if (retres) { - if (!used_passed_result_object) - QR_Destructor(result_in); + if (aborted) + { + if (clear_result_on_abort) + { + if (!used_passed_result_object) + { + QR_Destructor(retres); + retres = NULL; + } + } + else + { + /* + * discard results other than errors. + */ + QResultClass *qres; + for (qres = retres; qres->next; qres = retres) + { + if (QR_get_aborted(qres)) + break; + retres = qres->next; + qres->next = NULL; + QR_Destructor(qres); + } + } + } } return retres; } @@ -1591,7 +1640,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_ SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH); mylog("send_function(G): 'N' - %s\n", msgbuffer); - qlog("WARNING from backend during send_function: '%s'\n", msgbuffer); + qlog("NOTICE from backend during send_function: '%s'\n", msgbuffer); continue; /* dont return a result -- continue * reading */ @@ -1869,7 +1918,7 @@ CC_lookup_pg_version(ConnectionClass *self) void -CC_log_error(char *func, char *desc, ConnectionClass *self) +CC_log_error(const char *func, const char *desc, const ConnectionClass *self) { #ifdef PRN_NULLCHECK #define nullcheck(a) (a ? a : "(NULL)") @@ -1894,7 +1943,10 @@ CC_log_error(char *func, char *desc, ConnectionClass *self) } } else +{ qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc); + mylog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc); +} #undef PRN_NULLCHECK } |