diff options
author | Hiroshi Inoue <inoue@tpf.co.jp> | 2002-03-08 08:52:55 +0000 |
---|---|---|
committer | Hiroshi Inoue <inoue@tpf.co.jp> | 2002-03-08 08:52:55 +0000 |
commit | 4b47467a6b0d86162dd8814b8ab923aba982fb34 (patch) | |
tree | 85fea3bf0475716f35d440468eda620769081bac | |
parent | 21f8aa396fa833ac95cff4e85c5281fd24fd1632 (diff) | |
download | postgresql-4b47467a6b0d86162dd8814b8ab923aba982fb34.tar.gz postgresql-4b47467a6b0d86162dd8814b8ab923aba982fb34.zip |
1) Implement SQLParamOptions().
2) Handle Multiple results and implement SQLMoreResult().
3) Improve multibyte handling thanks to Eiji Tokuya.
4) Add new options.
LF <-> CR/LF converion.
TRUE is -1 (for VB).
5) Introduce unicode(UCS-2) support.
6) Reduce the length of connection strings.
7) Improve SQLError, SQLGetDiagRec(ODBC 3.0).
8) Implement SQLTablePrivileges().
9) Miscellaneous changes for ODBC 3.0 support.
43 files changed, 3862 insertions, 1395 deletions
diff --git a/src/interfaces/odbc/bind.c b/src/interfaces/odbc/bind.c index f3fb3537357..6ce32c7982b 100644 --- a/src/interfaces/odbc/bind.c +++ b/src/interfaces/odbc/bind.c @@ -7,7 +7,7 @@ * Classes: BindInfoClass, ParameterInfoClass * * API functions: SQLBindParameter, SQLBindCol, SQLDescribeParam, SQLNumParams, - * SQLParamOptions(NI) + * SQLParamOptions * * Comments: See "notice.txt" for copyright and license information. *------- @@ -331,17 +331,9 @@ PGAPI_ParamOptions( mylog("%s: entering... %d %x\n", func, crow, pirow); - if (crow == 1) /* temporary solution and must be - * rewritten later */ - { - if (pirow) - *pirow = 1; - return SQL_SUCCESS; - } - stmt->errornumber = CONN_UNSUPPORTED_OPTION; - stmt->errormsg = "Function not implemented"; - SC_log_error(func, "Function not implemented", (StatementClass *) hstmt); - return SQL_ERROR; + stmt->options.paramset_size = crow; + stmt->options.param_processed_ptr = pirow; + return SQL_SUCCESS; } 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 } diff --git a/src/interfaces/odbc/connection.h b/src/interfaces/odbc/connection.h index df40f440d69..408d11836c5 100644 --- a/src/interfaces/odbc/connection.h +++ b/src/interfaces/odbc/connection.h @@ -151,6 +151,8 @@ typedef struct char focus_password; char disallow_premature; char updatable_cursors; + char lf_conversion; + char true_is_minus1; GLOBAL_VALUES drivers; /* moved from driver's option */ } ConnInfo; @@ -271,6 +273,7 @@ struct ConnectionClass_ char *client_encoding; char *server_encoding; #endif /* MULTIBYTE */ + int ccsc; }; @@ -290,6 +293,7 @@ struct ConnectionClass_ /* prototypes */ ConnectionClass *CC_Constructor(void); +void CC_conninfo_init(ConnInfo *conninfo); char CC_Destructor(ConnectionClass *self); int CC_cursor_count(ConnectionClass *self); char CC_cleanup(ConnectionClass *self); @@ -301,7 +305,7 @@ char CC_connect(ConnectionClass *self, char do_password); char CC_add_statement(ConnectionClass *self, StatementClass *stmt); char CC_remove_statement(ConnectionClass *self, StatementClass *stmt); char CC_get_error(ConnectionClass *self, int *number, char **message); -QResultClass *CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi); +QResultClass *CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, BOOL); void CC_clear_error(ConnectionClass *self); char *CC_create_errormsg(ConnectionClass *self); int CC_send_function(ConnectionClass *conn, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *argv, int nargs); @@ -309,7 +313,7 @@ char CC_send_settings(ConnectionClass *self); void CC_lookup_lo(ConnectionClass *conn); void CC_lookup_pg_version(ConnectionClass *conn); void CC_initialize_pg_version(ConnectionClass *conn); -void CC_log_error(char *func, char *desc, ConnectionClass *self); +void CC_log_error(const char *func, const char *desc, const ConnectionClass *self); int CC_get_max_query_len(const ConnectionClass *self); #endif diff --git a/src/interfaces/odbc/convert.c b/src/interfaces/odbc/convert.c index 4291e36c34c..a38ffd1de83 100644 --- a/src/interfaces/odbc/convert.c +++ b/src/interfaces/odbc/convert.c @@ -335,12 +335,15 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 int bind_row = stmt->bind_row; int bind_size = stmt->options.bind_size; int result = COPY_OK; - BOOL changed; + BOOL changed, true_is_minus1 = FALSE; const char *neut_str = value; char midtemp[2][32]; int mtemp_cnt = 0; static BindInfoClass sbic; BindInfoClass *pbic; +#ifdef UNICODE_SUPPORT + BOOL wchanged = FALSE; +#endif /* UNICODE_SUPPORT */ if (stmt->current_col >= 0) { @@ -474,15 +477,23 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 char *s; s = midtemp[mtemp_cnt]; - strcpy(s, (char *) value); - if (s[0] == 'f' || s[0] == 'F' || s[0] == 'n' || s[0] == 'N' || s[0] == '0') - s[0] = '0'; - else - s[0] = '1'; - s[1] = '\0'; + switch (((char *)value)[0]) + { + case 'f': + case 'F': + case 'n': + case 'N': + case '0': + strcpy(s, "0"); + break; + default: + if (true_is_minus1) + strcpy(s, "-1"); + else + strcpy(s, "1"); + } neut_str = midtemp[mtemp_cnt]; mtemp_cnt++; - } break; @@ -567,7 +578,11 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 rgbValueBindRow = (char *) rgbValue + rgbValueOffset; +#ifdef UNICODE_SUPPORT + if (fCType == SQL_C_CHAR || fCType == SQL_C_WCHAR) +#else if (fCType == SQL_C_CHAR) +#endif /* UNICODE_SUPPORT */ { /* Special character formatting as required */ @@ -599,7 +614,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 break; case PG_TYPE_BOOL: - len = 1; + len = strlen(neut_str); if (cbValueMax > len) { strcpy(rgbValueBindRow, neut_str); @@ -637,8 +652,18 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 pbic = &stmt->bindings[stmt->current_col]; if (pbic->data_left < 0) { + BOOL lf_conv = SC_get_conn(stmt)->connInfo.lf_conversion; +#ifdef UNICODE_SUPPORT + if (fCType == SQL_C_WCHAR) + { + len = utf8_to_ucs2(neut_str, -1, NULL, 0); + len *= 2; + wchanged = changed = TRUE; + } + else +#endif /* UNICODE_SUPPORT */ /* convert linefeeds to carriage-return/linefeed */ - len = convert_linefeeds(neut_str, NULL, 0, &changed); + len = convert_linefeeds(neut_str, NULL, 0, lf_conv, &changed); if (cbValueMax == 0) /* just returns length * info */ { @@ -654,7 +679,14 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 pbic->ttlbuf = realloc(pbic->ttlbuf, len + 1); pbic->ttlbuflen = len + 1; } - convert_linefeeds(neut_str, pbic->ttlbuf, pbic->ttlbuflen, &changed); +#ifdef UNICODE_SUPPORT + if (fCType == SQL_C_WCHAR) + { + utf8_to_ucs2(neut_str, -1, (SQLWCHAR *) pbic->ttlbuf, len / 2); + } + else +#endif /* UNICODE_SUPPORT */ + convert_linefeeds(neut_str, pbic->ttlbuf, pbic->ttlbuflen, lf_conv, &changed); ptr = pbic->ttlbuf; } else @@ -715,7 +747,25 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 mylog(" SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n", len, cbValueMax, rgbValueBindRow); break; } - +#ifdef UNICODE_SUPPORT + if (SQL_C_WCHAR == fCType && ! wchanged) + { + if (cbValueMax > 2 * len) + { + char *str = strdup(rgbValueBindRow); + UInt4 ucount = utf8_to_ucs2(str, len, (SQLWCHAR *) rgbValueBindRow, cbValueMax / 2); + if (cbValueMax < 2 * (SDWORD) ucount) + result = COPY_RESULT_TRUNCATED; + len = ucount * 2; + free(str); + } + else + { + len *= 2; + result = COPY_RESULT_TRUNCATED; + } + } +#endif /* UNICODE_SUPPORT */ } else @@ -1107,11 +1157,11 @@ do { \ */ #define CVT_SPECIAL_CHARS(buf, used) \ do { \ - int cnvlen = convert_special_chars(buf, NULL, used); \ + int cnvlen = convert_special_chars(buf, NULL, used, lf_conv, conn->ccsc); \ unsigned int newlimit = npos + cnvlen; \ \ ENLARGE_NEWSTATEMENT(newlimit); \ - convert_special_chars(buf, &new_statement[npos], used); \ + convert_special_chars(buf, &new_statement[npos], used, lf_conv, conn->ccsc); \ npos += cnvlen; \ } while (0) @@ -1181,9 +1231,9 @@ table_for_update(const char *stmt, int *endpos) } #ifdef MULTIBYTE -#define my_strchr(s1,c1) multibyte_strchr(s1,c1) +#define my_strchr(conn, s1,c1) pg_mbschr(conn->ccsc, s1,c1) #else -#define my_strchr(s1,c1) strchr(s1,c1) +#define my_strchr(conn, s1,c1) strchr(s1,c1) #endif /* * This function inserts parameters into an SQL statements. @@ -1213,8 +1263,7 @@ copy_statement_with_parameters(StatementClass *stmt) time_t t = time(NULL); struct tm *tim; SDWORD used; - char *buffer, - *buf; + char *buffer, *buf, *allocbuf; BOOL in_quote = FALSE, in_dquote = FALSE, in_escape = FALSE; @@ -1234,6 +1283,10 @@ copy_statement_with_parameters(StatementClass *stmt) BOOL prev_token_end; UInt4 offset = stmt->options.param_offset_ptr ? *stmt->options.param_offset_ptr : 0; UInt4 current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row; + BOOL lf_conv = ci->lf_conversion; +#ifdef MULTIBYTE + encoded_str encstr; +#endif /* MULTIBYTE */ #ifdef DRIVER_CURSOR_IMPLEMENT BOOL search_from_pos = FALSE; @@ -1311,14 +1364,14 @@ copy_statement_with_parameters(StatementClass *stmt) } param_number = -1; #ifdef MULTIBYTE - multibyte_init(); + make_encoded_str(&encstr, conn, old_statement); #endif for (opos = 0; opos < oldstmtlen; opos++) { - oldchar = old_statement[opos]; #ifdef MULTIBYTE - if (multibyte_char_check(oldchar) != 0) + oldchar = encoded_byte_check(&encstr, opos); + if (ENCODE_STATUS(encstr) != 0) { CVT_APPEND_CHAR(oldchar); continue; @@ -1327,6 +1380,8 @@ copy_statement_with_parameters(StatementClass *stmt) /* * From here we are guaranteed to handle a 1-byte character. */ +#else + oldchar = old_statement[opos]; #endif if (in_escape) /* escape check */ @@ -1352,7 +1407,7 @@ copy_statement_with_parameters(StatementClass *stmt) * nor a double quote. */ /* Squeeze carriage-return/linefeed pairs to linefeed only */ - else if (oldchar == '\r' && opos + 1 < oldstmtlen && + else if (lf_conv && oldchar == '\r' && opos + 1 < oldstmtlen && old_statement[opos + 1] == '\n') continue; @@ -1390,11 +1445,12 @@ copy_statement_with_parameters(StatementClass *stmt) } opos += lit_call_len; CVT_APPEND_STR("SELECT "); - if (my_strchr(&old_statement[opos], '(')) + if (my_strchr(conn, &old_statement[opos], '(')) proc_no_param = FALSE; continue; } - if (convert_escape(begin, stmt, &npos, &new_stsize, &end) != CONVERT_ESCAPE_OK) + if (convert_escape(begin, stmt, &npos, &new_stsize, &end +) != CONVERT_ESCAPE_OK) { stmt->errormsg = "ODBC escape convert error"; stmt->errornumber = STMT_EXEC_ERROR; @@ -1585,7 +1641,7 @@ copy_statement_with_parameters(StatementClass *stmt) if (param_ctype == SQL_C_DEFAULT) param_ctype = sqltype_to_default_ctype(param_sqltype); - buf = NULL; + allocbuf = buf = NULL; param_string[0] = '\0'; cbuf[0] = '\0'; @@ -1597,6 +1653,13 @@ copy_statement_with_parameters(StatementClass *stmt) buf = buffer; break; +#ifdef UNICODE_SUPPORT + case SQL_C_WCHAR: + buf = allocbuf = ucs2_to_utf8((SQLWCHAR *) buffer, used / 2, &used); + used *= 2; + break; +#endif /* UNICODE_SUPPORT */ + case SQL_C_DOUBLE: sprintf(param_string, "%.15g", *((SDOUBLE *) buffer)); @@ -1729,6 +1792,11 @@ copy_statement_with_parameters(StatementClass *stmt) case SQL_CHAR: case SQL_VARCHAR: case SQL_LONGVARCHAR: +#ifdef UNICODE_SUPPORT + case SQL_WCHAR: + case SQL_WVARCHAR: + case SQL_WLONGVARCHAR: +#endif /* UNICODE_SUPPORT */ CVT_APPEND_CHAR('\''); /* Open Quote */ @@ -1801,7 +1869,7 @@ copy_statement_with_parameters(StatementClass *stmt) tmp[0] = '\''; /* Time zone stuff is unreliable */ stime2timestamp(&st, tmp + 1, USE_ZONE, PG_VERSION_GE(conn, 7.2)); - strcat(tmp, "'"); + strcat(tmp, "'::timestamp"); CVT_APPEND_STR(tmp); @@ -1942,6 +2010,10 @@ copy_statement_with_parameters(StatementClass *stmt) break; } +#ifdef UNICODE_SUPPORT + if (allocbuf) + free(allocbuf); +#endif /* UNICODE_SUPPORT */ } /* end, for */ /* make sure new_statement is always null-terminated */ @@ -2032,7 +2104,7 @@ int inner_convert_escape(const ConnectionClass *conn, const char *value, while ((*valptr != '\0') && isspace((unsigned char) *valptr)) valptr++; - if (end = my_strchr(valptr, '}'), NULL == end) + if (end = my_strchr(conn, valptr, '}'), NULL == end) { mylog("%s couldn't find the ending }\n",func); return CONVERT_ESCAPE_ERROR; @@ -2226,13 +2298,16 @@ int processParameters(const ConnectionClass *conn, const char *value, const char *valptr; char buf[1024]; BOOL in_quote, in_dquote, in_escape, leadingSpace; +#ifdef MULTIBYTE + encoded_str encstr; +#endif /* MULTIBYTE */ buf[sizeof(buf)-1] = '\0'; innerParenthesis = 0; in_quote = in_dquote = in_escape = leadingSpace = FALSE; param_count = 0; #ifdef MULTIBYTE - multibyte_init(); + make_encoded_str(&encstr, conn, value); #endif /* MULTIBYTE */ /* begin with outer '(' */ for (stop = FALSE, valptr = value, ipos = count = 0; *valptr != '\0'; ipos++, valptr++) @@ -2250,7 +2325,8 @@ int processParameters(const ConnectionClass *conn, const char *value, return CONVERT_ESCAPE_OVERFLOW; } #ifdef MULTIBYTE - if (multibyte_char_check(*valptr) != 0) + encoded_byte_check(&encstr, ipos); + if (ENCODE_STATUS(encstr) != 0) { result[count++] = *valptr; continue; @@ -2468,7 +2544,7 @@ parse_datetime(char *buf, SIMPLE_TIME *st) /* Change linefeed to carriage-return/linefeed */ int -convert_linefeeds(const char *si, char *dst, size_t max, BOOL *changed) +convert_linefeeds(const char *si, char *dst, size_t max, BOOL convlf, BOOL *changed) { size_t i = 0, out = 0; @@ -2478,7 +2554,7 @@ convert_linefeeds(const char *si, char *dst, size_t max, BOOL *changed) *changed = FALSE; for (i = 0; si[i] && out < max - 1; i++) { - if (si[i] == '\n') + if (convlf && si[i] == '\n') { /* Only add the carriage-return if needed */ if (i > 0 && si[i - 1] == '\r') @@ -2518,12 +2594,15 @@ convert_linefeeds(const char *si, char *dst, size_t max, BOOL *changed) * Plus, escape any special characters. */ int -convert_special_chars(const char *si, char *dst, int used) +convert_special_chars(const char *si, char *dst, int used, BOOL convlf, int ccsc) { size_t i = 0, out = 0, max; char *p = NULL; +#ifdef MULTIBYTE + encoded_str encstr; +#endif if (used == SQL_NTS) @@ -2536,13 +2615,14 @@ convert_special_chars(const char *si, char *dst, int used) p[0] = '\0'; } #ifdef MULTIBYTE - multibyte_init(); + encoded_str_constr(&encstr, ccsc, si); #endif for (i = 0; i < max && si[i]; i++) { #ifdef MULTIBYTE - if (multibyte_char_check(si[i]) != 0) + encoded_nextchar(&encstr); + if (ENCODE_STATUS(encstr) != 0) { if (p) p[out] = si[i]; @@ -2550,7 +2630,7 @@ convert_special_chars(const char *si, char *dst, int used) continue; } #endif - if (si[i] == '\r' && si[i + 1] == '\n') + if (convlf && si[i] == '\r' && si[i + 1] == '\n') continue; else if (si[i] == '\'' || si[i] == '\\') { diff --git a/src/interfaces/odbc/convert.h b/src/interfaces/odbc/convert.h index b06f72f3541..2d5f01859f0 100644 --- a/src/interfaces/odbc/convert.h +++ b/src/interfaces/odbc/convert.h @@ -21,7 +21,7 @@ /* convert_escape results */ #define CONVERT_ESCAPE_OK 0 #define CONVERT_ESCAPE_OVERFLOW 1 -#define CONVERT_ESCAPE_ERROR 2 +#define CONVERT_ESCAPE_ERROR -1 typedef struct { @@ -43,8 +43,8 @@ int convert_escape(const char *value, StatementClass *stmt, int *npos, int *stsize, const char **val_resume); BOOL convert_money(const char *s, char *sout, size_t soutmax); char parse_datetime(char *buf, SIMPLE_TIME *st); -int convert_linefeeds(const char *s, char *dst, size_t max, BOOL *changed); -int convert_special_chars(const char *si, char *dst, int used); +int convert_linefeeds(const char *s, char *dst, size_t max, BOOL convlf, BOOL *changed); +int convert_special_chars(const char *si, char *dst, int used, BOOL convlf,int ccsc); int convert_pgbinary_to_char(const char *value, char *rgbValue, int cbValueMax); int convert_from_pgbinary(const unsigned char *value, unsigned char *rgbValue, int cbValueMax); diff --git a/src/interfaces/odbc/dlg_specific.c b/src/interfaces/odbc/dlg_specific.c index f23fb9c527f..4fbf037cec2 100644 --- a/src/interfaces/odbc/dlg_specific.c +++ b/src/interfaces/odbc/dlg_specific.c @@ -123,7 +123,7 @@ driver_optionsDraw(HWND hdlg, const ConnInfo *ci, int src, BOOL enable) CheckDlgButton(hdlg, DRV_OPTIMIZER, comval->disable_optimizer); CheckDlgButton(hdlg, DRV_KSQO, comval->ksqo); CheckDlgButton(hdlg, DRV_UNIQUEINDEX, comval->unique_index); - EnableWindow(GetDlgItem(hdlg, DRV_UNIQUEINDEX), enable); + /* EnableWindow(GetDlgItem(hdlg, DRV_UNIQUEINDEX), enable); */ CheckDlgButton(hdlg, DRV_READONLY, comval->onlyread); EnableWindow(GetDlgItem(hdlg, DRV_READONLY), enable); CheckDlgButton(hdlg, DRV_USEDECLAREFETCH, comval->use_declarefetch); @@ -332,6 +332,8 @@ ds_optionsProc(HWND hdlg, CheckDlgButton(hdlg, DS_ROWVERSIONING, atoi(ci->row_versioning)); CheckDlgButton(hdlg, DS_SHOWSYSTEMTABLES, atoi(ci->show_system_tables)); CheckDlgButton(hdlg, DS_DISALLOWPREMATURE, ci->disallow_premature); + CheckDlgButton(hdlg, DS_LFCONVERSION, ci->lf_conversion); + CheckDlgButton(hdlg, DS_TRUEISMINUS1, ci->true_is_minus1); EnableWindow(GetDlgItem(hdlg, DS_FAKEOIDINDEX), atoi(ci->show_oid_column)); @@ -367,6 +369,8 @@ ds_optionsProc(HWND hdlg, sprintf(ci->row_versioning, "%d", IsDlgButtonChecked(hdlg, DS_ROWVERSIONING)); ci->disallow_premature = IsDlgButtonChecked(hdlg, DS_DISALLOWPREMATURE); + ci->lf_conversion = IsDlgButtonChecked(hdlg, DS_LFCONVERSION); + ci->true_is_minus1 = IsDlgButtonChecked(hdlg, DS_TRUEISMINUS1); /* OID Options */ sprintf(ci->fake_oid_index, "%d", IsDlgButtonChecked(hdlg, DS_FAKEOIDINDEX)); @@ -525,60 +529,186 @@ makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len) hlen = strlen(connect_string); if (!abbrev) sprintf(&connect_string[hlen], - ";READONLY=%s;PROTOCOL=%s;FAKEOIDINDEX=%s;SHOWOIDCOLUMN=%s;ROWVERSIONING=%s;SHOWSYSTEMTABLES=%s;CONNSETTINGS=%s;FETCH=%d;SOCKET=%d;UNKNOWNSIZES=%d;MAXVARCHARSIZE=%d;MAXLONGVARCHARSIZE=%d;DEBUG=%d;COMMLOG=%d;OPTIMIZER=%d;KSQO=%d;USEDECLAREFETCH=%d;TEXTASLONGVARCHAR=%d;UNKNOWNSASLONGVARCHAR=%d;BOOLSASCHAR=%d;PARSE=%d;CANCELASFREESTMT=%d;EXTRASYSTABLEPREFIXES=%s", + ";%s=%s;%s=%s;%s=%s;%s=%s;%s=%s;%s=%s;%s=%s;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%s;%s=%d;%s=%d;%s=%d;%s=%d", + INI_READONLY, ci->onlyread, + INI_PROTOCOL, ci->protocol, + INI_FAKEOIDINDEX, ci->fake_oid_index, + INI_SHOWOIDCOLUMN, ci->show_oid_column, + INI_ROWVERSIONING, ci->row_versioning, + INI_SHOWSYSTEMTABLES, ci->show_system_tables, + INI_CONNSETTINGS, encoded_conn_settings, + INI_FETCH, ci->drivers.fetch_max, + INI_SOCKET, ci->drivers.socket_buffersize, + INI_UNKNOWNSIZES, ci->drivers.unknown_sizes, + INI_MAXVARCHARSIZE, ci->drivers.max_varchar_size, + INI_MAXLONGVARCHARSIZE, ci->drivers.max_longvarchar_size, + INI_DEBUG, ci->drivers.debug, + INI_COMMLOG, ci->drivers.commlog, + INI_OPTIMIZER, ci->drivers.disable_optimizer, + INI_KSQO, ci->drivers.ksqo, + INI_USEDECLAREFETCH, ci->drivers.use_declarefetch, + INI_TEXTASLONGVARCHAR, ci->drivers.text_as_longvarchar, + INI_UNKNOWNSASLONGVARCHAR, ci->drivers.unknowns_as_longvarchar, + INI_BOOLSASCHAR, ci->drivers.bools_as_char, + INI_PARSE, ci->drivers.parse, + INI_CANCELASFREESTMT, ci->drivers.cancel_as_freestmt, - ci->drivers.extra_systable_prefixes); + INI_EXTRASYSTABLEPREFIXES, + ci->drivers.extra_systable_prefixes, + INI_LFCONVERSION, + ci->lf_conversion, + INI_UPDATABLECURSORS, + ci->updatable_cursors, + INI_DISALLOWPREMATURE, + ci->disallow_premature, + INI_TRUEISMINUS1, + ci->true_is_minus1); /* Abbrebiation is needed ? */ if (abbrev || strlen(connect_string) >= len) + { + unsigned long flag = 0; + if (ci->disallow_premature) + flag |= BIT_DISALLOWPREMATURE; + if (ci->updatable_cursors) + flag |= BIT_UPDATABLECURSORS; + if (ci->lf_conversion) + flag |= BIT_LFCONVERSION; + if (ci->drivers.unique_index) + flag |= BIT_UNIQUEINDEX; + if (strncmp(ci->protocol, PG64, strlen(PG64)) == 0) + flag |= BIT_PROTOCOL_64; + else if (strncmp(ci->protocol, PG63, strlen(PG63)) == 0) + flag |= BIT_PROTOCOL_63; + switch (ci->drivers.unknown_sizes) + { + case UNKNOWNS_AS_DONTKNOW: + flag |= BIT_UNKNOWN_DONTKNOW; + break; + case UNKNOWNS_AS_MAX: + flag |= BIT_UNKNOWN_ASMAX; + break; + } + if (ci->drivers.disable_optimizer) + flag |= BIT_OPTIMIZER; + if (ci->drivers.ksqo) + flag |= BIT_KSQO; + if (ci->drivers.commlog) + flag |= BIT_COMMLOG; + if (ci->drivers.debug) + flag |= BIT_DEBUG; + if (ci->drivers.parse) + flag |= BIT_PARSE; + if (ci->drivers.cancel_as_freestmt) + flag |= BIT_CANCELASFREESTMT; + if (ci->drivers.use_declarefetch) + flag |= BIT_USEDECLAREFETCH; + if (ci->onlyread[0] == '1') + flag |= BIT_READONLY; + if (ci->drivers.text_as_longvarchar) + flag |= BIT_TEXTASLONGVARCHAR; + if (ci->drivers.unknowns_as_longvarchar) + flag |= BIT_UNKNOWNSASLONGVARCHAR; + if (ci->drivers.bools_as_char) + flag |= BIT_BOOLSASCHAR; + if (ci->row_versioning[0] == '1') + flag |= BIT_ROWVERSIONING; + if (ci->show_system_tables[0] == '1') + flag |= BIT_SHOWSYSTEMTABLES; + if (ci->show_oid_column[0] == '1') + flag |= BIT_SHOWOIDCOLUMN; + if (ci->fake_oid_index[0] == '1') + flag |= BIT_FAKEOIDINDEX; + if (ci->true_is_minus1) + flag |= BIT_TRUEISMINUS1; + sprintf(&connect_string[hlen], - ";A0=%s;A1=%s;A2=%s;A3=%s;A4=%s;A5=%s;A6=%s;A7=%d;A8=%d;A9=%d;B0=%d;B1=%d;B2=%d;B3=%d;B4=%d;B5=%d;B6=%d;B7=%d;B8=%d;B9=%d;C0=%d;C1=%d;C2=%s", - ci->onlyread, - ci->protocol, - ci->fake_oid_index, - ci->show_oid_column, - ci->row_versioning, - ci->show_system_tables, + ";A6=%s;A7=%d;A8=%d;B0=%d;B1=%d;C2=%s;CX=%02x%x", encoded_conn_settings, ci->drivers.fetch_max, ci->drivers.socket_buffersize, - ci->drivers.unknown_sizes, ci->drivers.max_varchar_size, ci->drivers.max_longvarchar_size, - ci->drivers.debug, - ci->drivers.commlog, - ci->drivers.disable_optimizer, - ci->drivers.ksqo, - ci->drivers.use_declarefetch, - ci->drivers.text_as_longvarchar, - ci->drivers.unknowns_as_longvarchar, - ci->drivers.bools_as_char, - ci->drivers.parse, - ci->drivers.cancel_as_freestmt, - ci->drivers.extra_systable_prefixes); + ci->drivers.extra_systable_prefixes, + EFFECTIVE_BIT_COUNT, + flag); + } } +static void +unfoldCXAttribute(ConnInfo *ci, const char *value) +{ + int count; + unsigned long flag; + if (strlen(value) < 2) + { + count = 3; + sscanf(value, "%x", &flag); + } + else + { + char cnt[8]; + memcpy(cnt, value, 2); + cnt[2] = '\0'; + sscanf(cnt, "%x", &count); + sscanf(value + 2, "%x", &flag); + } + ci->disallow_premature = (char)((flag & BIT_DISALLOWPREMATURE) != 0); + ci->updatable_cursors = (char)((flag & BIT_UPDATABLECURSORS) != 0); + ci->lf_conversion = (char)((flag & BIT_LFCONVERSION) != 0); + if (count < 4) + return; + ci->drivers.unique_index = (char)((flag & BIT_UNIQUEINDEX) != 0); + if ((flag & BIT_PROTOCOL_64) != 0) + strcpy(ci->protocol, PG64); + else if ((flag & BIT_PROTOCOL_63) != 0) + strcpy(ci->protocol, PG63); + else + strcpy(ci->protocol, PG62); + if ((flag & BIT_UNKNOWN_DONTKNOW) != 0) + ci->drivers.unknown_sizes = UNKNOWNS_AS_DONTKNOW; + else if ((flag & BIT_UNKNOWN_ASMAX) != 0) + ci->drivers.unknown_sizes = UNKNOWNS_AS_MAX; + else + ci->drivers.unknown_sizes = UNKNOWNS_AS_LONGEST; + ci->drivers.disable_optimizer = (char)((flag & BIT_OPTIMIZER) != 0); + ci->drivers.ksqo = (char)((flag & BIT_KSQO) != 0); + ci->drivers.commlog = (char)((flag & BIT_COMMLOG) != 0); + ci->drivers.debug = (char)((flag & BIT_DEBUG) != 0); + ci->drivers.parse = (char)((flag & BIT_PARSE) != 0); + ci->drivers.cancel_as_freestmt = (char)((flag & BIT_CANCELASFREESTMT) != 0); + ci->drivers.use_declarefetch = (char)((flag & BIT_USEDECLAREFETCH) != 0); + sprintf(ci->onlyread, "%d", (char)((flag & BIT_READONLY) != 0)); + ci->drivers.text_as_longvarchar = (char)((flag & BIT_TEXTASLONGVARCHAR) !=0); + ci->drivers.unknowns_as_longvarchar = (char)((flag & BIT_UNKNOWNSASLONGVARCHAR) !=0); + ci->drivers.bools_as_char = (char)((flag & BIT_BOOLSASCHAR) != 0); + sprintf(ci->row_versioning, "%d", (char)((flag & BIT_ROWVERSIONING) != 0)); + sprintf(ci->show_system_tables, "%d", (char)((flag & BIT_SHOWSYSTEMTABLES) != 0)); + sprintf(ci->show_oid_column, "%d", (char)((flag & BIT_SHOWOIDCOLUMN) != 0)); + sprintf(ci->fake_oid_index, "%d", (char)((flag & BIT_FAKEOIDINDEX) != 0)); + ci->true_is_minus1 = (char)((flag & BIT_TRUEISMINUS1) != 0); +} void copyAttributes(ConnInfo *ci, const char *attribute, const char *value) { @@ -630,6 +760,12 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value) ci->disallow_premature = atoi(value); else if (stricmp(attribute, INI_UPDATABLECURSORS) == 0 || stricmp(attribute, "C4") == 0) ci->updatable_cursors = atoi(value); + else if (stricmp(attribute, INI_LFCONVERSION) == 0) + ci->lf_conversion = atoi(value); + else if (stricmp(attribute, INI_TRUEISMINUS1) == 0) + ci->true_is_minus1 = atoi(value); + else if (stricmp(attribute, "CX") == 0) + unfoldCXAttribute(ci, value); mylog("copyAttributes: DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',onlyread='%s',protocol='%s',conn_settings='%s',disallow_premature=%d)\n", ci->dsn, ci->server, ci->database, ci->username, ci->password, ci->port, ci->onlyread, ci->protocol, ci->conn_settings, ci->disallow_premature); } @@ -720,6 +856,15 @@ getDSNdefaults(ConnInfo *ci) if (ci->row_versioning[0] == '\0') sprintf(ci->row_versioning, "%d", DEFAULT_ROWVERSIONING); + + if (ci->disallow_premature < 0) + ci->disallow_premature = DEFAULT_DISALLOWPREMATURE; + if (ci->updatable_cursors < 0) + ci->updatable_cursors = DEFAULT_UPDATABLECURSORS; + if (ci->lf_conversion < 0) + ci->lf_conversion = DEFAULT_LFCONVERSION; + if (ci->true_is_minus1 < 0) + ci->true_is_minus1 = DEFAULT_TRUEISMINUS1; } @@ -797,16 +942,32 @@ getDSNinfo(ConnInfo *ci, char overwrite) if (ci->translation_option[0] == '\0' || overwrite) SQLGetPrivateProfileString(DSN, INI_TRANSLATIONOPTION, "", ci->translation_option, sizeof(ci->translation_option), ODBC_INI); - if (ci->disallow_premature == 0 || overwrite) + if (ci->disallow_premature < 0 || overwrite) { SQLGetPrivateProfileString(DSN, INI_DISALLOWPREMATURE, "", temp, sizeof(temp), ODBC_INI); - ci->disallow_premature = atoi(temp); + if (temp[0]) + ci->disallow_premature = atoi(temp); } - if (ci->updatable_cursors == 0 || overwrite) + if (ci->updatable_cursors < 0 || overwrite) { SQLGetPrivateProfileString(DSN, INI_UPDATABLECURSORS, "", temp, sizeof(temp), ODBC_INI); - ci->updatable_cursors = atoi(temp); + if (temp[0]) + ci->updatable_cursors = atoi(temp); + } + + if (ci->lf_conversion < 0 || overwrite) + { + SQLGetPrivateProfileString(DSN, INI_LFCONVERSION, "", temp, sizeof(temp), ODBC_INI); + if (temp[0]) + ci->lf_conversion = atoi(temp); + } + + if (ci->true_is_minus1 < 0 || overwrite) + { + SQLGetPrivateProfileString(DSN, INI_TRUEISMINUS1, "", temp, sizeof(temp), ODBC_INI); + if (temp[0]) + ci->true_is_minus1 = atoi(temp); } /* Allow override of odbcinst.ini parameters here */ @@ -927,6 +1088,16 @@ writeDSNinfo(const ConnInfo *ci) INI_UPDATABLECURSORS, temp, ODBC_INI); + sprintf(temp, "%d", ci->lf_conversion); + SQLWritePrivateProfileString(DSN, + INI_LFCONVERSION, + temp, + ODBC_INI); + sprintf(temp, "%d", ci->true_is_minus1); + SQLWritePrivateProfileString(DSN, + INI_TRUEISMINUS1, + temp, + ODBC_INI); } diff --git a/src/interfaces/odbc/dlg_specific.h b/src/interfaces/odbc/dlg_specific.h index b3192123d0f..f293079d35f 100644 --- a/src/interfaces/odbc/dlg_specific.h +++ b/src/interfaces/odbc/dlg_specific.h @@ -89,6 +89,35 @@ #define INI_TRANSLATIONOPTION "TranslationOption" #define INI_DISALLOWPREMATURE "DisallowPremature" #define INI_UPDATABLECURSORS "UpdatableCursors" +#define INI_LFCONVERSION "LFConversion" +#define INI_TRUEISMINUS1 "TrueIsMinus1" +/* Bit representaion for abbreviated connection strings */ +#define BIT_LFCONVERSION (1L) +#define BIT_UPDATABLECURSORS (1L<<1) +#define BIT_DISALLOWPREMATURE (1L<<2) +#define BIT_UNIQUEINDEX (1L<<3) +#define BIT_PROTOCOL_63 (1L<<4) +#define BIT_PROTOCOL_64 (1L<<5) +#define BIT_UNKNOWN_DONTKNOW (1L<<6) +#define BIT_UNKNOWN_ASMAX (1L<<7) +#define BIT_OPTIMIZER (1L<<8) +#define BIT_KSQO (1L<<9) +#define BIT_COMMLOG (1L<<10) +#define BIT_DEBUG (1L<<11) +#define BIT_PARSE (1L<<12) +#define BIT_CANCELASFREESTMT (1L<<13) +#define BIT_USEDECLAREFETCH (1L<<14) +#define BIT_READONLY (1L<<15) +#define BIT_TEXTASLONGVARCHAR (1L<<16) +#define BIT_UNKNOWNSASLONGVARCHAR (1L<<17) +#define BIT_BOOLSASCHAR (1L<<18) +#define BIT_ROWVERSIONING (1L<<19) +#define BIT_SHOWSYSTEMTABLES (1L<<20) +#define BIT_SHOWOIDCOLUMN (1L<<21) +#define BIT_FAKEOIDINDEX (1L<<22) +#define BIT_TRUEISMINUS1 (1L<<23) + +#define EFFECTIVE_BIT_COUNT 24 /* Connection Defaults */ @@ -119,6 +148,19 @@ #define DEFAULT_EXTRASYSTABLEPREFIXES "dd_;" +#define DEFAULT_DISALLOWPREMATURE 0 +#define DEFAULT_TRUEISMINUS1 0 +#ifdef DRIVER_CURSOR_IMPLEMENT +#define DEFAULT_UPDATABLECURSORS 1 +#else +#define DEFAULT_UPDATABLECURSORS 0 +#endif /* DRIVER_CURSOR_IMPLEMENT */ +#ifdef WIN32 +#define DEFAULT_LFCONVERSION 1 +#else +#define DEFAULT_LFCONVERSION 0 +#endif /* WIN32 */ + /* prototypes */ void getCommonDefaults(const char *section, const char *filename, ConnInfo *ci); diff --git a/src/interfaces/odbc/drvconn.c b/src/interfaces/odbc/drvconn.c index e369525ca02..e07cec3e8c1 100644 --- a/src/interfaces/odbc/drvconn.c +++ b/src/interfaces/odbc/drvconn.c @@ -242,7 +242,7 @@ dialog: qlog("conn=%u, PGAPI_DriverConnect(out)='%s'\n", conn, szConnStrOut); - mylog("PGAPI_DRiverConnect: returning %d\n", result); + mylog("PGAPI_DriverConnect: returning %d\n", result); return result; } @@ -351,10 +351,7 @@ dconn_get_connect_attributes(const UCHAR FAR * connect_string, ConnInfo *ci) *equals; char *strtok_arg; - memset(ci, 0, sizeof(ConnInfo)); -#ifdef DRIVER_CURSOR_IMPLEMENT - ci->updatable_cursors = 1; -#endif /* DRIVER_CURSOR_IMPLEMENT */ + CC_conninfo_init(ci); our_connect_string = strdup(connect_string); strtok_arg = our_connect_string; diff --git a/src/interfaces/odbc/environ.c b/src/interfaces/odbc/environ.c index 1113ca57ac6..69718a19149 100644 --- a/src/interfaces/odbc/environ.c +++ b/src/interfaces/odbc/environ.c @@ -78,408 +78,450 @@ PGAPI_FreeEnv(HENV henv) } +#define DRVMNGRDIV 511 /* Returns the next SQL error information. */ RETCODE SQL_API -PGAPI_Error( - HENV henv, - HDBC hdbc, - HSTMT hstmt, +PGAPI_StmtError( HSTMT hstmt, + SWORD RecNumber, UCHAR FAR * szSqlState, SDWORD FAR * pfNativeError, UCHAR FAR * szErrorMsg, SWORD cbErrorMsgMax, - SWORD FAR * pcbErrorMsg) + SWORD FAR * pcbErrorMsg, + UWORD flag) { - char *msg; - int status; - BOOL once_again = FALSE; - SWORD msglen; + /* CC: return an error of a hstmt */ + StatementClass *stmt = (StatementClass *) hstmt; + char *msg; + int status; + BOOL once_again = FALSE, + partial_ok = (flag & PODBC_ALLOW_PARTIAL_EXTRACT != 0), + clear_str = (flag & PODBC_ERROR_CLEAR != 0); + SWORD msglen, stapos, wrtlen, pcblen; - mylog("**** PGAPI_Error: henv=%u, hdbc=%u, hstmt=%u <%d>\n", henv, hdbc, hstmt, cbErrorMsgMax); + mylog("**** PGAPI_StmtError: hstmt=%u <%d>\n", hstmt, cbErrorMsgMax); if (cbErrorMsgMax < 0) return SQL_ERROR; - if (SQL_NULL_HSTMT != hstmt) - { - /* CC: return an error of a hstmt */ - StatementClass *stmt = (StatementClass *) hstmt; - if (SC_get_error(stmt, &status, &msg)) - { - mylog("SC_get_error: status = %d, msg = #%s#\n", status, msg); - if (NULL == msg) - { - if (NULL != szSqlState) - strcpy(szSqlState, "00000"); - if (NULL != pcbErrorMsg) - *pcbErrorMsg = 0; - if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) - szErrorMsg[0] = '\0'; - - return SQL_NO_DATA_FOUND; - } - msglen = (SWORD) strlen(msg); - if (NULL != pcbErrorMsg) - { - *pcbErrorMsg = msglen; - if (cbErrorMsgMax == 0) - once_again = TRUE; - else if (msglen >= cbErrorMsgMax) - { - once_again = TRUE; - *pcbErrorMsg = cbErrorMsgMax - 1; - } - } - - if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) - strncpy_null(szErrorMsg, msg, cbErrorMsgMax); - - if (NULL != pfNativeError) - *pfNativeError = status; - - if (NULL != szSqlState) - - switch (status) - { - /* now determine the SQLSTATE to be returned */ - case STMT_ROW_VERSION_CHANGED: - strcpy(szSqlState, "01001"); - /* data truncated */ - break; - case STMT_TRUNCATED: - strcpy(szSqlState, "01004"); - /* data truncated */ - break; - case STMT_INFO_ONLY: - strcpy(szSqlState, "00000"); - /* just information that is returned, no error */ - break; - case STMT_BAD_ERROR: - strcpy(szSqlState, "08S01"); - /* communication link failure */ - break; - case STMT_CREATE_TABLE_ERROR: - strcpy(szSqlState, "S0001"); - /* table already exists */ - break; - case STMT_STATUS_ERROR: - case STMT_SEQUENCE_ERROR: - strcpy(szSqlState, "S1010"); - /* Function sequence error */ - break; - case STMT_NO_MEMORY_ERROR: - strcpy(szSqlState, "S1001"); - /* memory allocation failure */ - break; - case STMT_COLNUM_ERROR: - strcpy(szSqlState, "S1002"); - /* invalid column number */ - break; - case STMT_NO_STMTSTRING: - strcpy(szSqlState, "S1001"); - /* having no stmtstring is also a malloc problem */ - break; - case STMT_ERROR_TAKEN_FROM_BACKEND: - strcpy(szSqlState, "S1000"); - /* general error */ - break; - case STMT_INTERNAL_ERROR: - strcpy(szSqlState, "S1000"); - /* general error */ - break; - case STMT_ROW_OUT_OF_RANGE: - strcpy(szSqlState, "S1107"); - break; - - case STMT_OPERATION_CANCELLED: - strcpy(szSqlState, "S1008"); - break; - - case STMT_NOT_IMPLEMENTED_ERROR: - strcpy(szSqlState, "S1C00"); /* == 'driver not - * capable' */ - break; - case STMT_OPTION_OUT_OF_RANGE_ERROR: - strcpy(szSqlState, "S1092"); - break; - case STMT_BAD_PARAMETER_NUMBER_ERROR: - strcpy(szSqlState, "S1093"); - break; - case STMT_INVALID_COLUMN_NUMBER_ERROR: - strcpy(szSqlState, "S1002"); - break; - case STMT_RESTRICTED_DATA_TYPE_ERROR: - strcpy(szSqlState, "07006"); - break; - case STMT_INVALID_CURSOR_STATE_ERROR: - strcpy(szSqlState, "24000"); - break; - case STMT_OPTION_VALUE_CHANGED: - strcpy(szSqlState, "01S02"); - break; - case STMT_POS_BEFORE_RECORDSET: - strcpy(szSqlState, "01S06"); - break; - case STMT_INVALID_CURSOR_NAME: - strcpy(szSqlState, "34000"); - break; - case STMT_NO_CURSOR_NAME: - strcpy(szSqlState, "S1015"); - break; - case STMT_INVALID_ARGUMENT_NO: - strcpy(szSqlState, "S1009"); - /* invalid argument value */ - break; - case STMT_INVALID_CURSOR_POSITION: - strcpy(szSqlState, "S1109"); - break; - case STMT_RETURN_NULL_WITHOUT_INDICATOR: - strcpy(szSqlState, "22002"); - break; - case STMT_VALUE_OUT_OF_RANGE: - strcpy(szSqlState, "22003"); - break; - case STMT_OPERATION_INVALID: - strcpy(szSqlState, "S1011"); - break; - case STMT_INVALID_OPTION_IDENTIFIER: - strcpy(szSqlState, "HY092"); - break; - case STMT_EXEC_ERROR: - default: - strcpy(szSqlState, "S1000"); - /* also a general error */ - break; - } - mylog(" szSqlState = '%s', szError='%s'\n", szSqlState, szErrorMsg); - } + if (!SC_get_error(stmt, &status, &msg) || NULL == msg || !msg[0]) + { + mylog("SC_Get_error returned nothing.\n"); + if (NULL != szSqlState) + strcpy(szSqlState, "00000"); + if (NULL != pcbErrorMsg) + *pcbErrorMsg = 0; + if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) + szErrorMsg[0] = '\0'; + + return SQL_NO_DATA_FOUND; + } + mylog("SC_get_error: status = %d, msg = #%s#\n", status, msg); + msglen = (SWORD) strlen(msg); + /* + * Even though an application specifies a larger error message + * buffer, the driver manager changes it silently. + * Therefore we divide the error message into ... + */ + if (stmt->error_recsize < 0) + { + if (cbErrorMsgMax > 0) + stmt->error_recsize = cbErrorMsgMax - 1; /* apply the first request */ else - { - if (NULL != szSqlState) - strcpy(szSqlState, "00000"); - if (NULL != pcbErrorMsg) - *pcbErrorMsg = 0; - if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) - szErrorMsg[0] = '\0'; + stmt->error_recsize = DRVMNGRDIV; + } + if (RecNumber < 0) + { + if (0 == stmt->errorpos) + RecNumber = 1; + else + RecNumber = 2 + (stmt->errorpos - 1) / stmt->error_recsize; + } + stapos = (RecNumber - 1) * stmt->error_recsize; + if (stapos > msglen) + return SQL_NO_DATA_FOUND; + pcblen = wrtlen = msglen - stapos; + if (pcblen > stmt->error_recsize) + pcblen = stmt->error_recsize; + if (0 == cbErrorMsgMax) + wrtlen = 0; + else if (wrtlen >= cbErrorMsgMax) + { + if (partial_ok) + wrtlen = cbErrorMsgMax - 1; + else if (cbErrorMsgMax <= stmt->error_recsize) + wrtlen = 0; + else + wrtlen = stmt->error_recsize; + } + if (wrtlen > pcblen) + wrtlen = pcblen; + if (NULL != pcbErrorMsg) + *pcbErrorMsg = pcblen; - mylog(" returning NO_DATA_FOUND\n"); + if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) + { + memcpy(szErrorMsg, msg + stapos, wrtlen); + szErrorMsg[wrtlen] = '\0'; + } - return SQL_NO_DATA_FOUND; - } + if (NULL != pfNativeError) + *pfNativeError = status; + + if (NULL != szSqlState) - if (once_again) + switch (status) { - int outlen; - - stmt->errornumber = status; - if (cbErrorMsgMax > 0) - outlen = *pcbErrorMsg; - else - outlen = 0; - if (!stmt->errormsg_malloced || !stmt->errormsg) - { - stmt->errormsg = malloc(msglen - outlen + 1); - stmt->errormsg_malloced = TRUE; - } - memmove(stmt->errormsg, msg + outlen, msglen - outlen + 1); + /* now determine the SQLSTATE to be returned */ + case STMT_ROW_VERSION_CHANGED: + strcpy(szSqlState, "01001"); + /* data truncated */ + break; + case STMT_TRUNCATED: + strcpy(szSqlState, "01004"); + /* data truncated */ + break; + case STMT_INFO_ONLY: + strcpy(szSqlState, "00000"); + /* just information that is returned, no error */ + break; + case STMT_BAD_ERROR: + strcpy(szSqlState, "08S01"); + /* communication link failure */ + break; + case STMT_CREATE_TABLE_ERROR: + strcpy(szSqlState, "S0001"); + /* table already exists */ + break; + case STMT_STATUS_ERROR: + case STMT_SEQUENCE_ERROR: + strcpy(szSqlState, "S1010"); + /* Function sequence error */ + break; + case STMT_NO_MEMORY_ERROR: + strcpy(szSqlState, "S1001"); + /* memory allocation failure */ + break; + case STMT_COLNUM_ERROR: + strcpy(szSqlState, "S1002"); + /* invalid column number */ + break; + case STMT_NO_STMTSTRING: + strcpy(szSqlState, "S1001"); + /* having no stmtstring is also a malloc problem */ + break; + case STMT_ERROR_TAKEN_FROM_BACKEND: + strcpy(szSqlState, "S1000"); + /* general error */ + break; + case STMT_INTERNAL_ERROR: + strcpy(szSqlState, "S1000"); + /* general error */ + break; + case STMT_ROW_OUT_OF_RANGE: + strcpy(szSqlState, "S1107"); + break; + + case STMT_OPERATION_CANCELLED: + strcpy(szSqlState, "S1008"); + break; + + case STMT_NOT_IMPLEMENTED_ERROR: + strcpy(szSqlState, "S1C00"); /* == 'driver not + * capable' */ + break; + case STMT_OPTION_OUT_OF_RANGE_ERROR: + strcpy(szSqlState, "S1092"); + break; + case STMT_BAD_PARAMETER_NUMBER_ERROR: + strcpy(szSqlState, "S1093"); + break; + case STMT_INVALID_COLUMN_NUMBER_ERROR: + strcpy(szSqlState, "S1002"); + break; + case STMT_RESTRICTED_DATA_TYPE_ERROR: + strcpy(szSqlState, "07006"); + break; + case STMT_INVALID_CURSOR_STATE_ERROR: + strcpy(szSqlState, "24000"); + break; + case STMT_OPTION_VALUE_CHANGED: + strcpy(szSqlState, "01S02"); + break; + case STMT_POS_BEFORE_RECORDSET: + strcpy(szSqlState, "01S06"); + break; + case STMT_INVALID_CURSOR_NAME: + strcpy(szSqlState, "34000"); + break; + case STMT_NO_CURSOR_NAME: + strcpy(szSqlState, "S1015"); + break; + case STMT_INVALID_ARGUMENT_NO: + strcpy(szSqlState, "S1009"); + /* invalid argument value */ + break; + case STMT_INVALID_CURSOR_POSITION: + strcpy(szSqlState, "S1109"); + break; + case STMT_RETURN_NULL_WITHOUT_INDICATOR: + strcpy(szSqlState, "22002"); + break; + case STMT_VALUE_OUT_OF_RANGE: + strcpy(szSqlState, "22003"); + break; + case STMT_OPERATION_INVALID: + strcpy(szSqlState, "S1011"); + break; + case STMT_INVALID_OPTION_IDENTIFIER: + strcpy(szSqlState, "HY092"); + break; + case STMT_EXEC_ERROR: + default: + strcpy(szSqlState, "S1000"); + /* also a general error */ + break; } - else if (stmt->errormsg_malloced) + mylog(" szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, pcblen, szErrorMsg); + if (clear_str) + { + stmt->errorpos = stapos + wrtlen; + if (stmt->errorpos >= msglen) SC_clear_error(stmt); - if (cbErrorMsgMax == 0) - return SQL_SUCCESS_WITH_INFO; - else - return SQL_SUCCESS; } - else if (SQL_NULL_HDBC != hdbc) - { - ConnectionClass *conn = (ConnectionClass *) hdbc; - - mylog("calling CC_get_error\n"); - if (CC_get_error(conn, &status, &msg)) - { - mylog("CC_get_error: status = %d, msg = #%s#\n", status, msg); - if (NULL == msg) - { - if (NULL != szSqlState) - strcpy(szSqlState, "00000"); - if (NULL != pcbErrorMsg) - *pcbErrorMsg = 0; - if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) - szErrorMsg[0] = '\0'; - - return SQL_NO_DATA_FOUND; - } - - msglen = strlen(msg); - if (NULL != pcbErrorMsg) - { - *pcbErrorMsg = msglen; - if (cbErrorMsgMax == 0) - once_again = TRUE; - else if (msglen >= cbErrorMsgMax) - *pcbErrorMsg = cbErrorMsgMax - 1; - } - if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) - strncpy_null(szErrorMsg, msg, cbErrorMsgMax); - if (NULL != pfNativeError) - *pfNativeError = status; - - if (NULL != szSqlState) - switch (status) - { - case STMT_OPTION_VALUE_CHANGED: - case CONN_OPTION_VALUE_CHANGED: - strcpy(szSqlState, "01S02"); - break; - case STMT_TRUNCATED: - case CONN_TRUNCATED: - strcpy(szSqlState, "01004"); - /* data truncated */ - break; - case CONN_INIREAD_ERROR: - strcpy(szSqlState, "IM002"); - /* data source not found */ - break; - case CONN_OPENDB_ERROR: - strcpy(szSqlState, "08001"); - /* unable to connect to data source */ - break; - case CONN_INVALID_AUTHENTICATION: - case CONN_AUTH_TYPE_UNSUPPORTED: - strcpy(szSqlState, "28000"); - break; - case CONN_STMT_ALLOC_ERROR: - strcpy(szSqlState, "S1001"); - /* memory allocation failure */ - break; - case CONN_IN_USE: - strcpy(szSqlState, "S1000"); - /* general error */ - break; - case CONN_UNSUPPORTED_OPTION: - strcpy(szSqlState, "IM001"); - /* driver does not support this function */ - case CONN_INVALID_ARGUMENT_NO: - strcpy(szSqlState, "S1009"); - /* invalid argument value */ - break; - case CONN_TRANSACT_IN_PROGRES: - strcpy(szSqlState, "S1010"); - - /* - * when the user tries to switch commit mode in a - * transaction - */ - /* -> function sequence error */ - break; - case CONN_NO_MEMORY_ERROR: - strcpy(szSqlState, "S1001"); - break; - case CONN_NOT_IMPLEMENTED_ERROR: - case STMT_NOT_IMPLEMENTED_ERROR: - strcpy(szSqlState, "S1C00"); - break; - case STMT_RETURN_NULL_WITHOUT_INDICATOR: - strcpy(szSqlState, "22002"); - break; - case CONN_VALUE_OUT_OF_RANGE: - case STMT_VALUE_OUT_OF_RANGE: - strcpy(szSqlState, "22003"); - break; - default: - strcpy(szSqlState, "S1000"); - /* general error */ - break; - } - } - else - { - mylog("CC_Get_error returned nothing.\n"); - if (NULL != szSqlState) - strcpy(szSqlState, "00000"); - if (NULL != pcbErrorMsg) - *pcbErrorMsg = 0; - if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) - szErrorMsg[0] = '\0'; + if (wrtlen == 0) + return SQL_SUCCESS_WITH_INFO; + else + return SQL_SUCCESS; +} - return SQL_NO_DATA_FOUND; - } +RETCODE SQL_API +PGAPI_ConnectError( HDBC hdbc, + SWORD RecNumber, + UCHAR FAR * szSqlState, + SDWORD FAR * pfNativeError, + UCHAR FAR * szErrorMsg, + SWORD cbErrorMsgMax, + SWORD FAR * pcbErrorMsg, + UWORD flag) +{ + ConnectionClass *conn = (ConnectionClass *) hdbc; + char *msg; + int status; + BOOL once_again = FALSE; + SWORD msglen; - if (once_again) - { - conn->errornumber = status; - return SQL_SUCCESS_WITH_INFO; - } - else - return SQL_SUCCESS; + if (RecNumber != 1) + return SQL_NO_DATA_FOUND; + if (cbErrorMsgMax < 0) + return SQL_ERROR; + if (!CC_get_error(conn, &status, &msg) || NULL == msg) + { + mylog("CC_Get_error returned nothing.\n"); + if (NULL != szSqlState) + strcpy(szSqlState, "00000"); + if (NULL != pcbErrorMsg) + *pcbErrorMsg = 0; + if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) + szErrorMsg[0] = '\0'; + + return SQL_NO_DATA_FOUND; } - else if (SQL_NULL_HENV != henv) + mylog("CC_get_error: status = %d, msg = #%s#\n", status, msg); + + msglen = strlen(msg); + if (NULL != pcbErrorMsg) { - EnvironmentClass *env = (EnvironmentClass *) henv; + *pcbErrorMsg = msglen; + if (cbErrorMsgMax == 0) + once_again = TRUE; + else if (msglen >= cbErrorMsgMax) + *pcbErrorMsg = cbErrorMsgMax - 1; + } + if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) + strncpy_null(szErrorMsg, msg, cbErrorMsgMax); + if (NULL != pfNativeError) + *pfNativeError = status; - if (EN_get_error(env, &status, &msg)) - { - mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg); - if (NULL == msg) - { - if (NULL != szSqlState) - strcpy(szSqlState, "00000"); - if (NULL != pcbErrorMsg) - *pcbErrorMsg = 0; - if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) - szErrorMsg[0] = '\0'; - - return SQL_NO_DATA_FOUND; - } - - if (NULL != pcbErrorMsg) - *pcbErrorMsg = (SWORD) strlen(msg); - if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) - strncpy_null(szErrorMsg, msg, cbErrorMsgMax); - if (NULL != pfNativeError) - *pfNativeError = status; - - if (szSqlState) - { - switch (status) - { - case ENV_ALLOC_ERROR: - /* memory allocation failure */ - strcpy(szSqlState, "S1001"); - break; - default: - strcpy(szSqlState, "S1000"); - /* general error */ - break; - } - } - } - else + if (NULL != szSqlState) + switch (status) { - if (NULL != szSqlState) - strcpy(szSqlState, "00000"); - if (NULL != pcbErrorMsg) - *pcbErrorMsg = 0; - if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) - szErrorMsg[0] = '\0'; - - return SQL_NO_DATA_FOUND; + case STMT_OPTION_VALUE_CHANGED: + case CONN_OPTION_VALUE_CHANGED: + strcpy(szSqlState, "01S02"); + break; + case STMT_TRUNCATED: + case CONN_TRUNCATED: + strcpy(szSqlState, "01004"); + /* data truncated */ + break; + case CONN_INIREAD_ERROR: + strcpy(szSqlState, "IM002"); + /* data source not found */ + break; + case CONN_OPENDB_ERROR: + strcpy(szSqlState, "08001"); + /* unable to connect to data source */ + break; + case CONN_INVALID_AUTHENTICATION: + case CONN_AUTH_TYPE_UNSUPPORTED: + strcpy(szSqlState, "28000"); + break; + case CONN_STMT_ALLOC_ERROR: + strcpy(szSqlState, "S1001"); + /* memory allocation failure */ + break; + case CONN_IN_USE: + strcpy(szSqlState, "S1000"); + /* general error */ + break; + case CONN_UNSUPPORTED_OPTION: + strcpy(szSqlState, "IM001"); + /* driver does not support this function */ + case CONN_INVALID_ARGUMENT_NO: + strcpy(szSqlState, "S1009"); + /* invalid argument value */ + break; + case CONN_TRANSACT_IN_PROGRES: + strcpy(szSqlState, "S1010"); + + /* + * when the user tries to switch commit mode in a + * transaction + */ + /* -> function sequence error */ + break; + case CONN_NO_MEMORY_ERROR: + strcpy(szSqlState, "S1001"); + break; + case CONN_NOT_IMPLEMENTED_ERROR: + case STMT_NOT_IMPLEMENTED_ERROR: + strcpy(szSqlState, "S1C00"); + break; + case STMT_RETURN_NULL_WITHOUT_INDICATOR: + strcpy(szSqlState, "22002"); + break; + case CONN_VALUE_OUT_OF_RANGE: + case STMT_VALUE_OUT_OF_RANGE: + strcpy(szSqlState, "22003"); + break; + default: + strcpy(szSqlState, "S1000"); + /* general error */ + break; } + if (once_again) + { + conn->errornumber = status; + return SQL_SUCCESS_WITH_INFO; + } + else return SQL_SUCCESS; +} + +RETCODE SQL_API +PGAPI_EnvError( HENV henv, + SWORD RecNumber, + UCHAR FAR * szSqlState, + SDWORD FAR * pfNativeError, + UCHAR FAR * szErrorMsg, + SWORD cbErrorMsgMax, + SWORD FAR * pcbErrorMsg, + UWORD flag) +{ + EnvironmentClass *env = (EnvironmentClass *) henv; + char *msg; + int status; + + if (RecNumber != 1) + return SQL_NO_DATA_FOUND; + if (cbErrorMsgMax < 0) + return SQL_ERROR; + if (!EN_get_error(env, &status, &msg) || NULL == msg) + { + mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg); + + if (NULL != szSqlState) + strcpy(szSqlState, "00000"); + if (NULL != pcbErrorMsg) + *pcbErrorMsg = 0; + if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) + szErrorMsg[0] = '\0'; + + return SQL_NO_DATA_FOUND; } + mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg); - if (NULL != szSqlState) - strcpy(szSqlState, "00000"); if (NULL != pcbErrorMsg) - *pcbErrorMsg = 0; + *pcbErrorMsg = (SWORD) strlen(msg); if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) - szErrorMsg[0] = '\0'; + strncpy_null(szErrorMsg, msg, cbErrorMsgMax); + if (NULL != pfNativeError) + *pfNativeError = status; - return SQL_NO_DATA_FOUND; + if (szSqlState) + { + switch (status) + { + case ENV_ALLOC_ERROR: + /* memory allocation failure */ + strcpy(szSqlState, "S1001"); + break; + default: + strcpy(szSqlState, "S1000"); + /* general error */ + break; + } + } + + return SQL_SUCCESS; } +/* Returns the next SQL error information. */ +RETCODE SQL_API +PGAPI_Error( + HENV henv, + HDBC hdbc, + HSTMT hstmt, + UCHAR FAR * szSqlState, + SDWORD FAR * pfNativeError, + UCHAR FAR * szErrorMsg, + SWORD cbErrorMsgMax, + SWORD FAR * pcbErrorMsg) +{ + RETCODE ret; + UWORD flag = PODBC_ALLOW_PARTIAL_EXTRACT | PODBC_ERROR_CLEAR; + + mylog("**** PGAPI_Error: henv=%u, hdbc=%u hstmt=%d\n", henv, hdbc, hstmt); + + if (cbErrorMsgMax < 0) + return SQL_ERROR; + if (SQL_NULL_HSTMT != hstmt) + ret = PGAPI_StmtError(hstmt, -1, szSqlState, pfNativeError, + szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag); + else if (SQL_NULL_HDBC != hdbc) + ret = PGAPI_ConnectError(hdbc, -1, szSqlState, pfNativeError, + szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag); + else if (SQL_NULL_HENV != hdbc) + ret = PGAPI_EnvError(henv, -1, szSqlState, pfNativeError, + szErrorMsg, cbErrorMsgMax, pcbErrorMsg, flag); + else + { + if (NULL != szSqlState) + strcpy(szSqlState, "00000"); + if (NULL != pcbErrorMsg) + *pcbErrorMsg = 0; + if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0)) + szErrorMsg[0] = '\0'; + + ret = SQL_NO_DATA_FOUND; + } + mylog("**** PGAPI_Error exit code=%d\n", ret); + return ret; +} + /* * EnvironmentClass implementation */ @@ -493,6 +535,7 @@ EN_Constructor(void) { rv->errormsg = 0; rv->errornumber = 0; + rv->flag = 0; } return rv; diff --git a/src/interfaces/odbc/environ.h b/src/interfaces/odbc/environ.h index 7b463b3e744..24b456d4899 100644 --- a/src/interfaces/odbc/environ.h +++ b/src/interfaces/odbc/environ.h @@ -17,7 +17,8 @@ struct EnvironmentClass_ { char *errormsg; - int errornumber; + int errornumber; + Int4 flag; }; /* Environment prototypes */ @@ -28,4 +29,10 @@ char EN_add_connection(EnvironmentClass *self, ConnectionClass *conn); char EN_remove_connection(EnvironmentClass *self, ConnectionClass *conn); void EN_log_error(char *func, char *desc, EnvironmentClass *self); +#define EN_OV_ODBC2 1L +#define EN_is_odbc2(env) ((env->flag & EN_OV_ODBC2) != 0) +#define EN_is_odbc3(env) ((env->flag & EN_OV_ODBC2) == 0) +#define EN_set_odbc2(env) (env->flag |= EN_OV_ODBC2) +#define EN_set_odbc3(env) (env->flag &= EN_OV_ODBC2) + #endif diff --git a/src/interfaces/odbc/execute.c b/src/interfaces/odbc/execute.c index 4c6608923a4..ae095e9691e 100644 --- a/src/interfaces/odbc/execute.c +++ b/src/interfaces/odbc/execute.c @@ -267,6 +267,7 @@ PGAPI_Execute( if (stmt->status == STMT_FINISHED) { mylog("%s: recycling statement (should have been done by app)...\n", func); +/******** Is this really NEEDED ? ******/ SC_recycle_statement(stmt); } @@ -291,6 +292,7 @@ PGAPI_Execute( { if (stmt->options.param_processed_ptr) *stmt->options.param_processed_ptr = 0; + SC_recycle_statement(stmt); } next_param_row: @@ -434,26 +436,24 @@ next_param_row: } /* we are now in a transaction */ CC_set_in_trans(conn); - stmt->result = res = CC_send_query(conn, stmt->stmt_with_params, NULL); - if (!res || QR_aborted(res)) + res = CC_send_query(conn, stmt->stmt_with_params, NULL, TRUE); + if (!res) { CC_abort(conn); stmt->errornumber = STMT_EXEC_ERROR; stmt->errormsg = "Handle prepare error"; return SQL_ERROR; } - else + SC_set_Result(stmt, res); + if (CC_is_in_autocommit(conn)) { - if (CC_is_in_autocommit(conn)) - { - if (issued_begin) - CC_commit(conn); - else if (!in_trans && begin_included) - CC_set_no_trans(conn); - } - stmt->status = STMT_FINISHED; - return SQL_SUCCESS; + if (issued_begin) + CC_commit(conn); + else if (!in_trans && begin_included) + CC_set_no_trans(conn); } + stmt->status = STMT_FINISHED; + return SQL_SUCCESS; } else return SQL_SUCCESS; @@ -518,7 +518,7 @@ PGAPI_Transact( { mylog("PGAPI_Transact: sending on conn %d '%s'\n", conn, stmt_string); - res = CC_send_query(conn, stmt_string, NULL); + res = CC_send_query(conn, stmt_string, NULL, TRUE); CC_set_no_trans(conn); if (!res) @@ -721,7 +721,7 @@ PGAPI_ParamData( /* commit transaction if needed */ if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(stmt->hdbc)) { - if (!CC_commit(stmt->hdbc)) + if (CC_commit(stmt->hdbc)) { stmt->errormsg = "Could not commit (in-line) a transaction"; stmt->errornumber = STMT_EXEC_ERROR; @@ -902,6 +902,14 @@ PGAPI_PutData( } else { + Int2 ctype = current_param->CType; + if (ctype == SQL_C_DEFAULT) + ctype = sqltype_to_default_ctype(current_param->SQLType); + +#ifdef UNICODE_SUPPORT + if (SQL_NTS == cbValue && SQL_C_WCHAR == ctype) + cbValue = 2 * ucs2strlen((SQLWCHAR *) rgbValue); +#endif /* UNICODE_SUPPORT */ /* for handling fields */ if (cbValue == SQL_NTS) { @@ -916,11 +924,11 @@ PGAPI_PutData( } else { - Int2 ctype = current_param->CType; - - if (ctype == SQL_C_DEFAULT) - ctype = sqltype_to_default_ctype(current_param->SQLType); +#ifdef UNICODE_SUPPORT + if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY || ctype == SQL_C_WCHAR) +#else if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY) +#endif /* UNICODE_SUPPORT */ { current_param->EXEC_buffer = malloc(cbValue + 1); if (!current_param->EXEC_buffer) @@ -965,31 +973,31 @@ PGAPI_PutData( } else { - buffer = current_param->EXEC_buffer; + Int2 ctype = current_param->CType; - if (cbValue == SQL_NTS) + if (ctype == SQL_C_DEFAULT) + ctype = sqltype_to_default_ctype(current_param->SQLType); + buffer = current_param->EXEC_buffer; + if (old_pos = *current_param->EXEC_used, SQL_NTS == old_pos) { - buffer = realloc(buffer, strlen(buffer) + strlen(rgbValue) + 1); - if (!buffer) - { - stmt->errornumber = STMT_NO_MEMORY_ERROR; - stmt->errormsg = "Out of memory in PGAPI_PutData (3)"; - SC_log_error(func, "", stmt); - return SQL_ERROR; - } - strcat(buffer, rgbValue); - - mylog(" cbValue = SQL_NTS: strlen(buffer) = %d\n", strlen(buffer)); - - *current_param->EXEC_used = cbValue; - - /* reassign buffer incase realloc moved it */ - current_param->EXEC_buffer = buffer; +#ifdef UNICODE_SUPPORT + if (SQL_C_WCHAR == ctype) + old_pos = 2 * ucs2strlen((SQLWCHAR *) buffer); + else +#endif /* UNICODE_SUPPORT */ + old_pos = strlen(buffer); } - else if (cbValue > 0) + if (SQL_NTS == cbValue) + { +#ifdef UNICODE_SUPPORT + if (SQL_C_WCHAR == ctype) + cbValue = 2 * ucs2strlen((SQLWCHAR *) rgbValue); + else +#endif /* UNICODE_SUPPORT */ + cbValue = strlen(rgbValue); + } + if (cbValue > 0) { - old_pos = *current_param->EXEC_used; - *current_param->EXEC_used += cbValue; mylog(" cbValue = %d, old_pos = %d, *used = %d\n", cbValue, old_pos, *current_param->EXEC_used); diff --git a/src/interfaces/odbc/info.c b/src/interfaces/odbc/info.c index d4fda3670b6..fc5dcef3415 100644 --- a/src/interfaces/odbc/info.c +++ b/src/interfaces/odbc/info.c @@ -10,7 +10,7 @@ * SQLTables, SQLColumns, SQLStatistics, SQLSpecialColumns, * SQLPrimaryKeys, SQLForeignKeys, * SQLProcedureColumns(NI), SQLProcedures, - * SQLTablePrivileges(NI), SQLColumnPrivileges(NI) + * SQLTablePrivileges, SQLColumnPrivileges(NI) * * Comments: See "notice.txt" for copyright and license information. *-------- @@ -231,13 +231,14 @@ PGAPI_GetInfo( case SQL_FETCH_DIRECTION: /* ODBC 1.0 */ len = 4; - value = ci->drivers.use_declarefetch ? (SQL_FD_FETCH_NEXT) : (SQL_FD_FETCH_NEXT | - SQL_FD_FETCH_FIRST | - SQL_FD_FETCH_LAST | - SQL_FD_FETCH_PRIOR | - SQL_FD_FETCH_ABSOLUTE | - SQL_FD_FETCH_RELATIVE | - SQL_FD_FETCH_BOOKMARK); + value = ci->drivers.use_declarefetch ? (SQL_FD_FETCH_NEXT) : + (SQL_FD_FETCH_NEXT | + SQL_FD_FETCH_FIRST | + SQL_FD_FETCH_LAST | + SQL_FD_FETCH_PRIOR | + SQL_FD_FETCH_ABSOLUTE | + SQL_FD_FETCH_RELATIVE | + SQL_FD_FETCH_BOOKMARK); break; case SQL_FILE_USAGE: /* ODBC 2.0 */ @@ -665,7 +666,6 @@ PGAPI_GetInfo( /* unrecognized key */ conn->errormsg = "Unrecognized key passed to PGAPI_GetInfo."; conn->errornumber = CONN_NOT_IMPLEMENTED_ERROR; - CC_log_error(func, "", conn); return SQL_ERROR; } @@ -685,12 +685,20 @@ PGAPI_GetInfo( if (rgbInfoValue) { +#ifdef UNICODE_SUPPORT + if (conn->unicode) + { + len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue, cbInfoValueMax / 2); + len *= 2; + } + else +#endif /* UNICODE_SUPPORT */ strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax); if (len >= cbInfoValueMax) { result = SQL_SUCCESS_WITH_INFO; - conn->errornumber = STMT_TRUNCATED; + conn->errornumber = CONN_TRUNCATED; conn->errormsg = "The buffer was too small for tthe InfoValue."; } } @@ -721,6 +729,7 @@ PGAPI_GetTypeInfo( { static char *func = "PGAPI_GetTypeInfo"; StatementClass *stmt = (StatementClass *) hstmt; + QResultClass *res; TupleNode *row; int i; @@ -737,31 +746,31 @@ PGAPI_GetTypeInfo( } stmt->manual_result = TRUE; - stmt->result = QR_Constructor(); - if (!stmt->result) + if (res = QR_Constructor(), !res) { SC_log_error(func, "Error creating result.", stmt); return SQL_ERROR; } + SC_set_Result(stmt, res); extend_bindings(stmt, 15); - QR_set_num_fields(stmt->result, 15); - QR_set_field_info(stmt->result, 0, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 1, "DATA_TYPE", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 2, "PRECISION", PG_TYPE_INT4, 4); - QR_set_field_info(stmt->result, 3, "LITERAL_PREFIX", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 4, "LITERAL_SUFFIX", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 5, "CREATE_PARAMS", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 6, "NULLABLE", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 7, "CASE_SENSITIVE", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 8, "SEARCHABLE", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 10, "MONEY", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 11, "AUTO_INCREMENT", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 12, "LOCAL_TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2); + QR_set_num_fields(res, 15); + QR_set_field_info(res, 0, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 1, "DATA_TYPE", PG_TYPE_INT2, 2); + QR_set_field_info(res, 2, "PRECISION", PG_TYPE_INT4, 4); + QR_set_field_info(res, 3, "LITERAL_PREFIX", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 4, "LITERAL_SUFFIX", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 5, "CREATE_PARAMS", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 6, "NULLABLE", PG_TYPE_INT2, 2); + QR_set_field_info(res, 7, "CASE_SENSITIVE", PG_TYPE_INT2, 2); + QR_set_field_info(res, 8, "SEARCHABLE", PG_TYPE_INT2, 2); + QR_set_field_info(res, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2, 2); + QR_set_field_info(res, 10, "MONEY", PG_TYPE_INT2, 2); + QR_set_field_info(res, 11, "AUTO_INCREMENT", PG_TYPE_INT2, 2); + QR_set_field_info(res, 12, "LOCAL_TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2); + QR_set_field_info(res, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2); for (i = 0, sqlType = sqlTypes[0]; sqlType; sqlType = sqlTypes[++i]) { @@ -795,7 +804,7 @@ PGAPI_GetTypeInfo( set_nullfield_int2(&row->tuple[13], pgtype_scale(stmt, pgType, PG_STATIC)); set_nullfield_int2(&row->tuple[14], pgtype_scale(stmt, pgType, PG_STATIC)); - QR_add_tuple(stmt->result, row); + QR_add_tuple(res, row); } } @@ -898,7 +907,7 @@ PGAPI_GetFunctions( pfExists[SQL_API_SQLMORERESULTS] = TRUE; pfExists[SQL_API_SQLNATIVESQL] = TRUE; pfExists[SQL_API_SQLNUMPARAMS] = TRUE; - pfExists[SQL_API_SQLPARAMOPTIONS] = FALSE; + pfExists[SQL_API_SQLPARAMOPTIONS] = TRUE; pfExists[SQL_API_SQLPRIMARYKEYS] = TRUE; pfExists[SQL_API_SQLPROCEDURECOLUMNS] = FALSE; if (PG_VERSION_LT(conn, 6.5)) @@ -907,7 +916,7 @@ PGAPI_GetFunctions( pfExists[SQL_API_SQLPROCEDURES] = TRUE; pfExists[SQL_API_SQLSETPOS] = TRUE; pfExists[SQL_API_SQLSETSCROLLOPTIONS] = TRUE; /* odbc 1.0 */ - pfExists[SQL_API_SQLTABLEPRIVILEGES] = FALSE; + pfExists[SQL_API_SQLTABLEPRIVILEGES] = TRUE; } } else @@ -1070,7 +1079,7 @@ PGAPI_GetFunctions( *pfExists = TRUE; break; case SQL_API_SQLPARAMOPTIONS: - *pfExists = FALSE; + *pfExists = TRUE; break; case SQL_API_SQLPRIMARYKEYS: *pfExists = TRUE; @@ -1091,7 +1100,7 @@ PGAPI_GetFunctions( *pfExists = TRUE; break; /* odbc 1.0 */ case SQL_API_SQLTABLEPRIVILEGES: - *pfExists = FALSE; + *pfExists = TRUE; break; } } @@ -1115,6 +1124,7 @@ PGAPI_Tables( static char *func = "PGAPI_Tables"; StatementClass *stmt = (StatementClass *) hstmt; StatementClass *tbl_stmt; + QResultClass *res; TupleNode *row; HSTMT htbl_stmt; RETCODE result; @@ -1291,8 +1301,7 @@ PGAPI_Tables( return SQL_ERROR; } - stmt->result = QR_Constructor(); - if (!stmt->result) + if (res = QR_Constructor(), !res) { stmt->errormsg = "Couldn't allocate memory for PGAPI_Tables result."; stmt->errornumber = STMT_NO_MEMORY_ERROR; @@ -1300,6 +1309,7 @@ PGAPI_Tables( PGAPI_FreeStmt(htbl_stmt, SQL_DROP); return SQL_ERROR; } + SC_set_Result(stmt, res); /* the binding structure for a statement is not set up until */ @@ -1310,12 +1320,12 @@ PGAPI_Tables( extend_bindings(stmt, 5); /* set the field names */ - QR_set_num_fields(stmt->result, 5); - QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 3, "TABLE_TYPE", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 4, "REMARKS", PG_TYPE_TEXT, 254); + QR_set_num_fields(res, 5); + QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 3, "TABLE_TYPE", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 4, "REMARKS", PG_TYPE_TEXT, 254); /* add the tuples */ result = PGAPI_Fetch(htbl_stmt); @@ -1372,6 +1382,7 @@ PGAPI_Tables( row = (TupleNode *) malloc(sizeof(TupleNode) + (5 - 1) *sizeof(TupleField)); /*set_tuplefield_string(&row->tuple[0], "");*/ + /*set_tuplefield_string(&row->tuple[0], "cat0");*/ set_tuplefield_null(&row->tuple[0]); /* @@ -1389,9 +1400,10 @@ PGAPI_Tables( set_tuplefield_null(&row->tuple[1]); set_tuplefield_string(&row->tuple[2], table_name); set_tuplefield_string(&row->tuple[3], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE")); - set_tuplefield_string(&row->tuple[4], ""); + /*set_tuplefield_string(&row->tuple[4], "");*/ + set_tuplefield_string(&row->tuple[4], "TABLE"); - QR_add_tuple(stmt->result, row); + QR_add_tuple(res, row); } result = PGAPI_Fetch(htbl_stmt); } @@ -1425,11 +1437,14 @@ PGAPI_Tables( * PostgreSQL needs 2 '\\' to escape '_' and '%'. */ static int -reallyEscapeCatalogEscapes(const char *src, int srclen, char *dest, int dst_len) +reallyEscapeCatalogEscapes(const char *src, int srclen, char *dest, int dst_len, int ccsc) { int i, outlen; const char *in; BOOL escape_in = FALSE; +#ifdef MULTIBYTE + encoded_str encstr; +#endif if (srclen == SQL_NULL_DATA) { @@ -1441,12 +1456,13 @@ reallyEscapeCatalogEscapes(const char *src, int srclen, char *dest, int dst_len) if (srclen <= 0) return STRCPY_FAIL; #ifdef MULTIBYTE - multibyte_init(); + encoded_str_constr(&encstr, ccsc, src); #endif for (i = 0, in = src, outlen = 0; i < srclen && outlen < dst_len; i++, in++) { #ifdef MULTIBYTE - if (multibyte_char_check(*in) != 0) + encoded_nextchar(&encstr); + if (ENCODE_STATUS(encstr) != 0) { dest[outlen++] = *in; continue; @@ -1496,6 +1512,7 @@ PGAPI_Columns( { static char *func = "PGAPI_Columns"; StatementClass *stmt = (StatementClass *) hstmt; + QResultClass *res; TupleNode *row; HSTMT hcol_stmt; StatementClass *col_stmt; @@ -1505,7 +1522,7 @@ PGAPI_Columns( table_name[MAX_INFO_STRING], field_name[MAX_INFO_STRING], field_type_name[MAX_INFO_STRING]; - Int2 field_number, + Int2 field_number, sqltype, result_cols, scale; Int4 field_type, @@ -1556,7 +1573,7 @@ PGAPI_Columns( char esc_table_name[MAX_TABLE_LEN * 2]; int escTbnamelen; - escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name)); + escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name), conn->ccsc); my_strcat(columns_query, " and c.relname like '%.*s'", esc_table_name, escTbnamelen); my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner); my_strcat(columns_query, " and a.attname like '%.*s'", szColumnName, cbColumnName); @@ -1701,8 +1718,7 @@ PGAPI_Columns( return SQL_ERROR; } - stmt->result = QR_Constructor(); - if (!stmt->result) + if (res = QR_Constructor(), !res) { stmt->errormsg = "Couldn't allocate memory for PGAPI_Columns result."; stmt->errornumber = STMT_NO_MEMORY_ERROR; @@ -1710,6 +1726,7 @@ PGAPI_Columns( PGAPI_FreeStmt(hcol_stmt, SQL_DROP); return SQL_ERROR; } + SC_set_Result(stmt, res); /* the binding structure for a statement is not set up until */ @@ -1721,23 +1738,32 @@ PGAPI_Columns( extend_bindings(stmt, result_cols); /* set the field names */ - QR_set_num_fields(stmt->result, result_cols); - QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 4, "DATA_TYPE", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 6, "PRECISION", PG_TYPE_INT4, 4); - QR_set_field_info(stmt->result, 7, "LENGTH", PG_TYPE_INT4, 4); - QR_set_field_info(stmt->result, 8, "SCALE", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 9, "RADIX", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 10, "NULLABLE", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 11, "REMARKS", PG_TYPE_TEXT, 254); + QR_set_num_fields(res, result_cols); + QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 4, "DATA_TYPE", PG_TYPE_INT2, 2); + QR_set_field_info(res, 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 6, "PRECISION", PG_TYPE_INT4, 4); + QR_set_field_info(res, 7, "LENGTH", PG_TYPE_INT4, 4); + QR_set_field_info(res, 8, "SCALE", PG_TYPE_INT2, 2); + QR_set_field_info(res, 9, "RADIX", PG_TYPE_INT2, 2); + QR_set_field_info(res, 10, "NULLABLE", PG_TYPE_INT2, 2); + QR_set_field_info(res, 11, "REMARKS", PG_TYPE_TEXT, 254); /* User defined fields */ - QR_set_field_info(stmt->result, 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4); - QR_set_field_info(stmt->result, 13, "FIELD_TYPE", PG_TYPE_INT4, 4); +#if (ODBCVER >= 0x0300) + QR_set_field_info(res, 12, "COLUMN_DEF", PG_TYPE_INT4, 254); + QR_set_field_info(res, 13, "SQL_DATA_TYPE", PG_TYPE_INT2, 2); + QR_set_field_info(res, 14, "SQL_DATETIME_SUB", PG_TYPE_INT2, 2); + QR_set_field_info(res, 15, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4); + QR_set_field_info(res, 16, "ORDINAL_POSITION", PG_TYPE_INT4, 4); + QR_set_field_info(res, 17, "IS_NULLABLE", PG_TYPE_TEXT, 254); +#else + QR_set_field_info(res, 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4); + QR_set_field_info(res, 13, "FIELD_TYPE", PG_TYPE_INT4, 4); +#endif /* ODBCVER */ result = PGAPI_Fetch(hcol_stmt); @@ -1764,7 +1790,8 @@ PGAPI_Columns( set_tuplefield_string(&row->tuple[1], ""); set_tuplefield_string(&row->tuple[2], table_name); set_tuplefield_string(&row->tuple[3], "oid"); - set_tuplefield_int2(&row->tuple[4], pgtype_to_sqltype(stmt, the_type)); + sqltype = pgtype_to_sqltype(stmt, the_type); + set_tuplefield_int2(&row->tuple[4], sqltype); set_tuplefield_string(&row->tuple[5], "OID"); set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, the_type, PG_STATIC, PG_STATIC)); @@ -1775,10 +1802,14 @@ PGAPI_Columns( set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS); set_tuplefield_string(&row->tuple[11], ""); +#if (ODBCVER >= 0x0300) + set_tuplefield_int2(&row->tuple[13], sqltype); +#else set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC)); set_tuplefield_int4(&row->tuple[13], the_type); +#endif /* ODBCVER */ - QR_add_tuple(stmt->result, row); + QR_add_tuple(res, row); } } @@ -1794,7 +1825,8 @@ PGAPI_Columns( set_tuplefield_string(&row->tuple[1], ""); set_tuplefield_string(&row->tuple[2], table_name); set_tuplefield_string(&row->tuple[3], field_name); - set_tuplefield_int2(&row->tuple[4], pgtype_to_sqltype(stmt, field_type)); + sqltype = pgtype_to_sqltype(stmt, field_type); + set_tuplefield_int2(&row->tuple[4], sqltype); set_tuplefield_string(&row->tuple[5], field_type_name); @@ -1812,7 +1844,7 @@ PGAPI_Columns( *---------- */ qlog("PGAPI_Columns: table='%s',field_name='%s',type=%d,sqltype=%d,name='%s'\n", - table_name, field_name, field_type, pgtype_to_sqltype(stmt,field_type), field_type_name); + table_name, field_name, field_type, pgtype_to_sqltype, field_type_name); useStaticPrecision = TRUE; @@ -1869,9 +1901,31 @@ PGAPI_Columns( set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, field_type)); set_tuplefield_int2(&row->tuple[10], (Int2) (not_null[0] == '1' ? SQL_NO_NULLS : pgtype_nullable(stmt, field_type))); set_tuplefield_string(&row->tuple[11], ""); +#if (ODBCVER >= 0x0300) + switch (sqltype) + { + case SQL_TYPE_DATE: + set_tuplefield_int2(&row->tuple[13], SQL_DATETIME); + set_tuplefield_int2(&row->tuple[14], SQL_CODE_DATE); + break; + case SQL_TYPE_TIME: + set_tuplefield_int2(&row->tuple[13], SQL_DATETIME); + set_tuplefield_int2(&row->tuple[14], SQL_CODE_TIME); + break; + case SQL_TYPE_TIMESTAMP: + set_tuplefield_int2(&row->tuple[13], SQL_DATETIME); + set_tuplefield_int2(&row->tuple[14], SQL_CODE_TIMESTAMP); + break; + default: + set_tuplefield_int2(&row->tuple[13], sqltype); + break; + } + set_tuplefield_int4(&row->tuple[16], field_number); +#else set_tuplefield_int4(&row->tuple[13], field_type); +#endif /* ODBCVER */ - QR_add_tuple(stmt->result, row); + QR_add_tuple(res, row); result = PGAPI_Fetch(hcol_stmt); @@ -1913,7 +1967,7 @@ PGAPI_Columns( set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC)); set_tuplefield_int4(&row->tuple[13], the_type); - QR_add_tuple(stmt->result, row); + QR_add_tuple(res, row); } /* @@ -1949,6 +2003,7 @@ PGAPI_SpecialColumns( static char *func = "PGAPI_SpecialColumns"; TupleNode *row; StatementClass *stmt = (StatementClass *) hstmt; + QResultClass *res; ConnInfo *ci; HSTMT hcol_stmt; StatementClass *col_stmt; @@ -2017,18 +2072,19 @@ PGAPI_SpecialColumns( result = PGAPI_Fetch(hcol_stmt); PGAPI_FreeStmt(hcol_stmt, SQL_DROP); - stmt->result = QR_Constructor(); + res = QR_Constructor(); + SC_set_Result(stmt, res); extend_bindings(stmt, 8); - QR_set_num_fields(stmt->result, 8); - QR_set_field_info(stmt->result, 0, "SCOPE", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 1, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 2, "DATA_TYPE", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 3, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 4, "PRECISION", PG_TYPE_INT4, 4); - QR_set_field_info(stmt->result, 5, "LENGTH", PG_TYPE_INT4, 4); - QR_set_field_info(stmt->result, 6, "SCALE", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 7, "PSEUDO_COLUMN", PG_TYPE_INT2, 2); + QR_set_num_fields(res, 8); + QR_set_field_info(res, 0, "SCOPE", PG_TYPE_INT2, 2); + QR_set_field_info(res, 1, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 2, "DATA_TYPE", PG_TYPE_INT2, 2); + QR_set_field_info(res, 3, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 4, "PRECISION", PG_TYPE_INT4, 4); + QR_set_field_info(res, 5, "LENGTH", PG_TYPE_INT4, 4); + QR_set_field_info(res, 6, "SCALE", PG_TYPE_INT2, 2); + QR_set_field_info(res, 7, "PSEUDO_COLUMN", PG_TYPE_INT2, 2); if (relhasrules[0] != '1') { @@ -2046,7 +2102,7 @@ PGAPI_SpecialColumns( set_tuplefield_int2(&row->tuple[6], pgtype_scale(stmt, PG_TYPE_OID, PG_STATIC)); set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO); - QR_add_tuple(stmt->result, row); + QR_add_tuple(res, row); } else if (fColType == SQL_ROWVER) @@ -2066,7 +2122,7 @@ PGAPI_SpecialColumns( set_tuplefield_int2(&row->tuple[6], pgtype_scale(stmt, the_type, PG_STATIC)); set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO); - QR_add_tuple(stmt->result, row); + QR_add_tuple(res, row); } } } @@ -2095,6 +2151,7 @@ PGAPI_Statistics( { static char *func = "PGAPI_Statistics"; StatementClass *stmt = (StatementClass *) hstmt; + QResultClass *res; char index_query[INFO_INQUIRY_LEN]; HSTMT hindx_stmt; RETCODE result; @@ -2133,14 +2190,14 @@ PGAPI_Statistics( ci = &(SC_get_conn(stmt)->connInfo); - stmt->result = QR_Constructor(); - if (!stmt->result) + if (res = QR_Constructor(), !res) { stmt->errormsg = "Couldn't allocate memory for PGAPI_Statistics result."; stmt->errornumber = STMT_NO_MEMORY_ERROR; SC_log_error(func, "", stmt); return SQL_ERROR; } + SC_set_Result(stmt, res); /* the binding structure for a statement is not set up until */ @@ -2151,20 +2208,20 @@ PGAPI_Statistics( extend_bindings(stmt, 13); /* set the field names */ - QR_set_num_fields(stmt->result, 13); - QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 3, "NON_UNIQUE", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 4, "INDEX_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 5, "INDEX_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 6, "TYPE", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 7, "SEQ_IN_INDEX", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 8, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 9, "COLLATION", PG_TYPE_CHAR, 1); - QR_set_field_info(stmt->result, 10, "CARDINALITY", PG_TYPE_INT4, 4); - QR_set_field_info(stmt->result, 11, "PAGES", PG_TYPE_INT4, 4); - QR_set_field_info(stmt->result, 12, "FILTER_CONDITION", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_num_fields(res, 13); + QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 3, "NON_UNIQUE", PG_TYPE_INT2, 2); + QR_set_field_info(res, 4, "INDEX_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 5, "INDEX_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 6, "TYPE", PG_TYPE_INT2, 2); + QR_set_field_info(res, 7, "SEQ_IN_INDEX", PG_TYPE_INT2, 2); + QR_set_field_info(res, 8, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 9, "COLLATION", PG_TYPE_CHAR, 1); + QR_set_field_info(res, 10, "CARDINALITY", PG_TYPE_INT4, 4); + QR_set_field_info(res, 11, "PAGES", PG_TYPE_INT4, 4); + QR_set_field_info(res, 12, "FILTER_CONDITION", PG_TYPE_TEXT, MAX_INFO_STRING); /* * only use the table name... the owner should be redundant, and we @@ -2395,7 +2452,7 @@ PGAPI_Statistics( set_tuplefield_null(&row->tuple[11]); set_tuplefield_null(&row->tuple[12]); - QR_add_tuple(stmt->result, row); + QR_add_tuple(res, row); } result = PGAPI_Fetch(hindx_stmt); @@ -2457,7 +2514,7 @@ PGAPI_Statistics( set_tuplefield_null(&row->tuple[11]); set_tuplefield_null(&row->tuple[12]); - QR_add_tuple(stmt->result, row); + QR_add_tuple(res, row); i++; } } @@ -2520,12 +2577,15 @@ PGAPI_ColumnPrivileges( SWORD cbColumnName) { static char *func = "PGAPI_ColumnPrivileges"; + StatementClass *stmt = (StatementClass *) hstmt; mylog("%s: entering...\n", func); /* Neither Access or Borland care about this. */ - SC_log_error(func, "Function not implemented", (StatementClass *) hstmt); + stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; + stmt->errormsg = "not implemented"; + SC_log_error(func, "Function not implemented", stmt); return SQL_ERROR; } @@ -2547,6 +2607,7 @@ PGAPI_PrimaryKeys( { static char *func = "PGAPI_PrimaryKeys"; StatementClass *stmt = (StatementClass *) hstmt; + QResultClass *res; ConnectionClass *conn; TupleNode *row; RETCODE result; @@ -2572,14 +2633,14 @@ PGAPI_PrimaryKeys( stmt->manual_result = TRUE; stmt->errormsg_created = TRUE; - stmt->result = QR_Constructor(); - if (!stmt->result) + if (res = QR_Constructor(), !res) { stmt->errormsg = "Couldn't allocate memory for PGAPI_PrimaryKeys result."; stmt->errornumber = STMT_NO_MEMORY_ERROR; SC_log_error(func, "", stmt); return SQL_ERROR; } + SC_set_Result(stmt, res); /* the binding structure for a statement is not set up until */ @@ -2591,13 +2652,13 @@ PGAPI_PrimaryKeys( extend_bindings(stmt, result_cols); /* set the field names */ - QR_set_num_fields(stmt->result, result_cols); - QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 4, "KEY_SEQ", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 5, "PK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_num_fields(res, result_cols); + QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 4, "KEY_SEQ", PG_TYPE_INT2, 2); + QR_set_field_info(res, 5, "PK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); result = PGAPI_AllocStmt(stmt->hdbc, &htbl_stmt); @@ -2709,7 +2770,7 @@ PGAPI_PrimaryKeys( set_tuplefield_int2(&row->tuple[4], (Int2) (++seq)); set_tuplefield_null(&row->tuple[5]); - QR_add_tuple(stmt->result, row); + QR_add_tuple(res, row); mylog(">> primaryKeys: pktab = '%s', attname = '%s', seq = %d\n", pktab, attname, seq); @@ -2775,7 +2836,7 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc return ret; if (!conn->server_encoding) { - if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL), res) + if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, TRUE), res) { if (QR_get_num_tuples(res) > 0) conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0)); @@ -2785,25 +2846,16 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc if (!conn->server_encoding) return ret; sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding); - if (res = CC_send_query(conn, query, NULL), res) - { - bError = QR_get_aborted(res); - QR_Destructor(res); - } - else - bError = TRUE; + bError = (CC_send_query(conn, query, NULL, TRUE) == NULL); if (!bError && continueExec) { sprintf(query, "select OID from pg_class where relname = '%s'", serverTableName); - if (res = CC_send_query(conn, query, NULL), res) + if (res = CC_send_query(conn, query, NULL, TRUE), res) { if (QR_get_num_tuples(res) > 0) strcpy(saveoid, QR_get_value_backend_row(res, 0, 0)); else - { continueExec = FALSE; - bError = QR_get_aborted(res); - } QR_Destructor(res); } else @@ -2817,17 +2869,11 @@ getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloc } /* restore the client encoding */ sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding); - if (res = CC_send_query(conn, query, NULL), res) - { - bError = QR_get_aborted(res); - QR_Destructor(res); - } - else - bError = TRUE; + bError = (CC_send_query(conn, query, NULL, TRUE) == NULL); if (bError || !continueExec) return ret; sprintf(query, "select relname from pg_class where OID = %s", saveoid); - if (res = CC_send_query(conn, query, NULL), res) + if (res = CC_send_query(conn, query, NULL, TRUE), res) { if (QR_get_num_tuples(res) > 0) { @@ -2854,7 +2900,7 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se return ret; if (!conn->server_encoding) { - if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL), res) + if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, TRUE), res) { if (QR_get_num_tuples(res) > 0) conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0)); @@ -2864,19 +2910,13 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se if (!conn->server_encoding) return ret; sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding); - if (res = CC_send_query(conn, query, NULL), res) - { - bError = QR_get_aborted(res); - QR_Destructor(res); - } - else - bError = TRUE; + bError = (CC_send_query(conn, query, NULL, TRUE) == NULL); if (!bError && continueExec) { sprintf(query, "select attrelid, attnum from pg_class, pg_attribute " "where relname = '%s' and attrelid = pg_class.oid " "and attname = '%s'", serverTableName, serverColumnName); - if (res = CC_send_query(conn, query, NULL), res) + if (res = CC_send_query(conn, query, NULL, TRUE), res) { if (QR_get_num_tuples(res) > 0) { @@ -2884,10 +2924,7 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se strcpy(saveattnum, QR_get_value_backend_row(res, 0, 1)); } else - { continueExec = FALSE; - bError = QR_get_aborted(res); - } QR_Destructor(res); } else @@ -2901,17 +2938,11 @@ getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *se } /* restore the cleint encoding */ sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding); - if (res = CC_send_query(conn, query, NULL), res) - { - bError = QR_get_aborted(res); - QR_Destructor(res); - } - else - bError = TRUE; + bError = (CC_send_query(conn, query, NULL, TRUE) == NULL); if (bError || !continueExec) return ret; sprintf(query, "select attname from pg_attribute where attrelid = %s and attnum = %s", saveattrelid, saveattnum); - if (res = CC_send_query(conn, query, NULL), res) + if (res = CC_send_query(conn, query, NULL, TRUE), res) { if (QR_get_num_tuples(res) > 0) { @@ -2942,6 +2973,7 @@ PGAPI_ForeignKeys( { static char *func = "PGAPI_ForeignKeys"; StatementClass *stmt = (StatementClass *) hstmt; + QResultClass *res; TupleNode *row; HSTMT htbl_stmt, hpkey_stmt; @@ -2997,14 +3029,14 @@ PGAPI_ForeignKeys( stmt->manual_result = TRUE; stmt->errormsg_created = TRUE; - stmt->result = QR_Constructor(); - if (!stmt->result) + if (res = QR_Constructor(), !res) { stmt->errormsg = "Couldn't allocate memory for PGAPI_ForeignKeys result."; stmt->errornumber = STMT_NO_MEMORY_ERROR; SC_log_error(func, "", stmt); return SQL_ERROR; } + SC_set_Result(stmt, res); /* the binding structure for a statement is not set up until */ @@ -3016,23 +3048,23 @@ PGAPI_ForeignKeys( extend_bindings(stmt, result_cols); /* set the field names */ - QR_set_num_fields(stmt->result, result_cols); - QR_set_field_info(stmt->result, 0, "PKTABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 1, "PKTABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 2, "PKTABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 3, "PKCOLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 4, "FKTABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 5, "FKTABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 6, "FKTABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 7, "FKCOLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 8, "KEY_SEQ", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 9, "UPDATE_RULE", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 10, "DELETE_RULE", PG_TYPE_INT2, 2); - QR_set_field_info(stmt->result, 11, "FK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 12, "PK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 13, "TRIGGER_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_num_fields(res, result_cols); + QR_set_field_info(res, 0, "PKTABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 1, "PKTABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 2, "PKTABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 3, "PKCOLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 4, "FKTABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 5, "FKTABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 6, "FKTABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 7, "FKCOLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 8, "KEY_SEQ", PG_TYPE_INT2, 2); + QR_set_field_info(res, 9, "UPDATE_RULE", PG_TYPE_INT2, 2); + QR_set_field_info(res, 10, "DELETE_RULE", PG_TYPE_INT2, 2); + QR_set_field_info(res, 11, "FK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 12, "PK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 13, "TRIGGER_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); #if (ODBCVER >= 0x0300) - QR_set_field_info(stmt->result, 14, "DEFERRABILITY", PG_TYPE_INT2, 2); + QR_set_field_info(res, 14, "DEFERRABILITY", PG_TYPE_INT2, 2); #endif /* ODBCVER >= 0x0300 */ /* @@ -3369,7 +3401,7 @@ PGAPI_ForeignKeys( set_tuplefield_int2(&row->tuple[14], defer_type); #endif /* ODBCVER >= 0x0300 */ - QR_add_tuple(stmt->result, row); + QR_add_tuple(res, row); #ifdef MULTIBYTE if (fkey_alloced) free(fkey_text); @@ -3623,7 +3655,7 @@ PGAPI_ForeignKeys( set_tuplefield_int2(&row->tuple[14], defer_type); #endif /* ODBCVER >= 0x0300 */ - QR_add_tuple(stmt->result, row); + QR_add_tuple(res, row); #ifdef MULTIBYTE if (pkey_alloced) free(pkey_text); @@ -3687,10 +3719,13 @@ PGAPI_ProcedureColumns( SWORD cbColumnName) { static char *func = "PGAPI_ProcedureColumns"; + StatementClass *stmt = (StatementClass *) hstmt; mylog("%s: entering...\n", func); - SC_log_error(func, "Function not implemented", (StatementClass *) hstmt); + stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; + stmt->errormsg = "not implemented"; + SC_log_error(func, "Function not implemented", stmt); return SQL_ERROR; } @@ -3717,7 +3752,7 @@ PGAPI_Procedures( { stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; stmt->errormsg = "Version is too old"; - SC_log_error(func, "Function not implemented", (StatementClass *) hstmt); + SC_log_error(func, "Function not implemented", stmt); return SQL_ERROR; } if (!SC_recycle_statement(stmt)) @@ -3733,16 +3768,13 @@ PGAPI_Procedures( " case when prorettype = 0 then 1::int2 else 2::int2 end as " "PROCEDURE_TYPE" " from pg_proc"); my_strcat(proc_query, " where proname like '%.*s'", szProcName, cbProcName); - res = CC_send_query(conn, proc_query, NULL); - if (!res || QR_aborted(res)) + if (res = CC_send_query(conn, proc_query, NULL, TRUE), !res) { - if (res) - QR_Destructor(res); stmt->errornumber = STMT_EXEC_ERROR; stmt->errormsg = "PGAPI_Procedures query error"; return SQL_ERROR; } - stmt->result = res; + SC_set_Result(stmt, res); /* * also, things need to think that this statement is finished so the @@ -3759,6 +3791,52 @@ PGAPI_Procedures( } +#define ACLMAX 8 +#define ALL_PRIVILIGES "arwdRxt" +static int +usracl_auth(char *usracl, const char *auth) +{ + int i, j, addcnt = 0; + + for (i = 0; auth[i]; i++) + { + for (j = 0; j < ACLMAX; j++) + { + if (usracl[j] == auth[i]) + break; + else if (!usracl[j]) + { + usracl[j]= auth[i]; + addcnt++; + break; + } + } + } + return addcnt; +} +static void +useracl_upd(char (*useracl)[ACLMAX], QResultClass *allures, const char *user, const char *auth) +{ + int usercount = QR_get_num_tuples(allures), i, addcnt = 0; + +mylog("user=%s auth=%s\n", user, auth); + if (user[0]) + for (i = 0; i < usercount; i++) + { + if (strcmp(QR_get_value_backend_row(allures, i, 0), user) == 0) + { + addcnt += usracl_auth(useracl[i], auth); + break; + } + } + else + for (i = 0; i < usercount; i++) + { + addcnt += usracl_auth(useracl[i], auth); + } + mylog("addcnt=%d\n", addcnt); +} + RETCODE SQL_API PGAPI_TablePrivileges( HSTMT hstmt, @@ -3767,13 +3845,24 @@ PGAPI_TablePrivileges( UCHAR FAR * szTableOwner, SWORD cbTableOwner, UCHAR FAR * szTableName, - SWORD cbTableName) + SWORD cbTableName, + UWORD flag) { StatementClass *stmt = (StatementClass *) hstmt; static char *func = "PGAPI_TablePrivileges"; + ConnectionClass *conn = SC_get_conn(stmt); Int2 result_cols; + char proc_query[INFO_INQUIRY_LEN]; + QResultClass *res, *allures = NULL; + TupleNode *row; + int tablecount, usercount, i, j, k; + BOOL grpauth, sys, su; + char (*useracl)[ACLMAX], *acl, *user, *delim, *auth; + char *reln, *owner, *priv; mylog("%s: entering...\n", func); + if (!SC_recycle_statement(stmt)) + return SQL_ERROR; /* * a statement is actually executed, so we'll have to do this @@ -3784,16 +3873,187 @@ PGAPI_TablePrivileges( /* set the field names */ stmt->manual_result = TRUE; - stmt->result = QR_Constructor(); - QR_set_num_fields(stmt->result, result_cols); - QR_set_field_info(stmt->result, 0, "TABLE_CAT", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 1, "TABLE_SCHEM", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 3, "GRANTOR", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 4, "GRANTEE", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 5, "PRIVILEGE", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 6, "IS_GRANTABLE", PG_TYPE_TEXT, MAX_INFO_STRING); - - SC_log_error(func, "Function not implemented", (StatementClass *) hstmt); - return SQL_ERROR; + res = QR_Constructor(); + SC_set_Result(stmt, res); + QR_set_num_fields(res, result_cols); + QR_set_field_info(res, 0, "TABLE_CAT", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 1, "TABLE_SCHEM", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 3, "GRANTOR", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 4, "GRANTEE", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 5, "PRIVILEGE", PG_TYPE_TEXT, MAX_INFO_STRING); + QR_set_field_info(res, 6, "IS_GRANTABLE", PG_TYPE_TEXT, MAX_INFO_STRING); + + /* + * 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; + stmt->current_col = -1; + strncpy_null(proc_query, "select relname, usename, relacl from pg_class , pg_user where", sizeof(proc_query)); + if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0) + my_strcat(proc_query, " relname = '%.*s' and", szTableName, cbTableName); + else + { + char esc_table_name[MAX_TABLE_LEN * 2]; + int escTbnamelen; + + escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name), conn->ccsc); + my_strcat(proc_query, " relname like '%.*s' and", esc_table_name, escTbnamelen); + } + strcat(proc_query, " pg_user.usesysid = relowner"); + if (res = CC_send_query(conn, proc_query, NULL, TRUE), !res) + { + stmt->errornumber = STMT_EXEC_ERROR; + stmt->errormsg = "PGAPI_TablePrivileges query error"; + return SQL_ERROR; + } + strncpy_null(proc_query, "select usename, usesysid, usesuper from pg_user", sizeof(proc_query)); + tablecount = QR_get_num_tuples(res); + if (allures = CC_send_query(conn, proc_query, NULL, TRUE), !allures) + { + QR_Destructor(res); + stmt->errornumber = STMT_EXEC_ERROR; + stmt->errormsg = "PGAPI_TablePrivileges query error"; + return SQL_ERROR; + } + usercount = QR_get_num_tuples(allures); + useracl = (char (*)[ACLMAX]) malloc(usercount * sizeof(char [ACLMAX])); + for (i = 0; i < tablecount; i++) + { + memset(useracl, 0, usercount * sizeof(char[ACLMAX])); + acl = (char *) QR_get_value_backend_row(res, i, 2); + if (acl && acl[0] == '{') + user = acl + 1; + else + user = NULL; + for (; user && *user;) + { + grpauth = FALSE; + if (user[0] == '"' && strncmp(user + 1, "group ", 6) == 0) + { + user += 7; + grpauth = TRUE; + } + if (delim = strchr(user, '='), !delim) + break; + *delim = '\0'; + auth = delim + 1; + if (grpauth) + { + if (delim = strchr(auth, '"'), delim) + { + *delim = '\0'; + delim++; + } + } + else if (delim = strchr(auth, ','), delim) + *delim = '\0'; + else if (delim = strchr(auth, '}'), delim) + *delim = '\0'; + if (grpauth) /* handle group privilege */ + { + QResultClass *gres; + int i; + char *grolist, *uid, *delm; + + snprintf(proc_query, sizeof(proc_query) - 1, "select grolist from pg_group where groname = '%s'", user); + if (gres = CC_send_query(conn, proc_query, NULL, TRUE)) + { + grolist = QR_get_value_backend_row(gres, 0, 0); + if (grolist && grolist[0] == '{') + { + for (uid = grolist + 1; *uid;) + { + if (delm = strchr(uid, ','), delm) + *delm = '\0'; + else if (delm = strchr(uid, '}'), delm) + *delm = '\0'; +mylog("guid=%s\n", uid); + for (i = 0; i < usercount; i++) + { + if (strcmp(QR_get_value_backend_row(allures, i, 1), uid) == 0) + useracl_upd(useracl, allures, QR_get_value_backend_row(allures, i, 0), auth); + } + uid = delm + 1; + } + } + QR_Destructor(gres); + } + } + else + useracl_upd(useracl, allures, user, auth); + if (!delim) + break; + user = delim + 1; + } + reln = QR_get_value_backend_row(res, i, 0); + owner = QR_get_value_backend_row(res, i, 1); + /* The owner has all privileges */ + useracl_upd(useracl, allures, owner, ALL_PRIVILIGES); + for (j = 0; j < usercount; j++) + { + user = QR_get_value_backend_row(allures, j, 0); + su = (strcmp(QR_get_value_backend_row(allures, j, 2), "t") == 0); + sys = (strcmp(user, owner) == 0); + /* Super user has all privileges */ + if (su) + useracl_upd(useracl, allures, user, ALL_PRIVILIGES); + for (k = 0; k < ACLMAX; k++) + { + if (!useracl[j][k]) + break; + switch (useracl[j][k]) + { + case 'R': /* rule */ + case 't': /* trigger */ + continue; + } + row = (TupleNode *) malloc(sizeof(TupleNode) + (7 - 1) *sizeof(TupleField)); + set_tuplefield_string(&row->tuple[0], ""); + set_tuplefield_string(&row->tuple[1], ""); + set_tuplefield_string(&row->tuple[2], reln); + if (su || sys) + set_tuplefield_string(&row->tuple[3], "_SYSTEM"); + else + set_tuplefield_string(&row->tuple[3], owner); + mylog("user=%s\n", user); + set_tuplefield_string(&row->tuple[4], user); + switch (useracl[j][k]) + { + case 'a': + priv = "INSERT"; + break; + case 'r': + priv = "SELECT"; + break; + case 'w': + priv = "UPDATE"; + break; + case 'd': + priv = "DELETE"; + break; + case 'x': + priv = "REFERENCES"; + break; + default: + priv = ""; + } + set_tuplefield_string(&row->tuple[5], priv); + /* The owner and the super user are grantable */ + if (sys || su) + set_tuplefield_string(&row->tuple[6], "YES"); + else + set_tuplefield_string(&row->tuple[6], "NO"); + QR_add_tuple(SC_get_Result(stmt), row); + } + } + } + free(useracl); + QR_Destructor(res); + QR_Destructor(allures); + return SQL_SUCCESS; } diff --git a/src/interfaces/odbc/info30.c b/src/interfaces/odbc/info30.c index 8aa2bfdf10b..b606f0dc622 100644 --- a/src/interfaces/odbc/info30.c +++ b/src/interfaces/odbc/info30.c @@ -19,6 +19,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, { static char *func = "PGAPI_GetInfo30"; ConnectionClass *conn = (ConnectionClass *) hdbc; + ConnInfo *ci = &(conn->connInfo); char *p = NULL; int len = 0, value = 0; @@ -50,35 +51,60 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, | SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK | SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION | SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE - | SQL_CA1_POS_REFRESH - /* | SQL_CA1_BULK_ADD + | SQL_CA1_POS_REFRESH; + if (ci->drivers.lie) + value |= + ( SQL_CA1_BULK_ADD | SQL_CA1_BULK_UPDATE_BY_BOOKMARK | SQL_CA1_BULK_DELETE_BY_BOOKMARK - | SQL_CA1_BULK_FETCH_BY_BOOKMARK */ - ; + | SQL_CA1_BULK_FETCH_BY_BOOKMARK + + | SQL_CA1_LOCK_EXCLUSIVE + | SQL_CA1_LOCK_UNLOCK + | SQL_CA1_POSITIONED_UPDATE + | SQL_CA1_POSITIONED_DELETE + | SQL_CA1_SELECT_FOR_UPDATE + ); break; case SQL_KEYSET_CURSOR_ATTRIBUTES2: len = 4; - value = SQL_CA2_OPT_ROWVER_CONCURRENCY | - SQL_CA2_SENSITIVITY_ADDITIONS | - SQL_CA2_SENSITIVITY_DELETIONS | - SQL_CA2_SENSITIVITY_UPDATES; + value = SQL_CA2_OPT_ROWVER_CONCURRENCY + | SQL_CA2_SENSITIVITY_ADDITIONS + | SQL_CA2_SENSITIVITY_DELETIONS + | SQL_CA2_SENSITIVITY_UPDATES; + if (ci->drivers.lie) + value |= + ( SQL_CA2_READ_ONLY_CONCURRENCY + | SQL_CA2_LOCK_CONCURRENCY + | SQL_CA2_OPT_VALUES_CONCURRENCY + | SQL_CA2_MAX_ROWS_SELECT + | SQL_CA2_MAX_ROWS_INSERT + | SQL_CA2_MAX_ROWS_DELETE + | SQL_CA2_MAX_ROWS_UPDATE + | SQL_CA2_MAX_ROWS_CATALOG + | SQL_CA2_MAX_ROWS_AFFECTS_ALL + | SQL_CA2_CRC_EXACT + | SQL_CA2_CRC_APPROXIMATE + | SQL_CA2_SIMULATE_NON_UNIQUE + | SQL_CA2_SIMULATE_TRY_UNIQUE + | SQL_CA2_SIMULATE_UNIQUE + ); break; case SQL_STATIC_CURSOR_ATTRIBUTES1: len = 4; - value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE | - SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK | - SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION | - SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE | - SQL_CA1_POS_REFRESH; + value = SQL_CA1_NEXT | SQL_CA1_ABSOLUTE + | SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK + | SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION + | SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE + | SQL_CA1_POS_REFRESH; break; case SQL_STATIC_CURSOR_ATTRIBUTES2: len = 4; - value = SQL_CA2_OPT_ROWVER_CONCURRENCY | - SQL_CA2_SENSITIVITY_ADDITIONS | - SQL_CA2_SENSITIVITY_DELETIONS | - SQL_CA2_SENSITIVITY_UPDATES; + value = SQL_CA2_OPT_ROWVER_CONCURRENCY + | SQL_CA2_SENSITIVITY_ADDITIONS + | SQL_CA2_SENSITIVITY_DELETIONS + | SQL_CA2_SENSITIVITY_UPDATES; break; case SQL_ODBC_INTERFACE_CONFORMANCE: @@ -103,11 +129,11 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, break; case SQL_BATCH_ROW_COUNT: len = 4; - value = SQL_BRC_ROLLED_UP | SQL_BRC_EXPLICIT; + value = SQL_BRC_EXPLICIT; break; case SQL_BATCH_SUPPORT: len = 4; - value = SQL_BS_ROW_COUNT_EXPLICIT; + value = SQL_BS_SELECT_EXPLICIT | SQL_BS_ROW_COUNT_EXPLICIT; break; case SQL_CATALOG_NAME: len = 0; @@ -194,7 +220,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, len = 4; value = SQL_DT_DROP_TABLE; if (PG_VERSION_GT(conn, 7.2)) /* hopefully */ - value |= SQL_DT_RESTRICT | SQL_DT_CASCADE; + value |= (SQL_DT_RESTRICT | SQL_DT_CASCADE); break; case SQL_DROP_TRANSLATION: len = 4; @@ -204,7 +230,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, len = 4; value = SQL_DV_DROP_VIEW; if (PG_VERSION_GT(conn, 7.2)) /* hopefully */ - value |= SQL_DV_RESTRICT | SQL_DV_CASCADE; + value |= (SQL_DV_RESTRICT | SQL_DV_CASCADE); break; case SQL_INDEX_KEYWORDS: len = 4; @@ -227,11 +253,11 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, break; case SQL_PARAM_ARRAY_ROW_COUNTS: len = 4; - value = SQL_PARC_NO_BATCH; + value = SQL_PARC_BATCH; break; case SQL_PARAM_ARRAY_SELECTS: len = 4; - value = SQL_PAS_NO_SELECT; + value = SQL_PAS_BATCH; break; case SQL_SQL_CONFORMANCE: len = 4; @@ -316,6 +342,7 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, return SQL_ERROR; } result = SQL_SUCCESS; + mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func, p ? p : "<NULL>", len, value, cbInfoValueMax); if (p) { /* char/binary data */ @@ -323,6 +350,14 @@ PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue, if (rgbInfoValue) { +#ifdef UNICODE_SUPPORT + if (conn->unicode) + { + len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue, cbInfoValueMax / 2); + len *= 2; + } + else +#endif /* UNICODE_SUPPORT */ strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax); if (len >= cbInfoValueMax) diff --git a/src/interfaces/odbc/misc.c b/src/interfaces/odbc/misc.c index dc505115fe3..443d1f47b3c 100644 --- a/src/interfaces/odbc/misc.c +++ b/src/interfaces/odbc/misc.c @@ -15,7 +15,6 @@ #include "psqlodbc.h" #include <stdio.h> -#include <stdlib.h> #include <stdarg.h> #include <string.h> diff --git a/src/interfaces/odbc/misc.h b/src/interfaces/odbc/misc.h index 5cedd4c147e..b658ed7c91e 100644 --- a/src/interfaces/odbc/misc.h +++ b/src/interfaces/odbc/misc.h @@ -38,6 +38,7 @@ #define MYLOGDIR "c:" #endif extern void mylog(char *fmt,...); +#define inolog mylog /* for really temporary debug */ #else #ifndef WIN32 diff --git a/src/interfaces/odbc/multibyte.c b/src/interfaces/odbc/multibyte.c index 464bf244326..06e24d08716 100644 --- a/src/interfaces/odbc/multibyte.c +++ b/src/interfaces/odbc/multibyte.c @@ -16,13 +16,6 @@ #include <stdio.h> #include <stdlib.h> -int PG_CCST; /* Client Charcter Status */ - -int PG_SCSC; /* Server Charcter Set (code) */ -int PG_CCSC; /* Client Charcter Set (code) */ -unsigned char *PG_SCSS; /* Server Charcter Set (string) */ -unsigned char *PG_CCSS; /* Client Charcter Set (string) */ - pg_CS CS_Table[] = { { "SQL_ASCII", SQL_ASCII }, @@ -78,19 +71,29 @@ pg_ismb(int characterset_code) int pg_CS_code(const unsigned char *characterset_string) { - int i = 0, c; + int i = 0, c = -1; + unsigned len = 0; for(i = 0; CS_Table[i].code != OTHER; i++) { if (strstr(characterset_string,CS_Table[i].name)) - c = CS_Table[i].code; + { + if(strlen(CS_Table[i].name) >= len) + { + len = strlen(CS_Table[i].name); + c = CS_Table[i].code; + } + + } } + if (c < 0) + c = i; return (c); } unsigned char * -pg_CS_name(const int characterset_code) +pg_CS_name(int characterset_code) { - int i = 0; + int i; for (i = 0; CS_Table[i].code != OTHER; i++) { if (CS_Table[i].code == characterset_code) @@ -242,7 +245,7 @@ pg_CS_stat(int stat,unsigned int character,int characterset_code) unsigned char * -pg_mbschr(const unsigned char *string, unsigned int character) +pg_mbschr(int csc, const unsigned char *string, unsigned int character) { int mb_st = 0; unsigned char *s; @@ -250,7 +253,7 @@ pg_mbschr(const unsigned char *string, unsigned int character) for(;;) { - mb_st = pg_CS_stat(mb_st, (unsigned char) *s,PG_CCSC); + mb_st = pg_CS_stat(mb_st, (unsigned char) *s, csc); if (mb_st == 0 && (*s == character || *s == 0)) break; else @@ -260,13 +263,13 @@ pg_mbschr(const unsigned char *string, unsigned int character) } int -pg_mbslen(const unsigned char *string) +pg_mbslen(int csc, const unsigned char *string) { unsigned char *s; int len, cs_stat; for (len = 0, cs_stat = 0, s = (unsigned char *) string; *s != 0; s++) { - cs_stat = pg_CS_stat(cs_stat,(unsigned int) *s, PG_CCSC); + cs_stat = pg_CS_stat(cs_stat,(unsigned int) *s, csc); if (cs_stat < 2) len++; } @@ -274,12 +277,12 @@ pg_mbslen(const unsigned char *string) } unsigned char * -pg_mbsinc(const unsigned char *current ) +pg_mbsinc(int csc, const unsigned char *current ) { int mb_stat = 0; if (*current != 0) { - mb_stat = (int) pg_CS_stat(mb_stat, *current, PG_CCSC); + mb_stat = (int) pg_CS_stat(mb_stat, *current, csc); if (mb_stat == 0) mb_stat = 1; return ((unsigned char *) current + mb_stat); @@ -288,43 +291,100 @@ pg_mbsinc(const unsigned char *current ) return NULL; } -void -CC_lookup_characterset(ConnectionClass *self) +static char * +CC_lookup_cs_new(ConnectionClass *self) { + char *encstr = NULL; + QResultClass *res; + + res = CC_send_query(self, "select pg_client_encoding()", NULL, TRUE); + if (res) + { + char *enc = QR_get_value_backend_row(res, 0, 0); + + if (enc) + encstr = strdup(enc); + QR_Destructor(res); + } + return encstr; +} +static char * +CC_lookup_cs_old(ConnectionClass *self) +{ + char *encstr = NULL; HSTMT hstmt; - StatementClass *stmt; RETCODE result; - static char *func = "CC_lookup_characterset"; - - mylog("%s: entering...\n", func); - PG_SCSS = malloc(MAX_CHARACTERSET_NAME); - PG_CCSS = malloc(MAX_CHARACTERSET_NAME); result = PGAPI_AllocStmt(self, &hstmt); if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - return; - stmt = (StatementClass *) hstmt; + return encstr; result = PGAPI_ExecDirect(hstmt, "Show Client_Encoding", SQL_NTS); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) + if (result == SQL_SUCCESS_WITH_INFO) { - PGAPI_FreeStmt(hstmt, SQL_DROP); - return; + char sqlState[8], errormsg[128], enc[32]; + + if (PGAPI_Error(NULL, NULL, hstmt, sqlState, NULL, errormsg, + sizeof(errormsg), NULL) == SQL_SUCCESS && + sscanf(errormsg, "%*s %*s %*s %*s %*s %s", enc) > 0) + encstr = strdup(enc); } - result = PGAPI_AllocStmt(self, &hstmt); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - return; - stmt = (StatementClass *) hstmt; + PGAPI_FreeStmt(hstmt, SQL_DROP); + return encstr; +} - result = PGAPI_ExecDirect(hstmt, "Show Server_Encoding", SQL_NTS); - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) +void +CC_lookup_characterset(ConnectionClass *self) +{ + char *encstr; + static char *func = "CC_lookup_characterset"; + + mylog("%s: entering...\n", func); + if (PG_VERSION_LT(self, 7.2)) + encstr = CC_lookup_cs_old(self); + else + encstr = CC_lookup_cs_new(self); + if (self->client_encoding) + free(self->client_encoding); + if (encstr) + { + self->client_encoding = encstr; + self->ccsc = pg_CS_code(encstr); + qlog(" [ Client encoding = '%s' (code = %d) ]\n", self->client_encoding, self->ccsc); + if (stricmp(pg_CS_name(self->ccsc), encstr)) + { + qlog(" Client encoding = '%s' and %s\n", self->client_encoding, pg_CS_name(self->ccsc)); + self->errornumber = CONN_VALUE_OUT_OF_RANGE; + self->errormsg = "client encoding mismatch"; + } + } + else { - PGAPI_FreeStmt(hstmt, SQL_DROP); - return; + self->ccsc = SQL_ASCII; + self->client_encoding = NULL; } +} - strcpy(PG_SCSS , pg_CS_name(PG_SCSC = pg_CS_code(PG_SCSS))); - strcpy(PG_CCSS , pg_CS_name(PG_CCSC = pg_CS_code(PG_CCSS))); +void encoded_str_constr(encoded_str *encstr, int ccsc, const char *str) +{ + encstr->ccsc = ccsc; + encstr->encstr = str; + encstr->pos = -1; + encstr->ccst = 0; +} +int encoded_nextchar(encoded_str *encstr) +{ + int chr; + + chr = encstr->encstr[++encstr->pos]; + encstr->ccst = pg_CS_stat(encstr->ccst, (unsigned int) chr, encstr->ccsc); + return chr; +} +int encoded_byte_check(encoded_str *encstr, int abspos) +{ + int chr; - qlog(" [ Server encoding = '%s' (code = %d), Client encoding = '%s' (code = %d) ]\n", PG_SCSS, PG_SCSC, PG_CCSS, PG_CCSC); + chr = encstr->encstr[encstr->pos = abspos]; + encstr->ccst = pg_CS_stat(encstr->ccst, (unsigned int) chr, encstr->ccsc); + return chr; } diff --git a/src/interfaces/odbc/multibyte.h b/src/interfaces/odbc/multibyte.h index b6d487b634d..47a57b0ade6 100644 --- a/src/interfaces/odbc/multibyte.h +++ b/src/interfaces/odbc/multibyte.h @@ -4,13 +4,14 @@ * */ #include "psqlodbc.h" +#include "qresult.h" /* PostgreSQL client encoding */ #define SQL_ASCII 0 /* SQL/ASCII */ #define EUC_JP 1 /* EUC for Japanese */ #define EUC_CN 2 /* EUC for Chinese */ #define EUC_KR 3 /* EUC for Korean */ -#define EUC_TW 4 /* EUC for Taiwan */
+#define EUC_TW 4 /* EUC for Taiwan */ #define JOHAB 5 #define UTF8 6 /* Unicode UTF-8 */ #define MULE_INTERNAL 7 /* Mule internal code */ @@ -22,66 +23,67 @@ #define LATIN6 13 /* ISO-8859 Latin 6 */ #define LATIN7 14 /* ISO-8859 Latin 7 */ #define LATIN8 15 /* ISO-8859 Latin 8 */ -#define LATIN9 16 /* ISO-8859 Latin 9 */
-#define LATIN10 17 /* ISO-8859 Latin 10 */
-#define WIN1256 18 /* Arabic Windows */
-#define TCVN 19 /* Vietnamese Windows */
-#define WIN874 20 /* Thai Windows */
-#define KOI8R 21 /* KOI8-R/U */
+#define LATIN9 16 /* ISO-8859 Latin 9 */ +#define LATIN10 17 /* ISO-8859 Latin 10 */ +#define WIN1256 18 /* Arabic Windows */ +#define TCVN 19 /* Vietnamese Windows */ +#define WIN874 20 /* Thai Windows */ +#define KOI8R 21 /* KOI8-R/U */ #define WIN1251 22 /* windows-1251 */ #define ALT 23 /* Alternativny Variant (MS-DOS CP866) */ -#define ISO_8859_5 24 /* ISO-8859-5 */
-#define ISO_8859_6 25 /* ISO-8859-6 */
-#define ISO_8859_7 26 /* ISO-8859-7 */
-#define ISO_8859_8 27 /* ISO-8859-8 */
-
+#define ISO_8859_5 24 /* ISO-8859-5 */ +#define ISO_8859_6 25 /* ISO-8859-6 */ +#define ISO_8859_7 26 /* ISO-8859-7 */ +#define ISO_8859_8 27 /* ISO-8859-8 */ + #define SJIS 28 /* Shift JIS */ -#define BIG5 29 /* Big5 */
-#define GBK 30 /* GBK */
-#define UHC 31 /* UHC */
-#define WIN1250 32 /* windows-1250 */
-#define OTHER -1
-
-#define MAX_CHARACTERSET_NAME 24
-#define MAX_CHARACTER_LEN 6
+#define BIG5 29 /* Big5 */ +#define GBK 30 /* GBK */ +#define UHC 31 /* UHC */ +#define WIN1250 32 /* windows-1250 */ +#define OTHER -1 + +#define MAX_CHARACTERSET_NAME 24 +#define MAX_CHARACTER_LEN 6 -/* OLD Type */
+/* OLD Type */ // extern int multibyte_client_encoding; /* Multibyte client encoding. */ // extern int multibyte_status; /* Multibyte charcter status. */ // // void multibyte_init(void); // unsigned char *check_client_encoding(unsigned char *sql_string); // int multibyte_char_check(unsigned char s); -// unsigned char *multibyte_strchr(const unsigned char *string, unsigned int c);
-
-/* New Type */
-
-extern int PG_CCST; /* Client Character StaTus */
-
-extern int PG_SCSC; /* Server Character Set (Code) */
-extern int PG_CCSC; /* Client Character Set (Code) */
-extern unsigned char *PG_SCSS; /* Server Character Set (String) */
-extern unsigned char *PG_CCSS; /* Client Character Set (String) */
-
-extern void CC_lookup_characterset(ConnectionClass *self);
-
-extern int pg_CS_stat(int stat,unsigned int charcter,int characterset_code);
-extern int pg_CS_code(const unsigned char *stat_string);
-extern unsigned char *pg_CS_name(const int code);
-
-typedef struct pg_CS
-{
- unsigned char *name;
- int code;
-}pg_CS;
-extern pg_CS CS_Table[];
-
-extern int pg_mbslen(const unsigned char *string);
-extern unsigned char *pg_mbschr(const unsigned char *string, unsigned int character);
-extern unsigned char *pg_mbsinc( const unsigned char *current );
-
-/* Old Type Compatible */
-#define multibyte_init() (PG_CCST = 0)
-#define multibyte_char_check(X) pg_CS_stat(PG_CCST, (unsigned int) X, PG_CCSC)
-#define multibyte_strchr(X,Y) pg_mbschr(X,Y)
-#define check_client_encoding(X) pg_CS_name(PG_CCSC = pg_CS_code(X))
+// unsigned char *multibyte_strchr(const unsigned char *string, unsigned int c); + +/* New Type */ + +extern void CC_lookup_characterset(ConnectionClass *self); + +extern int pg_CS_stat(int stat,unsigned int charcter,int characterset_code); +extern int pg_CS_code(const unsigned char *stat_string); +extern unsigned char *pg_CS_name(int code); + +typedef struct pg_CS +{ + unsigned char *name; + int code; +}pg_CS; +extern int pg_mbslen(int ccsc, const unsigned char *string); +extern unsigned char *pg_mbschr(int ccsc, const unsigned char *string, unsigned int character); +extern unsigned char *pg_mbsinc(int ccsc, const unsigned char *current ); + +/* Old Type Compatible */ +typedef struct +{ + int ccsc; + const char *encstr; + int pos; + int ccst; +} encoded_str; +#define ENCODE_STATUS(enc) ((enc).ccst) + +void encoded_str_constr(encoded_str *encstr, int ccsc, const char *str); +#define make_encoded_str(encstr, conn, str) encoded_str_constr(encstr, conn->ccsc, str) +extern int encoded_nextchar(encoded_str *encstr); +extern int encoded_byte_check(encoded_str *encstr, int abspos); +#define check_client_encoding(X) pg_CS_name(pg_CS_code(X)) diff --git a/src/interfaces/odbc/odbcapi.c b/src/interfaces/odbc/odbcapi.c index 0527b21c38b..cbb31dad0a7 100644 --- a/src/interfaces/odbc/odbcapi.c +++ b/src/interfaces/odbc/odbcapi.c @@ -174,7 +174,8 @@ SQLError(HENV EnvironmentHandle, { mylog("[SQLError]"); return PGAPI_Error(EnvironmentHandle, ConnectionHandle, StatementHandle, - Sqlstate, NativeError, MessageText, BufferLength, TextLength); + Sqlstate, NativeError, MessageText, BufferLength, + TextLength); } RETCODE SQL_API @@ -281,23 +282,31 @@ SQLGetInfo(HDBC ConnectionHandle, SQLUSMALLINT InfoType, PTR InfoValue, SQLSMALLINT BufferLength, SQLSMALLINT *StringLength) { -#if (ODBCVER >= 0x0300) RETCODE ret; + ConnectionClass *conn = (ConnectionClass *) ConnectionHandle; + CC_clear_error(conn); +#if (ODBCVER >= 0x0300) mylog("[SQLGetInfo(30)]"); if ((ret = PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue, BufferLength, StringLength)) == SQL_ERROR) { if (((ConnectionClass *) ConnectionHandle)->driver_version >= 0x0300) - return PGAPI_GetInfo30(ConnectionHandle, InfoType, InfoValue, + { + CC_clear_error(conn); + ret = PGAPI_GetInfo30(ConnectionHandle, InfoType, InfoValue, BufferLength, StringLength); + } } - return ret; + if (SQL_ERROR == ret) + CC_log_error("SQLGetInfo30", "", conn); #else mylog("[SQLGetInfo]"); - return PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue, - BufferLength, StringLength); + if (ret = PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue, + BufferLength, StringLength), SQL_ERROR == ret) + CC_log_error("PGAPI_GetInfo", "", conn); #endif + return ret; } RETCODE SQL_API @@ -638,7 +647,7 @@ SQLTablePrivileges( { mylog("[SQLTablePrivileges]"); return PGAPI_TablePrivileges(hstmt, szCatalogName, cbCatalogName, - szSchemaName, cbSchemaName, szTableName, cbTableName); + szSchemaName, cbSchemaName, szTableName, cbTableName, 0); } RETCODE SQL_API diff --git a/src/interfaces/odbc/odbcapi25w.c b/src/interfaces/odbc/odbcapi25w.c index 0bebf5d128c..47015a23220 100644 --- a/src/interfaces/odbc/odbcapi25w.c +++ b/src/interfaces/odbc/odbcapi25w.c @@ -25,22 +25,27 @@ RETCODE SQL_API SQLErrorW(HENV EnvironmentHandle, SQLSMALLINT *TextLength) { RETCODE ret; - SWORD tlen; + SWORD tlen, buflen; char *qst = NULL, *mtxt = NULL; mylog("[SQLErrorW]"); if (Sqlstate) qst = malloc(8); - if (MessageText) - mtxt = malloc(BufferLength); + buflen = 0; + if (MessageText && BufferLength > 0) + { + buflen = BufferLength * 3 + 1; + mtxt = malloc(buflen); + } ret = PGAPI_Error(EnvironmentHandle, ConnectionHandle, StatementHandle, - qst, NativeError, mtxt, BufferLength, &tlen); + qst, NativeError, mtxt, buflen, &tlen); if (qst) utf8_to_ucs2(qst, strlen(qst), Sqlstate, 5); if (TextLength) *TextLength = utf8_to_ucs2(mtxt, tlen, MessageText, BufferLength); free(qst); - free(mtxt); + if (mtxt) + free(mtxt); return ret; } @@ -56,6 +61,7 @@ RETCODE SQL_API SQLSetConnectOptionW(HDBC ConnectionHandle, SQLUSMALLINT Option, SQLUINTEGER Value) { mylog("[SQLSetConnectionOptionW]"); +if (!ConnectionHandle) return SQL_ERROR; ((ConnectionClass *) ConnectionHandle)->unicode = 1; return PGAPI_SetConnectOption(ConnectionHandle, Option, Value); } diff --git a/src/interfaces/odbc/odbcapi30.c b/src/interfaces/odbc/odbcapi30.c index 2c5e73bf359..6d4ad1f2877 100644 --- a/src/interfaces/odbc/odbcapi30.c +++ b/src/interfaces/odbc/odbcapi30.c @@ -144,9 +144,7 @@ SQLEndTran(SQLSMALLINT HandleType, SQLHANDLE Handle, default: break; } - return SQL_ERROR; /* SQLSTATE HY092 ("Invalid - * attribute/option identifier") */ - + return SQL_ERROR; } /* SQLExtendedFetch -> SQLFetchScroll */ @@ -246,39 +244,9 @@ SQLGetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLINTEGER *NativeError, SQLCHAR *MessageText, SQLSMALLINT BufferLength, SQLSMALLINT *TextLength) { - RETCODE ret; - mylog("[[SQLGetDiagRec]]\n"); - switch (HandleType) - { - case SQL_HANDLE_ENV: - ret = PGAPI_Error(Handle, NULL, NULL, Sqlstate, NativeError, - MessageText, BufferLength, TextLength); - break; - case SQL_HANDLE_DBC: - ret = PGAPI_Error(NULL, Handle, NULL, Sqlstate, NativeError, - MessageText, BufferLength, TextLength); - break; - case SQL_HANDLE_STMT: - ret = PGAPI_Error(NULL, NULL, Handle, Sqlstate, NativeError, - MessageText, BufferLength, TextLength); - break; - default: - ret = SQL_ERROR; - } - if (ret == SQL_SUCCESS_WITH_INFO && - BufferLength == 0 && - *TextLength) - { - SQLSMALLINT BufferLength = *TextLength + 4; - SQLCHAR *MessageText = malloc(BufferLength); - - ret = SQLGetDiagRec(HandleType, Handle, RecNumber, Sqlstate, - NativeError, MessageText, BufferLength, - TextLength); - free(MessageText); - } - return ret; + return PGAPI_GetDiagRec(HandleType, Handle, RecNumber, Sqlstate, + NativeError, MessageText, BufferLength, TextLength); } /* new function */ @@ -299,7 +267,7 @@ SQLGetEnvAttr(HENV EnvironmentHandle, *((unsigned int *) Value) = SQL_CP_RELAXED_MATCH; break; case SQL_ATTR_ODBC_VERSION: - *((unsigned int *) Value) = SQL_OV_ODBC3; + *((unsigned int *) Value) = EN_is_odbc2(env) ? SQL_OV_ODBC2 : SQL_OV_ODBC3; break; case SQL_ATTR_OUTPUT_NTS: *((unsigned int *) Value) = SQL_TRUE; @@ -456,6 +424,7 @@ ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength) { RETCODE ret = SQL_SUCCESS; + PTR tptr; switch (FieldIdentifier) { case SQL_DESC_ARRAY_SIZE: @@ -470,8 +439,34 @@ ARDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, case SQL_DESC_BIND_TYPE: stmt->options.bind_size = (SQLUINTEGER) Value; break; + + case SQL_DESC_DATA_PTR: + if (!RecNumber) + stmt->bookmark.buffer = Value; + else + stmt->bindings[RecNumber - 1].buffer = Value; + break; + case SQL_DESC_INDICATOR_PTR: + if (!RecNumber) + tptr = stmt->bookmark.used; + else + tptr = stmt->bindings[RecNumber - 1].used; + if (Value != tptr) + { + ret = SQL_ERROR; + stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; + stmt->errormsg = "INDICATOR != OCTET_LENGTH_PTR"; + } + break; + case SQL_DESC_OCTET_LENGTH_PTR: + if (!RecNumber) + stmt->bookmark.used = Value; + else + stmt->bindings[RecNumber - 1].used = Value; + break; default:ret = SQL_ERROR; stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; + stmt->errormsg = "not implemedted yet"; } return ret; } @@ -495,6 +490,26 @@ APDSetField(StatementClass *stmt, SQLSMALLINT RecNumber, case SQL_DESC_BIND_TYPE: stmt->options.param_bind_type = (SQLUINTEGER) Value; break; + + case SQL_DESC_DATA_PTR: + if (stmt->parameters_allocated < RecNumber) + PGAPI_BindParameter(stmt, RecNumber, 0, 0, 0, 0, 0, 0, 0, 0); + stmt->parameters[RecNumber - 1].buffer = Value; + break; + case SQL_DESC_INDICATOR_PTR: + if (stmt->parameters_allocated < RecNumber || + Value != stmt->parameters[RecNumber - 1].used) + { + ret = SQL_ERROR; + stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; + stmt->errormsg = "INDICATOR != OCTET_LENGTH_PTR"; + } + break; + case SQL_DESC_OCTET_LENGTH_PTR: + if (stmt->parameters_allocated < RecNumber) + PGAPI_BindParameter(stmt, RecNumber, 0, 0, 0, 0, 0, 0, 0, 0); + stmt->parameters[RecNumber - 1].used = Value; + break; default:ret = SQL_ERROR; stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; } @@ -549,6 +564,8 @@ SQLSetDescField(SQLHDESC DescriptorHandle, HSTMT hstmt; SQLUINTEGER descType; StatementClass *stmt; + static const char *func = "SQLSetDescField"; + mylog("[[SQLSetDescField]] h=%u rec=%d field=%d val=%x\n", DescriptorHandle, RecNumber, FieldIdentifier, Value); hstmt = statementHandleFromDescHandle(DescriptorHandle, &descType); mylog("stmt=%x type=%d\n", hstmt, descType); @@ -569,8 +586,10 @@ SQLSetDescField(SQLHDESC DescriptorHandle, break; default:ret = SQL_ERROR; stmt->errornumber = STMT_INTERNAL_ERROR; - mylog("Error not implemented\n"); + stmt->errormsg = "Error not implemented"; } + if (ret == SQL_ERROR) + SC_log_error(func, "", stmt); return ret; } @@ -583,6 +602,8 @@ SQLSetDescRec(SQLHDESC DescriptorHandle, PTR Data, SQLINTEGER *StringLength, SQLINTEGER *Indicator) { + const char *func = "SQLSetDescField"; + mylog("[[SQLSetDescRec]]\n"); mylog("Error not implemented\n"); return SQL_ERROR; @@ -608,7 +629,10 @@ SQLSetEnvAttr(HENV EnvironmentHandle, return SQL_SUCCESS; case SQL_ATTR_ODBC_VERSION: if ((SQLUINTEGER) Value == SQL_OV_ODBC2) - return SQL_SUCCESS; + EN_set_odbc2(env); + else + EN_set_odbc3(env); + return SQL_SUCCESS; break; case SQL_ATTR_OUTPUT_NTS: if ((SQLUINTEGER) Value == SQL_TRUE) @@ -652,44 +676,46 @@ SQLSetStmtAttr(HSTMT StatementHandle, * case SQL_ATTR_PREDICATE_PTR: case * SQL_ATTR_PREDICATE_OCTET_LENGTH_PTR: */ - case SQL_ATTR_PARAM_OPERATION_PTR: /* 19 */ - case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */ - case SQL_ATTR_ROW_OPERATION_PTR: /* 24 */ stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; stmt->errormsg = "Unsupported statement option (Set)"; SC_log_error(func, "", stmt); return SQL_ERROR; - case SQL_ATTR_PARAM_BIND_OFFSET_PTR: /* 17 */ - stmt->options.param_offset_ptr = (SQLUINTEGER *) Value; - break; - case SQL_ATTR_ROW_BIND_OFFSET_PTR: /* 23 */ - stmt->options.row_offset_ptr = (SQLUINTEGER *) Value; - break; - case SQL_ATTR_FETCH_BOOKMARK_PTR: /* 16 */ stmt->options.bookmark_ptr = Value; break; + case SQL_ATTR_PARAM_BIND_OFFSET_PTR: /* 17 */ + stmt->options.param_offset_ptr = (SQLUINTEGER *) Value; + break; case SQL_ATTR_PARAM_BIND_TYPE: /* 18 */ stmt->options.param_bind_type = (SQLUINTEGER) Value; break; + case SQL_ATTR_PARAM_OPERATION_PTR: /* 19 */ + stmt->options.param_operation_ptr = Value; + break; + case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */ + stmt->options.param_status_ptr = (SQLUSMALLINT *) Value; + break; case SQL_ATTR_PARAMS_PROCESSED_PTR: /* 21 */ stmt->options.param_processed_ptr = (SQLUINTEGER *) Value; break; case SQL_ATTR_PARAMSET_SIZE: /* 22 */ stmt->options.paramset_size = (SQLUINTEGER) Value; break; + case SQL_ATTR_ROW_BIND_OFFSET_PTR: /* 23 */ + stmt->options.row_offset_ptr = (SQLUINTEGER *) Value; + break; + case SQL_ATTR_ROW_OPERATION_PTR: /* 24 */ + stmt->options.row_operation_ptr = Value; + break; case SQL_ATTR_ROW_STATUS_PTR: /* 25 */ stmt->options.rowStatusArray = (SQLUSMALLINT *) Value; - break; case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */ stmt->options.rowsFetched = (SQLUINTEGER *) Value; - break; case SQL_ATTR_ROW_ARRAY_SIZE: /* 27 */ stmt->options.rowset_size = (SQLUINTEGER) Value; - break; default: return PGAPI_SetStmtOption(StatementHandle, (UWORD) Attribute, (UDWORD) Value); @@ -704,7 +730,7 @@ SQLSetStmtAttr(HSTMT StatementHandle, RETCODE SQL_API PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists) { - ConnectionClass *conn = (ConnectionClass *) hdbc; + ConnectionClass *conn = (ConnectionClass *) hdbc; ConnInfo *ci = &(conn->connInfo); if (fFunction != SQL_API_ODBC3_ALL_FUNCTIONS) @@ -755,17 +781,14 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists) SQL_FUNC_ESET(pfExists, SQL_API_SQLPARAMDATA); /* 48 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLPUTDATA); /* 49 */ - /* - * SQL_FUNC_ESET(pfExists, SQL_API_SQLSETCONNECTIONOPTION); 50 - * deprecated - */ + /* SQL_FUNC_ESET(pfExists, SQL_API_SQLSETCONNECTIONOPTION); 50 deprecated */ /* SQL_FUNC_ESET(pfExists, SQL_API_SQLSETSTMTOPTION); 51 deprecated */ - SQL_FUNC_ESET(pfExists, SQL_API_SQLSPECIALCOLUMNS); /* 52 */ + SQL_FUNC_ESET(pfExists, SQL_API_SQLSPECIALCOLUMNS); /* 52 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLSTATISTICS); /* 53 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLTABLES); /* 54 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLBROWSECONNECT); /* 55 */ if (ci->drivers.lie) - SQL_FUNC_ESET(pfExists, SQL_API_SQLCOLUMNPRIVILEGES); /* 56 not implmented yet */ + SQL_FUNC_ESET(pfExists, SQL_API_SQLCOLUMNPRIVILEGES); /* 56 not implemented yet */ SQL_FUNC_ESET(pfExists, SQL_API_SQLDATASOURCES); /* 57 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLDESCRIBEPARAM); /* 58 */ /* SQL_FUNC_ESET(pfExists, SQL_API_SQLEXTENDEDFETCH); 59 deprecated */ @@ -781,12 +804,11 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists) /* SQL_FUNC_ESET(pfExists, SQL_API_SQLPARAMOPTIONS); 64 deprecated */ SQL_FUNC_ESET(pfExists, SQL_API_SQLPRIMARYKEYS); /* 65 */ if (ci->drivers.lie) - SQL_FUNC_ESET(pfExists, SQL_API_SQLPROCEDURECOLUMNS); /* 66 not implmented yet */ + SQL_FUNC_ESET(pfExists, SQL_API_SQLPROCEDURECOLUMNS); /* 66 not implemeted yet */ SQL_FUNC_ESET(pfExists, SQL_API_SQLPROCEDURES); /* 67 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLSETPOS); /* 68 */ - SQL_FUNC_ESET(pfExists, SQL_API_SQLSETSCROLLOPTIONS); /* 69 deprecated */ - if (ci->drivers.lie) - SQL_FUNC_ESET(pfExists, SQL_API_SQLTABLEPRIVILEGES); /* 70 not implemented yet */ + /* SQL_FUNC_ESET(pfExists, SQL_API_SQLSETSCROLLOPTIONS); 69 deprecated */ + SQL_FUNC_ESET(pfExists, SQL_API_SQLTABLEPRIVILEGES); /* 70 */ /* SQL_FUNC_ESET(pfExists, SQL_API_SQLDRIVERS); */ /* 71 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLBINDPARAMETER); /* 72 */ @@ -801,7 +823,7 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists) if (ci->drivers.lie) { SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDESCFIELD); /* 1008 not implemented yet */ - SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDESCREC); /* 1009 not implemented yet */ + SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDESCREC); /* 1009 not implemented yet */ SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDIAGFIELD); /* 1010 not implemented yet */ } SQL_FUNC_ESET(pfExists, SQL_API_SQLGETDIAGREC); /* 1011 */ @@ -810,7 +832,9 @@ PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists) SQL_FUNC_ESET(pfExists, SQL_API_SQLSETCONNECTATTR); /* 1016 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLSETDESCFIELD); /* 1017 */ if (ci->drivers.lie) - SQL_FUNC_ESET(pfExists, SQL_API_SQLSETDESCREC); /* 1018 not implemented yet */ + { + SQL_FUNC_ESET(pfExists, SQL_API_SQLSETDESCREC); /* 1018 not implemented yet */ + } SQL_FUNC_ESET(pfExists, SQL_API_SQLSETENVATTR); /* 1019 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLSETSTMTATTR); /* 1020 */ SQL_FUNC_ESET(pfExists, SQL_API_SQLFETCHSCROLL); /* 1021 */ diff --git a/src/interfaces/odbc/odbcapi30w.c b/src/interfaces/odbc/odbcapi30w.c index d2a2005c1b9..35237202faa 100644 --- a/src/interfaces/odbc/odbcapi30w.c +++ b/src/interfaces/odbc/odbcapi30w.c @@ -85,22 +85,37 @@ RETCODE SQL_API SQLGetDiagRecW(SWORD fHandleType, SQLSMALLINT *pcbErrorMsg) { RETCODE ret; - SWORD tlen; - char *qst = NULL, *mtxt = NULL; + SWORD buflen, tlen; + char *qstr = NULL, *mtxt = NULL; mylog("[SQLGetDiagRecW]"); if (szSqlState) - qst = malloc(8); - if (szErrorMsg) - mtxt = malloc(cbErrorMsgMax); - ret = PGAPI_GetDiagRec(fHandleType, handle, iRecord, qst, - pfNativeError, mtxt, cbErrorMsgMax, &tlen); - if (qst) - utf8_to_ucs2(qst, strlen(qst), szSqlState, 5); - if (pcbErrorMsg) - *pcbErrorMsg = utf8_to_ucs2(mtxt, tlen, szErrorMsg, cbErrorMsgMax); - free(qst); - free(mtxt); + qstr = malloc(8); + buflen = 0; + if (szErrorMsg && cbErrorMsgMax > 0) + { + buflen = cbErrorMsgMax; + mtxt = malloc(buflen); + } + ret = PGAPI_GetDiagRec(fHandleType, handle, iRecord, qstr, + pfNativeError, mtxt, buflen, &tlen); + if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) + { + if (qstr) + utf8_to_ucs2(qstr, strlen(qstr), szSqlState, 6); + if (mtxt && tlen <= cbErrorMsgMax) + { + tlen = utf8_to_ucs2(mtxt, tlen, szErrorMsg, cbErrorMsgMax); + if (tlen >= cbErrorMsgMax) + ret = SQL_SUCCESS_WITH_INFO; + } + if (pcbErrorMsg) + *pcbErrorMsg = tlen; + } + if (qstr); + free(qstr); + if (mtxt) + free(mtxt); return ret; } diff --git a/src/interfaces/odbc/odbcapiw.c b/src/interfaces/odbc/odbcapiw.c index 637f69f9699..ac1e3f28f4e 100755 --- a/src/interfaces/odbc/odbcapiw.c +++ b/src/interfaces/odbc/odbcapiw.c @@ -13,7 +13,7 @@ SQLPrepareW, SQLPrimaryKeysW, SQLProcedureColumnsW, SQLProceduresW, SQLSetCursorNameW, SQLSpecialColumnsW, SQLStatisticsW, SQLTablesW, - SQLTablePrivilegesW + SQLTablePrivilegesW, SQLGetTypeInfoW *------- */ @@ -102,7 +102,11 @@ RETCODE SQL_API SQLDriverConnectW(HDBC hdbc, ret = PGAPI_DriverConnect(hdbc, hwnd, szIn, (SWORD) inlen, szOut, cbConnStrOutMax, &olen, fDriverCompletion); if (ret != SQL_ERROR) - *pcbConnStrOut = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax); + { + UInt4 outlen = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax); + if (pcbConnStrOut) + *pcbConnStrOut = outlen; + } free(szOut); if (szIn); free(szIn); @@ -129,7 +133,11 @@ RETCODE SQL_API SQLBrowseConnectW( ret = PGAPI_BrowseConnect(hdbc, szIn, (SWORD) inlen, szOut, cbConnStrOutMax, &olen); if (ret != SQL_ERROR) - *pcbConnStrOut = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax); + { + UInt4 outlen = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax); + if (pcbConnStrOut) + *pcbConnStrOut = outlen; + } free(szOut); if (szIn); free(szIn); @@ -158,15 +166,28 @@ RETCODE SQL_API SQLDescribeColW(HSTMT StatementHandle, SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable) { RETCODE ret; - SWORD nmlen; + SWORD buflen, nmlen; char *clName; mylog("[SQLDescribeColW]"); - clName = malloc(BufferLength); + buflen = BufferLength * 3 + 1; + clName = malloc(buflen); ret = PGAPI_DescribeCol(StatementHandle, ColumnNumber, - clName, BufferLength, &nmlen, - DataType, ColumnSize, DecimalDigits, Nullable); - *NameLength = utf8_to_ucs2(clName, nmlen, ColumnName, BufferLength); + clName, buflen, &nmlen, DataType, ColumnSize, + DecimalDigits, Nullable); + if (ret == SQL_SUCCESS) + { + UInt4 nmcount = utf8_to_ucs2(clName, nmlen, ColumnName, BufferLength); + if (nmcount > (UInt4) BufferLength) + { + StatementClass *stmt = (StatementClass *) StatementHandle; + ret = SQL_SUCCESS_WITH_INFO; + stmt->errornumber = STMT_TRUNCATED; + stmt->errormsg = "Column name too large"; + } + if (NameLength) + *NameLength = nmcount; + } free(clName); return ret; } @@ -192,13 +213,25 @@ RETCODE SQL_API SQLGetCursorNameW(HSTMT StatementHandle, { RETCODE ret; char *crName; - SWORD clen; + SWORD clen, buflen; mylog("[SQLGetCursorNameW]"); - crName = malloc(BufferLength); - ret = PGAPI_GetCursorName(StatementHandle, crName, BufferLength, - &clen); - *NameLength = utf8_to_ucs2(crName, (Int4) clen, CursorName, BufferLength); + buflen = BufferLength * 3 + 1; + crName = malloc(buflen); + ret = PGAPI_GetCursorName(StatementHandle, crName, buflen, &clen); + if (ret == SQL_SUCCESS) + { + UInt4 nmcount = utf8_to_ucs2(crName, (Int4) clen, CursorName, BufferLength); + if (nmcount > (UInt4) BufferLength) + { + StatementClass *stmt = (StatementClass *) StatementHandle; + ret = SQL_SUCCESS_WITH_INFO; + stmt->errornumber = STMT_TRUNCATED; + stmt->errormsg = "Cursor name too large"; + } + if (NameLength) + *NameLength = utf8_to_ucs2(crName, (Int4) clen, CursorName, BufferLength); + } free(crName); return ret; } @@ -207,23 +240,33 @@ RETCODE SQL_API SQLGetInfoW(HDBC ConnectionHandle, SQLUSMALLINT InfoType, PTR InfoValue, SQLSMALLINT BufferLength, SQLSMALLINT *StringLength) { + ConnectionClass *conn = (ConnectionClass *) ConnectionHandle; RETCODE ret; - ((ConnectionClass *) ConnectionHandle)->unicode = 1; + + conn->unicode = 1; + CC_clear_error(conn); #if (ODBCVER >= 0x0300) mylog("[SQLGetInfoW(30)]"); if ((ret = PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue, BufferLength, StringLength)) == SQL_ERROR) { - if (((ConnectionClass *) ConnectionHandle)->driver_version >= 0x0300) - return PGAPI_GetInfo30(ConnectionHandle, InfoType, InfoValue, + if (conn->driver_version >= 0x0300) + { + CC_clear_error(conn); + ret = PGAPI_GetInfo30(ConnectionHandle, InfoType, InfoValue, BufferLength, StringLength); + } } - return ret; + if (SQL_ERROR == ret) + CC_log_error("SQLGetInfoW(30)", "", conn); #else mylog("[SQLGetInfoW]"); - return PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue, + ret = PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue, BufferLength, StringLength); + if (SQL_ERROR == ret) + CC_log_error("SQLGetInfoW", "", conn); #endif + return ret; } RETCODE SQL_API SQLPrepareW(HSTMT StatementHandle, @@ -428,17 +471,31 @@ RETCODE SQL_API SQLNativeSqlW( RETCODE ret; char *szIn, *szOut; UInt4 slen; - SQLINTEGER olen; + SQLINTEGER buflen, olen; mylog("[SQLNativeSqlW]"); ((ConnectionClass *) hdbc)->unicode = 1; szIn = ucs2_to_utf8(szSqlStrIn, cbSqlStrIn, &slen); - szOut = malloc(cbSqlStrMax); + buflen = 3 * cbSqlStrMax + 1; + szOut = malloc(buflen); ret = PGAPI_NativeSql(hdbc, szIn, (SQLINTEGER) slen, - szOut, cbSqlStrMax, &olen); + szOut, buflen, &olen); if (szIn); free(szIn); - *pcbSqlStr = utf8_to_ucs2(szOut, olen, szSqlStr, cbSqlStrMax); + if (ret == SQL_SUCCESS) + { + UInt4 szcount = utf8_to_ucs2(szOut, olen, szSqlStr, cbSqlStrMax); + if (szcount > (UInt4) cbSqlStrMax) + { + ConnectionClass *conn = (ConnectionClass *) hdbc; + + ret = SQL_SUCCESS_WITH_INFO; + conn->errornumber = CONN_TRUNCATED; + conn->errormsg = "Sql string too large"; + } + if (pcbSqlStr) + *pcbSqlStr = szcount; + } free(szOut); return ret; } @@ -560,3 +617,10 @@ RETCODE SQL_API SQLTablePrivilegesW( free(tbName); return ret; } + +RETCODE SQL_API SQLGetTypeInfoW( + SQLHSTMT StatementHandle, + SQLSMALLINT DataType) +{ + return PGAPI_GetTypeInfo(StatementHandle, DataType); +} diff --git a/src/interfaces/odbc/options.c b/src/interfaces/odbc/options.c index 80ec7dac68e..d58f84916fc 100644 --- a/src/interfaces/odbc/options.c +++ b/src/interfaces/odbc/options.c @@ -342,12 +342,13 @@ PGAPI_SetConnectOption( break; case SQL_AUTOCOMMIT: - if (vParam == SQL_AUTOCOMMIT_ON && CC_is_in_autocommit(conn)) + if (vParam == SQL_AUTOCOMMIT_ON && CC_is_in_trans(conn)) break; - else if (vParam == SQL_AUTOCOMMIT_OFF && !CC_is_in_autocommit(conn)) + else if (vParam == SQL_AUTOCOMMIT_OFF && !CC_is_in_trans(conn)) break; if (CC_is_in_trans(conn)) CC_commit(conn); + mylog("PGAPI_SetConnectOption: AUTOCOMMIT: transact_status=%d, vparam=%d\n", conn->transact_status, vParam); switch (vParam) @@ -401,8 +402,21 @@ PGAPI_SetConnectOption( sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam); if (fOption == 30002 && vParam) { - if (strcmp((char *) vParam, "Microsoft Jet") == 0) + int cmp; +#ifdef UNICODE_SUPPORT + char *asPara; + if (conn->unicode) + { + asPara = ucs2_to_utf8((SQLWCHAR *) vParam, -1, NULL); + cmp = strcmp(asPara, "Microsoft Jet"); + free(asPara); + } + else +#endif /* UNICODE_SUPPORT */ + cmp = strncmp((char *) vParam, "Microsoft Jet", 13); + if (0 == cmp) { + mylog("Microsoft Jet !!!!\n"); conn->errornumber = 0; conn->ms_jet = 1; return SQL_SUCCESS; @@ -456,7 +470,7 @@ PGAPI_GetConnectOption( case SQL_CURRENT_QUALIFIER: /* don't use qualifiers */ if (pvParam) - strcpy(pvParam, ""); + ((char *) pvParam)[0] = ((char *) pvParam)[1] = '\0'; break; @@ -557,7 +571,7 @@ PGAPI_GetStmtOption( case SQL_GET_BOOKMARK: case SQL_ROW_NUMBER: - res = stmt->result; + res = SC_get_Curres(stmt); if (stmt->manual_result || !ci->drivers.use_declarefetch) { diff --git a/src/interfaces/odbc/parse.c b/src/interfaces/odbc/parse.c index 525fb736fdf..55bb08bd93b 100644 --- a/src/interfaces/odbc/parse.c +++ b/src/interfaces/odbc/parse.c @@ -42,18 +42,29 @@ #define TAB_INCR 8 #define COL_INCR 16 +#ifdef MULTIBYTE +char *getNextToken(int ccsc, char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric); +#else char *getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric); +#endif /* MULTIBYTE */ void getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k); char searchColInfo(COL_INFO *col_info, FIELD_INFO *fi); char * -getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric) +getNextToken( +#ifdef MULTIBYTE + int ccsc, /* client encoding */ +#endif /* MULTIBYTE */ + char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric) { int i = 0; int out = 0; char qc, in_escape = FALSE; +#ifdef MULTIBYTE + encoded_str encstr; +#endif if (smax <= 1) return NULL; @@ -80,17 +91,22 @@ getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dqu if (numeric) *numeric = FALSE; +#ifdef MULTIBYTE + encoded_str_constr(&encstr, ccsc, &s[i]); +#endif /* get the next token */ - while (!isspace((unsigned char) s[i]) && s[i] != ',' && - s[i] != '\0' && out != smax) + while (s[i] != '\0' && out < smax) { #ifdef MULTIBYTE - if (multibyte_char_check(s[i]) != 0) + encoded_nextchar(&encstr); + if (ENCODE_STATUS(encstr) != 0) { token[out++] = s[i++]; continue; } #endif + if (isspace((unsigned char) s[i]) || s[i] == ',') + break; /* Handle quoted stuff */ if (out == 0 && (s[i] == '\"' || s[i] == '\'')) { @@ -110,7 +126,8 @@ getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dqu while (s[i] != '\0' && out != smax) { #ifdef MULTIBYTE - if (multibyte_char_check(s[i]) != 0) + encoded_nextchar(&encstr); + if (ENCODE_STATUS(encstr) != 0) { token[out++] = s[i++]; continue; @@ -197,22 +214,22 @@ getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dqu #if 0 -QR_set_num_fields(stmt->result, 14); -QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); -QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); -QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); -QR_set_field_info(stmt->result, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); -QR_set_field_info(stmt->result, 4, "DATA_TYPE", PG_TYPE_INT2, 2); -QR_set_field_info(stmt->result, 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); -QR_set_field_info(stmt->result, 6, "PRECISION", PG_TYPE_INT4, 4); -QR_set_field_info(stmt->result, 7, "LENGTH", PG_TYPE_INT4, 4); -QR_set_field_info(stmt->result, 8, "SCALE", PG_TYPE_INT2, 2); -QR_set_field_info(stmt->result, 9, "RADIX", PG_TYPE_INT2, 2); -QR_set_field_info(stmt->result, 10, "NULLABLE", PG_TYPE_INT2, 2); -QR_set_field_info(stmt->result, 11, "REMARKS", PG_TYPE_TEXT, 254); +QR_set_num_fields(SC_get_Curres(stmt), 14); +QR_set_field_info(SC_get_Curres(stmt), 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING); +QR_set_field_info(SC_get_Curres(stmt), 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING); +QR_set_field_info(SC_get_Curres(stmt), 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); +QR_set_field_info(SC_get_Curres(stmt), 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); +QR_set_field_info(SC_get_Curres(stmt), 4, "DATA_TYPE", PG_TYPE_INT2, 2); +QR_set_field_info(SC_get_Curres(stmt), 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); +QR_set_field_info(SC_get_Curres(stmt), 6, "PRECISION", PG_TYPE_INT4, 4); +QR_set_field_info(SC_get_Curres(stmt), 7, "LENGTH", PG_TYPE_INT4, 4); +QR_set_field_info(SC_get_Curres(stmt), 8, "SCALE", PG_TYPE_INT2, 2); +QR_set_field_info(SC_get_Curres(stmt), 9, "RADIX", PG_TYPE_INT2, 2); +QR_set_field_info(SC_get_Curres(stmt), 10, "NULLABLE", PG_TYPE_INT2, 2); +QR_set_field_info(SC_get_Curres(stmt), 11, "REMARKS", PG_TYPE_TEXT, 254); /* User defined fields */ -QR_set_field_info(stmt->result, 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4); -QR_set_field_info(stmt->result, 13, "FIELD_TYPE", PG_TYPE_INT4, 4); +QR_set_field_info(SC_get_Curres(stmt), 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4); +QR_set_field_info(SC_get_Curres(stmt), 13, "FIELD_TYPE", PG_TYPE_INT4, 4); #endif void @@ -312,9 +329,10 @@ parse_statement(StatementClass *stmt) stmt->ntab = 0; #ifdef MULTIBYTE - multibyte_init(); -#endif + while (pptr = ptr, (ptr = getNextToken(conn->ccsc, pptr, token, sizeof(token), &delim, "e, &dquote, &numeric)) != NULL) +#else while (pptr = ptr, (ptr = getNextToken(pptr, token, sizeof(token), &delim, "e, &dquote, &numeric)) != NULL) +#endif { unquoted = !(quote || dquote); @@ -607,12 +625,17 @@ parse_statement(StatementClass *stmt) if (!dquote) { char *ptr; +#ifdef MULTIBYTE + encoded_str encstr; + make_encoded_str(&encstr, conn, ti[stmt->ntab]->name); +#endif /* MULTIBYTE */ /* lower case table name */ for (ptr = ti[stmt->ntab]->name; *ptr; ptr++) { #ifdef MULTIBYTE - if ((unsigned char) *ptr >= 0x80) + encoded_nextchar(&encstr); + if (ENCODE_STATUS(encstr) != 0) ptr++; else #endif /* MULTIBYTE */ @@ -773,13 +796,13 @@ parse_statement(StatementClass *stmt) * structure */ strcpy(conn->col_info[conn->ntables]->name, ti[i]->name); - conn->col_info[conn->ntables]->result = col_stmt->result; + conn->col_info[conn->ntables]->result = SC_get_Curres(col_stmt); /* * The connection will now free the result structures, so * make sure that the statement doesn't free it */ - col_stmt->result = NULL; + SC_set_Result(col_stmt, NULL); conn->ntables++; diff --git a/src/interfaces/odbc/pgapi30.c b/src/interfaces/odbc/pgapi30.c index 9ee8c58983b..6e4c575e31e 100644 --- a/src/interfaces/odbc/pgapi30.c +++ b/src/interfaces/odbc/pgapi30.c @@ -36,37 +36,92 @@ PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, RETCODE ret; static const char *func = "PGAPI_GetDiagRec"; - mylog("%s entering ", func); + mylog("%s entering rec=%d", func, RecNumber); switch (HandleType) { case SQL_HANDLE_ENV: - ret = PGAPI_Error(Handle, NULL, NULL, Sqlstate, NativeError, - MessageText, BufferLength, TextLength); + ret = PGAPI_EnvError(Handle, RecNumber, Sqlstate, + NativeError, MessageText, + BufferLength, TextLength, 0); break; case SQL_HANDLE_DBC: - ret = PGAPI_Error(NULL, Handle, NULL, Sqlstate, NativeError, - MessageText, BufferLength, TextLength); + ret = PGAPI_ConnectError(Handle, RecNumber, Sqlstate, + NativeError, MessageText, BufferLength, + TextLength, 0); break; case SQL_HANDLE_STMT: - ret = PGAPI_Error(NULL, NULL, Handle, Sqlstate, NativeError, - MessageText, BufferLength, TextLength); + ret = PGAPI_StmtError(Handle, RecNumber, Sqlstate, + NativeError, MessageText, BufferLength, + TextLength, 0); break; default: ret = SQL_ERROR; } - if (ret == SQL_SUCCESS_WITH_INFO && - BufferLength == 0 && - *TextLength) - { - SQLSMALLINT BufferLength = *TextLength + 4; - SQLCHAR *MessageText = malloc(BufferLength); + mylog("%s exiting %d\n", func, ret); + return ret; +} + +RETCODE SQL_API +PGAPI_GetDiagField(SQLSMALLINT HandleType, SQLHANDLE Handle, + SQLSMALLINT RecNumber, SQLSMALLINT DiagIdentifier, + PTR DiagInfoPtr, SQLSMALLINT BufferLength, + SQLSMALLINT *StringLengthPtr) +{ + RETCODE ret = SQL_SUCCESS; + static const char *func = "PGAPI_GetDiagField"; - ret = PGAPI_GetDiagRec(HandleType, Handle, RecNumber, Sqlstate, - NativeError, MessageText, BufferLength, - TextLength); - free(MessageText); + mylog("%s entering rec=%d", func, RecNumber); + switch (HandleType) + { + case SQL_HANDLE_ENV: + switch (DiagIdentifier) + { + case SQL_DIAG_CLASS_ORIGIN: + case SQL_DIAG_SUBCLASS_ORIGIN: + case SQL_DIAG_CONNECTION_NAME: + case SQL_DIAG_MESSAGE_TEXT: + case SQL_DIAG_NATIVE: + case SQL_DIAG_NUMBER: + case SQL_DIAG_RETURNCODE: + case SQL_DIAG_SERVER_NAME: + case SQL_DIAG_SQLSTATE: + break; + } + break; + case SQL_HANDLE_DBC: + switch (DiagIdentifier) + { + case SQL_DIAG_CLASS_ORIGIN: + case SQL_DIAG_SUBCLASS_ORIGIN: + case SQL_DIAG_CONNECTION_NAME: + case SQL_DIAG_MESSAGE_TEXT: + case SQL_DIAG_NATIVE: + case SQL_DIAG_NUMBER: + case SQL_DIAG_RETURNCODE: + case SQL_DIAG_SERVER_NAME: + case SQL_DIAG_SQLSTATE: + break; + } + break; + case SQL_HANDLE_STMT: + switch (DiagIdentifier) + { + case SQL_DIAG_CLASS_ORIGIN: + case SQL_DIAG_SUBCLASS_ORIGIN: + case SQL_DIAG_CONNECTION_NAME: + case SQL_DIAG_MESSAGE_TEXT: + case SQL_DIAG_NATIVE: + case SQL_DIAG_NUMBER: + case SQL_DIAG_RETURNCODE: + case SQL_DIAG_SERVER_NAME: + case SQL_DIAG_SQLSTATE: + break; + } + break; + default: + ret = SQL_ERROR; } -mylog("%s exiting\n", func); + mylog("%s exiting %d\n", func, ret); return ret; } @@ -87,7 +142,7 @@ PGAPI_GetConnectAttr(HDBC ConnectionHandle, case SQL_ATTR_CONNECTION_TIMEOUT: case SQL_ATTR_METADATA_ID: conn->errornumber = STMT_INVALID_OPTION_IDENTIFIER; - conn->errormsg = "Unsupported connection option (Set)"; + conn->errormsg = "Unsupported connect attribute (Get)"; return SQL_ERROR; } return PGAPI_GetConnectOption(ConnectionHandle, (UWORD) Attribute, Value); @@ -373,7 +428,7 @@ PGAPI_SetConnectAttr(HDBC ConnectionHandle, case SQL_ATTR_CONNECTION_TIMEOUT: case SQL_ATTR_METADATA_ID: conn->errornumber = STMT_INVALID_OPTION_IDENTIFIER; - conn->errormsg = "Unsupported connection option (Set)"; + conn->errormsg = "Unsupported connect attribute (Set)"; return SQL_ERROR; } return PGAPI_SetConnectOption(ConnectionHandle, (UWORD) Attribute, (UDWORD) Value); diff --git a/src/interfaces/odbc/pgapifunc.h b/src/interfaces/odbc/pgapifunc.h index 3117a6dc379..f7a72a28e43 100644 --- a/src/interfaces/odbc/pgapifunc.h +++ b/src/interfaces/odbc/pgapifunc.h @@ -11,6 +11,8 @@ #include <string.h> #define PODBC_NOT_SEARCH_PATTERN 1L +#define PODBC_ALLOW_PARTIAL_EXTRACT 1L +#define PODBC_ERROR_CLEAR (1L << 1) RETCODE SQL_API PGAPI_AllocConnect(HENV EnvironmentHandle, HDBC FAR * ConnectionHandle); @@ -56,6 +58,20 @@ RETCODE SQL_API PGAPI_Error(HENV EnvironmentHandle, SQLCHAR *Sqlstate, SQLINTEGER *NativeError, SQLCHAR *MessageText, SQLSMALLINT BufferLength, SQLSMALLINT *TextLength); +/* Helper functions for Error handling */ +RETCODE SQL_API PGAPI_EnvError(HENV EnvironmentHandle, SWORD RecNumber, + SQLCHAR *Sqlstate, SQLINTEGER *NativeError, + SQLCHAR *MessageText, SQLSMALLINT BufferLength, + SQLSMALLINT *TextLength, UWORD flag); +RETCODE SQL_API PGAPI_ConnectError(HDBC ConnectionHandle, SWORD RecNumber, + SQLCHAR *Sqlstate, SQLINTEGER *NativeError, + SQLCHAR *MessageText, SQLSMALLINT BufferLength, + SQLSMALLINT *TextLength, UWORD flag); +RETCODE SQL_API PGAPI_StmtError(HSTMT StatementHandle, SWORD RecNumber, + SQLCHAR *Sqlstate, SQLINTEGER *NativeError, + SQLCHAR *MessageText, SQLSMALLINT BufferLength, + SQLSMALLINT *TextLength, UWORD flag); + RETCODE SQL_API PGAPI_ExecDirect(HSTMT StatementHandle, SQLCHAR *StatementText, SQLINTEGER TextLength); RETCODE SQL_API PGAPI_Execute(HSTMT StatementHandle); @@ -225,7 +241,8 @@ RETCODE SQL_API PGAPI_TablePrivileges( SQLCHAR *szSchemaName, SQLSMALLINT cbSchemaName, SQLCHAR *szTableName, - SQLSMALLINT cbTableName); + SQLSMALLINT cbTableName, + UWORD flag); RETCODE SQL_API PGAPI_BindParameter( HSTMT hstmt, SQLUSMALLINT ipar, @@ -243,4 +260,25 @@ RETCODE SQL_API PGAPI_SetScrollOptions( SDWORD crowKeyset, UWORD crowRowset); +#if (ODBCVER >= 0x0300) +RETCODE SQL_API PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle, + SQLSMALLINT RecNumber, SQLCHAR *Sqlstate, + SQLINTEGER *NativeError, SQLCHAR *MessageText, + SQLSMALLINT BufferLength, SQLSMALLINT *TextLength); +RETCODE SQL_API PGAPI_GetConnectAttr(HDBC ConnectionHandle, + SQLINTEGER Attribute, PTR Value, + SQLINTEGER BufferLength, SQLINTEGER *StringLength); +RETCODE SQL_API PGAPI_GetStmtAttr(HSTMT StatementHandle, + SQLINTEGER Attribute, PTR Value, + SQLINTEGER BufferLength, SQLINTEGER *StringLength); +RETCODE SQL_API PGAPI_SetConnectAttr(HDBC ConnectionHandle, + SQLINTEGER Attribute, PTR Value, + SQLINTEGER StringLength); +RETCODE SQL_API PGAPI_SetStmtAttr(HSTMT StatementHandle, + SQLINTEGER Attribute, PTR Value, + SQLINTEGER StringLength); +RETCODE SQL_API PGAPI_SetDescField(SQLHDESC DescriptorHandle, + SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, + PTR Value, SQLINTEGER BufferLength); +#endif /* ODBCVER */ #endif /* define_PG_API_FUNC_H__ */ diff --git a/src/interfaces/odbc/pgtypes.c b/src/interfaces/odbc/pgtypes.c index be822a2eb4d..8cade89b73f 100644 --- a/src/interfaces/odbc/pgtypes.c +++ b/src/interfaces/odbc/pgtypes.c @@ -21,6 +21,7 @@ #include "dlg_specific.h" #include "statement.h" #include "connection.h" +#include "environ.h" #include "qresult.h" @@ -90,15 +91,26 @@ Int2 sqlTypes[] = { SQL_TINYINT, SQL_VARBINARY, SQL_VARCHAR, +#ifdef UNICODE_SUPPORT + SQL_WCHAR, + SQL_WVARCHAR, + SQL_WLONGVARCHAR, +#endif /* UNICODE_SUPPORT */ 0 }; +#if (ODBCVER >= 0x0300) && defined(OBDCINT64) +#define ALLOWED_C_BIGINT SQL_C_SBIGINT +#else +#define ALLOWED_C_BIGINT SQL_C_CHAR +#endif Int4 sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType) { Int4 pgType; - ConnInfo *ci = &(SC_get_conn(stmt)->connInfo); + ConnectionClass *conn = SC_get_conn(stmt); + ConnInfo *ci = &(conn->connInfo); switch (fSqlType) { @@ -110,11 +122,20 @@ sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType) pgType = PG_TYPE_BPCHAR; break; +#ifdef UNICODE_SUPPORT + case SQL_WCHAR: + pgType = PG_TYPE_BPCHAR; + break; +#endif /* UNICODE_SUPPORT */ + case SQL_BIT: pgType = ci->drivers.bools_as_char ? PG_TYPE_CHAR : PG_TYPE_BOOL; break; case SQL_DATE: +#if (ODBCVER >= 0x0300) + case SQL_TYPE_DATE: +#endif /* ODBCVER */ pgType = PG_TYPE_DATE; break; @@ -144,6 +165,12 @@ sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType) pgType = ci->drivers.text_as_longvarchar ? PG_TYPE_TEXT : PG_TYPE_VARCHAR; break; +#ifdef UNICODE_SUPPORT + case SQL_WLONGVARCHAR: + pgType = ci->drivers.text_as_longvarchar ? PG_TYPE_TEXT : PG_TYPE_VARCHAR; + break; +#endif /* UNICODE_SUPPORT */ + case SQL_REAL: pgType = PG_TYPE_FLOAT4; break; @@ -154,10 +181,16 @@ sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType) break; case SQL_TIME: +#if (ODBCVER >= 0x0300) + case SQL_TYPE_TIME: +#endif /* ODBCVER */ pgType = PG_TYPE_TIME; break; case SQL_TIMESTAMP: +#if (ODBCVER >= 0x0300) + case SQL_TYPE_TIMESTAMP: +#endif /* ODBCVER */ pgType = PG_TYPE_DATETIME; break; @@ -169,6 +202,12 @@ sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType) pgType = PG_TYPE_VARCHAR; break; +#if UNICODE_SUPPORT + case SQL_WVARCHAR: + pgType = PG_TYPE_VARCHAR; + break; +#endif /* UNICODE_SUPPORT */ + default: pgType = 0; /* ??? */ break; @@ -193,7 +232,9 @@ sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType) Int2 pgtype_to_sqltype(StatementClass *stmt, Int4 type) { - ConnInfo *ci = &(SC_get_conn(stmt)->connInfo); + ConnectionClass *conn = SC_get_conn(stmt); + ConnInfo *ci = &(conn->connInfo); + EnvironmentClass *env = (EnvironmentClass *) (conn->henv); switch (type) { @@ -204,6 +245,19 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type) case PG_TYPE_NAME: return SQL_CHAR; +#ifdef UNICODE_SUPPORT + case PG_TYPE_BPCHAR: + return conn->unicode ? SQL_WCHAR : SQL_CHAR; + + case PG_TYPE_VARCHAR: + return conn->unicode ? SQL_WVARCHAR : SQL_VARCHAR; + + case PG_TYPE_TEXT: + return ci->drivers.text_as_longvarchar ? + (conn->unicode ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR) : + (conn->unicode ? SQL_WVARCHAR : SQL_VARCHAR); + +#else case PG_TYPE_BPCHAR: return SQL_CHAR; @@ -212,6 +266,7 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type) case PG_TYPE_TEXT: return ci->drivers.text_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR; +#endif /* UNICODE_SUPPORT */ case PG_TYPE_BYTEA: return SQL_VARBINARY; @@ -229,10 +284,10 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type) /* Change this to SQL_BIGINT for ODBC v3 bjm 2001-01-23 */ case PG_TYPE_INT8: #if (ODBCVER >= 0x0300) - return SQL_BIGINT; -#else - return SQL_CHAR; + if (!conn->ms_jet) + return SQL_BIGINT; #endif /* ODBCVER */ + return SQL_CHAR; case PG_TYPE_NUMERIC: return SQL_NUMERIC; @@ -242,12 +297,24 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type) case PG_TYPE_FLOAT8: return SQL_FLOAT; case PG_TYPE_DATE: +#if (ODBCVER >= 0x0300) + if (EN_is_odbc3(env)) + return SQL_TYPE_DATE; +#endif /* ODBCVER */ return SQL_DATE; case PG_TYPE_TIME: +#if (ODBCVER >= 0x0300) + if (EN_is_odbc3(env)) + return SQL_TYPE_TIME; +#endif /* ODBCVER */ return SQL_TIME; case PG_TYPE_ABSTIME: case PG_TYPE_DATETIME: case PG_TYPE_TIMESTAMP: +#if (ODBCVER >= 0x0300) + if (EN_is_odbc3(env)) + return SQL_TYPE_TIMESTAMP; +#endif /* ODBCVER */ return SQL_TIMESTAMP; case PG_TYPE_MONEY: return SQL_FLOAT; @@ -273,16 +340,18 @@ pgtype_to_sqltype(StatementClass *stmt, Int4 type) Int2 pgtype_to_ctype(StatementClass *stmt, Int4 type) { - ConnInfo *ci = &(SC_get_conn(stmt)->connInfo); + ConnectionClass *conn = SC_get_conn(stmt); + ConnInfo *ci = &(conn->connInfo); + EnvironmentClass *env = (EnvironmentClass *) (conn->henv); switch (type) { case PG_TYPE_INT8: #if (ODBCVER >= 0x0300) - return SQL_C_SBIGINT; -#else + if (!conn->ms_jet) + return ALLOWED_C_BIGINT; +#endif /* ODBCVER */ return SQL_C_CHAR; -#endif case PG_TYPE_NUMERIC: return SQL_C_CHAR; case PG_TYPE_INT2: @@ -297,24 +366,24 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type) return SQL_C_DOUBLE; case PG_TYPE_DATE: #if (ODBCVER >= 0x0300) - return SQL_C_TYPE_DATE; -#else - return SQL_C_DATE; + if (EN_is_odbc3(env)) + return SQL_C_TYPE_DATE; #endif /* ODBCVER */ + return SQL_C_DATE; case PG_TYPE_TIME: #if (ODBCVER >= 0x0300) - return SQL_C_TYPE_TIME; -#else - return SQL_C_TIME; + if (EN_is_odbc3(env)) + return SQL_C_TYPE_TIME; #endif /* ODBCVER */ + return SQL_C_TIME; case PG_TYPE_ABSTIME: case PG_TYPE_DATETIME: case PG_TYPE_TIMESTAMP: #if (ODBCVER >= 0x0300) - return SQL_C_TYPE_TIMESTAMP; -#else - return SQL_C_TIMESTAMP; + if (EN_is_odbc3(env)) + return SQL_C_TYPE_TIMESTAMP; #endif /* ODBCVER */ + return SQL_C_TIMESTAMP; case PG_TYPE_MONEY: return SQL_C_FLOAT; case PG_TYPE_BOOL: @@ -324,6 +393,12 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type) return SQL_C_BINARY; case PG_TYPE_LO: return SQL_C_BINARY; +#ifdef UNICODE_SUPPORT + case PG_TYPE_BPCHAR: + case PG_TYPE_VARCHAR: + case PG_TYPE_TEXT: + return conn->unicode ? SQL_C_WCHAR : SQL_C_CHAR; +#endif /* UNICODE_SUPPORT */ default: /* hack until permanent type is available */ @@ -416,7 +491,7 @@ getNumericScale(StatementClass *stmt, Int4 type, int col) if (col < 0) return PG_NUMERIC_MAX_SCALE; - result = SC_get_Result(stmt); + result = SC_get_Curres(stmt); /* * Manual Result Sets -- use assigned column width (i.e., from @@ -457,7 +532,7 @@ getNumericPrecision(StatementClass *stmt, Int4 type, int col) if (col < 0) return PG_NUMERIC_MAX_PRECISION; - result = SC_get_Result(stmt); + result = SC_get_Curres(stmt); /* * Manual Result Sets -- use assigned column width (i.e., from @@ -520,10 +595,6 @@ getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si break; } - /* - * Static Precision (i.e., the Maximum Precision of the datatype) This - * has nothing to do with a result set. - */ if (maxsize == TEXT_FIELD_SIZE + 1) /* magic length for testing */ { if (PG_VERSION_GE(SC_get_conn(stmt), 7.1)) @@ -531,10 +602,14 @@ getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si else maxsize = TEXT_FIELD_SIZE; } + /* + * Static Precision (i.e., the Maximum Precision of the datatype) This + * has nothing to do with a result set. + */ if (col < 0) return maxsize; - result = SC_get_Result(stmt); + result = SC_get_Curres(stmt); /* * Manual Result Sets -- use assigned column width (i.e., from @@ -553,16 +628,20 @@ getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si if (QR_get_atttypmod(result, col) > -1) return QR_get_atttypmod(result, col); + /* The type is really unknown */ if (type == PG_TYPE_BPCHAR || handle_unknown_size_as == UNKNOWNS_AS_LONGEST) { p = QR_get_display_size(result, col); mylog("getCharPrecision: LONGEST: p = %d\n", p); + if (p >= 0) + return p; } - if (p < 0 && handle_unknown_size_as == UNKNOWNS_AS_MAX) + if (handle_unknown_size_as == UNKNOWNS_AS_MAX) return maxsize; - else - return p; + else /* handle_unknown_size_as == DONT_KNOW */ + return -1; + } static Int2 @@ -580,7 +659,7 @@ getTimestampScale(StatementClass *stmt, Int4 type, int col) if (PG_VERSION_LT(conn, 7.2)) return 0; - result = SC_get_Result(stmt); + result = SC_get_Curres(stmt); /* * Manual Result Sets -- use assigned column width (i.e., from @@ -615,10 +694,7 @@ getTimestampPrecision(StatementClass *stmt, Int4 type, int col) fixed = 8; break; case PG_TYPE_TIME_WITH_TMZONE: - if (USE_ZONE) - fixed = 11; - else - fixed = 8; + fixed = 11; break; case PG_TYPE_TIMESTAMP_NO_TMZONE: fixed = 19; @@ -692,7 +768,10 @@ pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si return getTimestampPrecision(stmt, type, col); case PG_TYPE_BOOL: - return 1; + { + BOOL true_is_minus1 = FALSE; + return true_is_minus1 ? 2 : 1; + } case PG_TYPE_LO: return SQL_NO_TOTAL; @@ -756,6 +835,8 @@ pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown Int4 pgtype_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as) { + ConnectionClass *conn = SC_get_conn(stmt); + switch (type) { case PG_TYPE_INT2: @@ -791,15 +872,27 @@ pgtype_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_ /* Character types (and NUMERIC) use the default precision */ case PG_TYPE_VARCHAR: case PG_TYPE_BPCHAR: + { + int coef = 1; + Int4 prec = pgtype_precision(stmt, type, col, handle_unknown_size_as), maxvarc; + if (conn->unicode) + return (prec + 1) * 2; #ifdef MULTIBYTE /* after 7.2 */ - if (PG_VERSION_GE(SC_get_conn(stmt), 7.2)) - return 3 * pgtype_precision(stmt, type, col, handle_unknown_size_as); + if (PG_VERSION_GE(conn, 7.2)) + coef = 3; else -#else - /* CR -> CR/LF */ - return 2 * pgtype_precision(stmt, type, col, handle_unknown_size_as); #endif /* MULTIBYTE */ + if ((conn->connInfo).lf_conversion) + /* CR -> CR/LF */ + coef = 2; + if (coef == 1) + return prec + 1; + maxvarc = conn->connInfo.drivers.max_varchar_size; + if (prec <= maxvarc && prec * coef > maxvarc) + return maxvarc; + return coef * prec; + } default: return pgtype_precision(stmt, type, col, handle_unknown_size_as); } @@ -885,8 +978,8 @@ pgtype_auto_increment(StatementClass *stmt, Int4 type) case PG_TYPE_NUMERIC: case PG_TYPE_DATE: - case PG_TYPE_TIME: case PG_TYPE_TIME_WITH_TMZONE: + case PG_TYPE_TIME: case PG_TYPE_ABSTIME: case PG_TYPE_DATETIME: case PG_TYPE_TIMESTAMP: @@ -1058,9 +1151,16 @@ sqltype_to_default_ctype(Int2 sqltype) #else return SQL_C_CHAR; case SQL_BIGINT: - return SQL_C_SBIGINT; + return ALLOWED_C_BIGINT; #endif +#ifdef UNICODE_SUPPORT + case SQL_WCHAR: + case SQL_WVARCHAR: + case SQL_WLONGVARCHAR: + return SQL_C_WCHAR; +#endif /* UNICODE_SUPPORT */ + case SQL_BIT: return SQL_C_BIT; @@ -1086,24 +1186,23 @@ sqltype_to_default_ctype(Int2 sqltype) return SQL_C_BINARY; case SQL_DATE: -#if (ODBCVER >= 0x0300) - return SQL_C_TYPE_DATE; -#else return SQL_C_DATE; -#endif /* ODBCVER */ case SQL_TIME: -#if (ODBCVER >= 0x0300) - return SQL_C_TYPE_TIME; -#else return SQL_C_TIME; -#endif /* ODBCVER */ case SQL_TIMESTAMP: + return SQL_C_TIMESTAMP; + #if (ODBCVER >= 0x0300) + case SQL_TYPE_DATE: + return SQL_C_TYPE_DATE; + + case SQL_TYPE_TIME: + return SQL_C_TYPE_TIME; + + case SQL_TYPE_TIMESTAMP: return SQL_C_TYPE_TIMESTAMP; -#else - return SQL_C_TIMESTAMP; #endif /* ODBCVER */ default: @@ -1167,6 +1266,7 @@ ctype_length(Int2 ctype) case SQL_C_BINARY: case SQL_C_CHAR: + case SQL_C_WCHAR: return 0; default: /* should never happen */ diff --git a/src/interfaces/odbc/psqlodbc.h b/src/interfaces/odbc/psqlodbc.h index fc246b8b77e..534678e2802 100644 --- a/src/interfaces/odbc/psqlodbc.h +++ b/src/interfaces/odbc/psqlodbc.h @@ -5,7 +5,7 @@ * * Comments: See "notice.txt" for copyright and license information. * - * $Id: psqlodbc.h,v 1.57 2002/02/18 03:16:11 inoue Exp $ + * $Id: psqlodbc.h,v 1.58 2002/03/08 08:52:53 inoue Exp $ * */ @@ -87,7 +87,7 @@ typedef UInt4 Oid; #define DBMS_NAME "PostgreSQL" #endif /* ODBCVER */ -#define POSTGRESDRIVERVERSION "07.01.0010" +#define POSTGRESDRIVERVERSION "07.01.0011" #ifdef WIN32 #if (ODBCVER >= 0x0300) @@ -254,6 +254,11 @@ void logs_on_off(int cnopen, int, int); #include "misc.h" +#ifdef UNICODE_SUPPORT +UInt4 ucs2strlen(const SQLWCHAR *ucs2str); +char *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen); +UInt4 utf8_to_ucs2(const char * utf8str, Int4 ilen, SQLWCHAR *ucs2str, UInt4 buflen); +#endif /* UNICODE_SUPPORT */ #ifdef _MEMORY_DEBUG_ void *debug_alloc(size_t); void *debug_realloc(void *, size_t); diff --git a/src/interfaces/odbc/psqlodbc.rc b/src/interfaces/odbc/psqlodbc.rc index 5b7b53583eb..698bd6c74fe 100644 --- a/src/interfaces/odbc/psqlodbc.rc +++ b/src/interfaces/odbc/psqlodbc.rc @@ -138,7 +138,7 @@ BEGIN BS_NOTIFY | WS_TABSTOP,247,205,40,10 END -DLG_OPTIONS_DS DIALOG DISCARDABLE 0, 0, 267, 161 +DLG_OPTIONS_DS DIALOG DISCARDABLE 0, 0, 267, 176 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Advanced Options (DataSource)" FONT 10, "Terminal" @@ -151,23 +151,27 @@ BEGIN BS_AUTOCHECKBOX | WS_TABSTOP,45,28,88,10 CONTROL "Disallow &Premature",DS_DISALLOWPREMATURE,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,149,28,86,10 - GROUPBOX "Protocol",IDC_STATIC,43,44,180,25 + CONTROL "LF <-> CR/LF convert",DS_LFCONVERSION,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,45,43,92,10 + CONTROL "True is -1",DS_TRUEISMINUS1,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,149,43,86,10 + GROUPBOX "Protocol",IDC_STATIC,43,59,180,25 CONTROL "7.X,6.4+",DS_PG64,"Button",BS_AUTORADIOBUTTON | - WS_GROUP,53,54,47,10 + WS_GROUP,53,69,47,10 CONTROL "6.3",DS_PG63,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP, - 131,54,26,10 + 131,69,26,10 CONTROL "6.2",DS_PG62,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP, - 187,54,26,10 - GROUPBOX "OID Options",IDC_STATIC,43,74,180,25 + 187,69,26,10 + GROUPBOX "OID Options",IDC_STATIC,43,89,180,25 CONTROL "Show &Column",DS_SHOWOIDCOLUMN,"Button",BS_AUTOCHECKBOX | - WS_GROUP | WS_TABSTOP,53,85,59,10 + WS_GROUP | WS_TABSTOP,53,100,59,10 CONTROL "Fake &Index",DS_FAKEOIDINDEX,"Button",BS_AUTOCHECKBOX | - WS_GROUP | WS_TABSTOP,161,85,55,10 - LTEXT "Connect &Settings:",IDC_STATIC,10,105,35,25 - EDITTEXT DS_CONNSETTINGS,50,105,200,20,ES_MULTILINE | + WS_GROUP | WS_TABSTOP,161,100,55,10 + LTEXT "Connect &Settings:",IDC_STATIC,10,120,35,25 + EDITTEXT DS_CONNSETTINGS,50,120,200,20,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN - DEFPUSHBUTTON "OK",IDOK,71,135,50,14,WS_GROUP - PUSHBUTTON "Cancel",IDCANCEL,146,135,50,14 + DEFPUSHBUTTON "OK",IDOK,71,150,50,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,146,150,50,14 END #else DLG_CONFIG DIALOG DISCARDABLE 65, 43, 292, 116 @@ -255,7 +259,7 @@ BEGIN BS_NOTIFY | WS_TABSTOP,233,224,40,10 END -DLG_OPTIONS_DS DIALOG DISCARDABLE 0, 0, 267, 161 +DLG_OPTIONS_DS DIALOG DISCARDABLE 0, 0, 267, 176 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Advanced Options (DataSource)" FONT 8, "MS Sans Serif" @@ -268,23 +272,27 @@ BEGIN BS_AUTOCHECKBOX | WS_TABSTOP,25,25,85,10 CONTROL "Disallow &Premature",DS_DISALLOWPREMATURE,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,130,25,85,10 - GROUPBOX "Protocol",IDC_STATIC,15,40,180,25 + CONTROL "LF <-> CR/LF convert",DS_LFCONVERSION,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,45,40,92,10 + CONTROL "True is -1",DS_TRUEISMINUS1,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,149,40,86,10 + GROUPBOX "Protocol",IDC_STATIC,15,55,180,25 CONTROL "7.X,6.4+",DS_PG64,"Button",BS_AUTORADIOBUTTON | WS_GROUP,25, - 50,35,10 + 65,35,10 CONTROL "6.3",DS_PG63,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP, - 75,50,26,10 + 75,65,26,10 CONTROL "6.2",DS_PG62,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP, - 130,50,26,10 - GROUPBOX "OID Options",IDC_STATIC,15,70,180,25 + 130,65,26,10 + GROUPBOX "OID Options",IDC_STATIC,15,86,180,25 CONTROL "Show &Column",DS_SHOWOIDCOLUMN,"Button",BS_AUTOCHECKBOX | - WS_GROUP | WS_TABSTOP,25,81,59,10 + WS_GROUP | WS_TABSTOP,25,96,59,10 CONTROL "Fake &Index",DS_FAKEOIDINDEX,"Button",BS_AUTOCHECKBOX | - WS_GROUP | WS_TABSTOP,115,81,51,10 - RTEXT "Connect &Settings:",IDC_STATIC,10,105,35,25 - EDITTEXT DS_CONNSETTINGS,50,105,200,20,ES_MULTILINE | + WS_GROUP | WS_TABSTOP,115,96,51,10 + RTEXT "Connect &Settings:",IDC_STATIC,10,120,35,25 + EDITTEXT DS_CONNSETTINGS,50,120,200,20,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN - DEFPUSHBUTTON "OK",IDOK,71,135,50,14,WS_GROUP - PUSHBUTTON "Cancel",IDCANCEL,146,135,50,14 + DEFPUSHBUTTON "OK",IDOK,71,150,50,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,146,150,50,14 END #endif @@ -354,8 +362,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 7,1,0,10 - PRODUCTVERSION 7,1,0,10 + FILEVERSION 7,1,0,11 + PRODUCTVERSION 7,1,0,11 FILEFLAGSMASK 0x3L #ifdef _DEBUG FILEFLAGS 0x1L @@ -377,14 +385,14 @@ BEGIN VALUE "CompanyName", "Insight Distribution Systems\0" #endif VALUE "FileDescription", "PostgreSQL Driver\0" - VALUE "FileVersion", " 07.01.0010\0" + VALUE "FileVersion", " 07.01.0011\0" VALUE "InternalName", "psqlodbc\0" VALUE "LegalCopyright", "\0" VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation. Microsoft® is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0" VALUE "OriginalFilename", "psqlodbc.dll\0" VALUE "PrivateBuild", "\0" VALUE "ProductName", "Microsoft Open Database Connectivity\0" - VALUE "ProductVersion", " 07.01.0010\0" + VALUE "ProductVersion", " 07.01.0011\0" VALUE "SpecialBuild", "\0" END END diff --git a/src/interfaces/odbc/psqlodbc_api30w.def b/src/interfaces/odbc/psqlodbc_api30w.def new file mode 100644 index 00000000000..71ea830cb43 --- /dev/null +++ b/src/interfaces/odbc/psqlodbc_api30w.def @@ -0,0 +1,106 @@ +LIBRARY psqlodbc30 +EXPORTS +SQLAllocConnect @1 +SQLAllocEnv @2 +SQLAllocStmt @3 +SQLBindCol @4 +SQLCancel @5 +SQLColAttributes @6 +SQLConnect @7 +SQLDescribeCol @8 +SQLDisconnect @9 +SQLError @10 +SQLExecDirect @11 +SQLExecute @12 +SQLFetch @13 +SQLFreeConnect @14 +SQLFreeEnv @15 +SQLFreeStmt @16 +SQLGetCursorName @17 +SQLNumResultCols @18 +SQLPrepare @19 +SQLRowCount @20 +SQLSetCursorName @21 +SQLTransact @23 +SQLColumns @40 +SQLDriverConnect @41 +SQLGetData @43 +SQLGetFunctions @44 +SQLGetInfo @45 +SQLGetStmtOption @46 +SQLGetTypeInfo @47 +SQLParamData @48 +SQLPutData @49 +SQLSpecialColumns @52 +SQLStatistics @53 +SQLTables @54 +SQLBrowseConnect @55 +SQLColumnPrivileges @56 +SQLDescribeParam @58 +SQLExtendedFetch @59 +SQLForeignKeys @60 +SQLMoreResults @61 +SQLNativeSql @62 +SQLNumParams @63 +SQLParamOptions @64 +SQLPrimaryKeys @65 +SQLProcedureColumns @66 +SQLProcedures @67 +SQLSetPos @68 +SQLSetScrollOptions @69 +SQLTablePrivileges @70 +SQLBindParameter @72 + +SQLAllocHandle @80 +SQLBindParam @81 +SQLCloseCursor @82 +SQLColAttribute @83 +SQLCopyDesc @84 +SQLEndTran @85 +SQLFetchScroll @86 +SQLFreeHandle @87 +SQLGetDescField @88 +SQLGetDescRec @89 +SQLGetDiagField @90 +SQLGetDiagRec @91 +SQLGetEnvAttr @92 +SQLGetConnectAttr @93 +SQLGetStmtAttr @94 +SQLSetConnectAttr @95 +SQLSetDescField @96 +SQLSetDescRec @97 +SQLSetEnvAttr @98 +SQLSetStmtAttr @99 + +SQLDummyOrdinal @199 +dconn_FDriverConnectProc @200 +DllMain @201 +ConfigDSN @202 + +SQLColAttributeW @101 +SQLColumnPrivilegesW @102 +SQLColumnsW @103 +SQLConnectW @104 +SQLDescribeColW @106 +SQLExecDirectW @107 +SQLForeignKeysW @108 +SQLGetConnectAttrW @109 +SQLGetCursorNameW @110 +SQLGetInfoW @111 +SQLNativeSqlW @112 +SQLPrepareW @113 +SQLPrimaryKeysW @114 +SQLProcedureColumnsW @115 +SQLProceduresW @116 +SQLSetConnectAttrW @117 +SQLSetCursorNameW @118 +SQLSpecialColumnsW @119 +SQLStatisticsW @120 +SQLTablesW @121 +SQLTablePrivilegesW @122 +SQLDriverConnectW @123 +SQLGetDiagRecW @124 +SQLGetStmtAttrW @125 +SQLSetStmtAttrW @126 +SQLSetDescFieldW @127 +SQLGetTypeInfoW @128 diff --git a/src/interfaces/odbc/psqlodbc_apiw.def b/src/interfaces/odbc/psqlodbc_apiw.def new file mode 100644 index 00000000000..c719a20e3b5 --- /dev/null +++ b/src/interfaces/odbc/psqlodbc_apiw.def @@ -0,0 +1,84 @@ +LIBRARY psqlodbc +EXPORTS +SQLAllocConnect @1 +SQLAllocEnv @2 +SQLAllocStmt @3 +SQLBindCol @4 +SQLCancel @5 +SQLColAttributes @6 +SQLConnect @7 +SQLDescribeCol @8 +SQLDisconnect @9 +SQLError @10 +SQLExecDirect @11 +SQLExecute @12 +SQLFetch @13 +SQLFreeConnect @14 +SQLFreeEnv @15 +SQLFreeStmt @16 +SQLGetCursorName @17 +SQLNumResultCols @18 +SQLPrepare @19 +SQLRowCount @20 +SQLSetCursorName @21 +SQLTransact @23 +SQLColumns @40 +SQLDriverConnect @41 +SQLGetConnectOption @42 +SQLGetData @43 +SQLGetFunctions @44 +SQLGetInfo @45 +SQLGetStmtOption @46 +SQLGetTypeInfo @47 +SQLParamData @48 +SQLPutData @49 +SQLSetConnectOption @50 +SQLSetStmtOption @51 +SQLSpecialColumns @52 +SQLStatistics @53 +SQLTables @54 +SQLBrowseConnect @55 +SQLColumnPrivileges @56 +SQLDescribeParam @58 +SQLExtendedFetch @59 +SQLForeignKeys @60 +SQLMoreResults @61 +SQLNativeSql @62 +SQLNumParams @63 +SQLParamOptions @64 +SQLPrimaryKeys @65 +SQLProcedureColumns @66 +SQLProcedures @67 +SQLSetPos @68 +SQLSetScrollOptions @69 +SQLTablePrivileges @70 +SQLBindParameter @72 + +SQLColAttributesW @101 +SQLColumnPrivilegesW @102 +SQLColumnsW @103 +SQLConnectW @104 +SQLDescribeColW @106 +SQLExecDirectW @107 +SQLForeignKeysW @108 +SQLGetConnectOptionW @109 +SQLGetCursorNameW @110 +SQLGetInfoW @111 +SQLNativeSqlW @112 +SQLPrepareW @113 +SQLPrimaryKeysW @114 +SQLProcedureColumnsW @115 +SQLProceduresW @116 +SQLSetConnectOptionW @117 +SQLSetCursorNameW @118 +SQLSpecialColumnsW @119 +SQLStatisticsW @120 +SQLTablesW @121 +SQLTablePrivilegesW @122 +SQLDriverConnectW @123 +SQLErrorW @124 +SQLGetTypeInfoW @128 + +dconn_FDriverConnectProc @200 +DllMain @201 +ConfigDSN @202 diff --git a/src/interfaces/odbc/qresult.c b/src/interfaces/odbc/qresult.c index 2cbe64f0b4c..2e462bf5d5b 100644 --- a/src/interfaces/odbc/qresult.c +++ b/src/interfaces/odbc/qresult.c @@ -108,6 +108,7 @@ QR_Constructor() rv->command = NULL; rv->notice = NULL; rv->conn = NULL; + rv->next = NULL; rv->inTuples = FALSE; rv->fcount = 0; rv->fetch_count = 0; @@ -160,6 +161,9 @@ QR_Destructor(QResultClass *self) /* Free notice info (this is from strdup()) */ if (self->notice) free(self->notice); + /* Destruct the result object in the chain */ + if (self->next) + QR_Destructor(self->next); free(self); @@ -247,6 +251,7 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor) if (self->cursor) free(self->cursor); + self->cursor = NULL; if (fetch_cursor) { @@ -342,7 +347,7 @@ QR_close(QResultClass *self) sprintf(buf, "close %s", self->cursor); mylog("QResult: closing cursor: '%s'\n", buf); - res = CC_send_query(self->conn, buf, NULL); + res = CC_send_query(self->conn, buf, NULL, TRUE); self->inTuples = FALSE; self->currTuple = -1; @@ -487,13 +492,11 @@ QR_next_tuple(QResultClass *self) qi.row_size = self->cache_size; qi.result_in = self; qi.cursor = NULL; - res = CC_send_query(self->conn, fetch, &qi); - if (res == NULL || QR_get_aborted(res)) + res = CC_send_query(self->conn, fetch, &qi, TRUE); + if (res == NULL) { self->status = PGRES_FATAL_ERROR; QR_set_message(self, "Error fetching next group."); - if (res) - QR_Destructor(res); return FALSE; } self->inTuples = TRUE; @@ -689,7 +692,7 @@ QR_read_tuple(QResultClass *self, char binary) */ flds = self->fields; - if (flds->display_size[field_lf] < len) + if (flds && flds->display_size && flds->display_size[field_lf] < len) flds->display_size[field_lf] = len; } diff --git a/src/interfaces/odbc/qresult.h b/src/interfaces/odbc/qresult.h index 251bc449c12..b304fd5d351 100644 --- a/src/interfaces/odbc/qresult.h +++ b/src/interfaces/odbc/qresult.h @@ -45,6 +45,7 @@ struct QResultClass_ TupleListClass *manual_tuples; /* manual result tuple list */ ConnectionClass *conn; /* the connection this result is using * (backend) */ + QResultClass *next; /* the following result class */ /* Stuff for declare/fetch tuples */ int count_allocated; /* m(re)alloced count */ diff --git a/src/interfaces/odbc/resource.h b/src/interfaces/odbc/resource.h index b8bbd4fcfc1..4cd1639887b 100644 --- a/src/interfaces/odbc/resource.h +++ b/src/interfaces/odbc/resource.h @@ -52,6 +52,8 @@ #define DRV_OR_DSN 1059
#define DRV_DEBUG 1060
#define DS_DISALLOWPREMATURE 1061
+#define DS_LFCONVERSION 1062
+#define DS_TRUEISMINUS1 1063
/* Next default values for new objects
*/ /*
*/ diff --git a/src/interfaces/odbc/results.c b/src/interfaces/odbc/results.c index 4d221cacc63..e43c0e3db45 100644 --- a/src/interfaces/odbc/results.c +++ b/src/interfaces/odbc/results.c @@ -8,7 +8,7 @@ * * API functions: SQLRowCount, SQLNumResultCols, SQLDescribeCol, * SQLColAttributes, SQLGetData, SQLFetch, SQLExtendedFetch, - * SQLMoreResults(NI), SQLSetPos, SQLSetScrollOptions(NI), + * SQLMoreResults, SQLSetPos, SQLSetScrollOptions(NI), * SQLSetCursorName, SQLGetCursorName * * Comments: See "notice.txt" for copyright and license information. @@ -45,6 +45,7 @@ PGAPI_RowCount( *ptr; ConnInfo *ci; + mylog("%s: entering...\n", func); if (!stmt) { SC_log_error(func, "", NULL); @@ -62,7 +63,7 @@ PGAPI_RowCount( { if (stmt->status == STMT_FINISHED) { - res = SC_get_Result(stmt); + res = SC_get_Curres(stmt); if (res && pcrow) { @@ -73,7 +74,7 @@ PGAPI_RowCount( } else { - res = SC_get_Result(stmt); + res = SC_get_Curres(stmt); if (res && pcrow) { msg = QR_get_command(res); @@ -115,6 +116,7 @@ PGAPI_NumResultCols( char parse_ok; ConnInfo *ci; + mylog("%s: entering...\n", func); if (!stmt) { SC_log_error(func, "", NULL); @@ -144,7 +146,7 @@ PGAPI_NumResultCols( if (!parse_ok) { SC_pre_execute(stmt); - result = SC_get_Result(stmt); + result = SC_get_Curres(stmt); mylog("PGAPI_NumResultCols: result = %u, status = %d, numcols = %d\n", result, stmt->status, result != NULL ? QR_NumResultCols(result) : -1); if ((!result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) @@ -210,6 +212,25 @@ PGAPI_DescribeCol( SC_clear_error(stmt); +#if (ODBCVER >= 0x0300) + if (0 == icol) /* bookmark column */ + { + SQLSMALLINT fType = SQL_INTEGER; + if (szColName && cbColNameMax > 0) + *szColName = '\0'; + if (pcbColName) + *pcbColName = 0; + if (pfSqlType) + *pfSqlType = fType; + if (pcbColDef) + *pcbColDef = 10; + if (pibScale) + *pibScale = 0; + if (pfNullable) + *pfNullable = SQL_NO_NULLS; + return SQL_SUCCESS; + } +#endif /* ODBCVER */ /* * Dont check for bookmark column. This is the responsibility of the * driver manager. @@ -262,7 +283,7 @@ PGAPI_DescribeCol( { SC_pre_execute(stmt); - res = SC_get_Result(stmt); + res = SC_get_Curres(stmt); mylog("**** PGAPI_DescribeCol: res = %u, stmt->status = %d, !finished=%d, !premature=%d\n", res, stmt->status, stmt->status != STMT_FINISHED, stmt->status != STMT_PREMATURE); if ((NULL == res) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) @@ -305,7 +326,7 @@ PGAPI_DescribeCol( if (pcbColName) *pcbColName = len; - if (szColName) + if (szColName && cbColNameMax > 0) { strncpy_null(szColName, col_name, cbColNameMax); @@ -379,17 +400,19 @@ PGAPI_ColAttributes( { static char *func = "PGAPI_ColAttributes"; StatementClass *stmt = (StatementClass *) hstmt; - Int4 field_type = 0; - ConnInfo *ci; + Int4 col_idx, field_type = 0; + ConnectionClass *conn; + ConnInfo *ci; int unknown_sizes; int cols = 0; char parse_ok; RETCODE result; - char *p = NULL; + const char *p = NULL; int len = 0, value = 0; + const FIELD_INFO *fi = NULL; - mylog("%s: entering...\n", func); + mylog("%s: entering..col=%d %d.\n", func, icol, fDescType); if (!stmt) { @@ -397,7 +420,8 @@ PGAPI_ColAttributes( return SQL_INVALID_HANDLE; } - ci = &(SC_get_conn(stmt)->connInfo); + conn = SC_get_conn(stmt); + ci = &(conn->connInfo); /* * Dont check for bookmark column. This is the responsibility of the @@ -405,7 +429,24 @@ PGAPI_ColAttributes( * is ignored anyway, so it may be 0. */ - icol--; +#if (ODBCVER >= 0x0300) + if (0 == icol) /* bookmark column */ + { + switch (fDescType) + { + case SQL_DESC_OCTET_LENGTH: + if (pfDesc) + *pfDesc = 4; + break; + case SQL_DESC_TYPE: + if (pfDesc) + *pfDesc = SQL_INTEGER; + break; + } + return SQL_SUCCESS; + } +#endif /* ODBCVER */ + col_idx = icol - 1; /* atoi(ci->unknown_sizes); */ unknown_sizes = ci->drivers.unknown_sizes; @@ -437,28 +478,30 @@ PGAPI_ColAttributes( return SQL_SUCCESS; } - if (stmt->parse_status != STMT_PARSE_FATAL && stmt->fi && stmt->fi[icol]) + if (stmt->parse_status != STMT_PARSE_FATAL && stmt->fi && stmt->fi[col_idx]) { - if (icol >= cols) + if (col_idx >= cols) { stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR; stmt->errormsg = "Invalid column number in ColAttributes."; SC_log_error(func, "", stmt); return SQL_ERROR; } - field_type = stmt->fi[icol]->type; + field_type = stmt->fi[col_idx]->type; if (field_type > 0) parse_ok = TRUE; } } - if (!parse_ok) + if (parse_ok) + fi = stmt->fi[col_idx]; + else { SC_pre_execute(stmt); - mylog("**** PGAPI_ColAtt: result = %u, status = %d, numcols = %d\n", stmt->result, stmt->status, stmt->result != NULL ? QR_NumResultCols(stmt->result) : -1); + mylog("**** PGAPI_ColAtt: result = %u, status = %d, numcols = %d\n", SC_get_Curres(stmt), stmt->status, SC_get_Curres(stmt) != NULL ? QR_NumResultCols(SC_get_Curres(stmt)) : -1); - if ((NULL == stmt->result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) + if ((NULL == SC_get_Curres(stmt)) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) { stmt->errormsg = "Can't get column attributes: no result found."; stmt->errornumber = STMT_SEQUENCE_ERROR; @@ -466,13 +509,17 @@ PGAPI_ColAttributes( return SQL_ERROR; } - cols = QR_NumResultCols(stmt->result); + cols = QR_NumResultCols(SC_get_Curres(stmt)); /* * Column Count is a special case. The Column number is ignored * in this case. */ +#if (ODBCVER >= 0x0300) + if (fDescType == SQL_DESC_COUNT) +#else if (fDescType == SQL_COLUMN_COUNT) +#endif /* ODBCVER */ { if (pfDesc) *pfDesc = cols; @@ -480,7 +527,7 @@ PGAPI_ColAttributes( return SQL_SUCCESS; } - if (icol >= cols) + if (col_idx >= cols) { stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR; stmt->errormsg = "Invalid column number in ColAttributes."; @@ -488,21 +535,21 @@ PGAPI_ColAttributes( return SQL_ERROR; } - field_type = QR_get_field_type(stmt->result, icol); + field_type = QR_get_field_type(SC_get_Curres(stmt), col_idx); } - mylog("colAttr: col %d field_type = %d\n", icol, field_type); + mylog("colAttr: col %d field_type = %d\n", col_idx, field_type); switch (fDescType) { - case SQL_COLUMN_AUTO_INCREMENT: + case SQL_COLUMN_AUTO_INCREMENT: /* == SQL_DESC_AUTO_UNIQUE_VALUE */ value = pgtype_auto_increment(stmt, field_type); if (value == -1) /* non-numeric becomes FALSE (ODBC Doc) */ value = FALSE; break; - case SQL_COLUMN_CASE_SENSITIVE: + case SQL_COLUMN_CASE_SENSITIVE: /* == SQL_DESC_CASE_SENSITIVE */ value = pgtype_case_sensitive(stmt, field_type); break; @@ -511,17 +558,17 @@ PGAPI_ColAttributes( * * case SQL_COLUMN_COUNT: */ - case SQL_COLUMN_DISPLAY_SIZE: - value = (parse_ok) ? stmt->fi[icol]->display_size : pgtype_display_size(stmt, field_type, icol, unknown_sizes); + case SQL_COLUMN_DISPLAY_SIZE: /* == SQL_DESC_DISPLAY_SIZE */ + value = fi ? fi->display_size : pgtype_display_size(stmt, field_type, col_idx, unknown_sizes); - mylog("PGAPI_ColAttributes: col %d, display_size= %d\n", icol, value); + mylog("PGAPI_ColAttributes: col %d, display_size= %d\n", col_idx, value); break; - case SQL_COLUMN_LABEL: - if (parse_ok && stmt->fi[icol]->alias[0] != '\0') + case SQL_COLUMN_LABEL: /* == SQL_DESC_LABEL */ + if (fi && fi->alias[0] != '\0') { - p = stmt->fi[icol]->alias; + p = fi->alias; mylog("PGAPI_ColAttr: COLUMN_LABEL = '%s'\n", p); break; @@ -529,70 +576,78 @@ PGAPI_ColAttributes( } /* otherwise same as column name -- FALL THROUGH!!! */ +#if (ODBCVER >= 0x0300) + case SQL_DESC_NAME: +#else case SQL_COLUMN_NAME: - p = (parse_ok) ? stmt->fi[icol]->name : QR_get_fieldname(stmt->result, icol); +#endif /* ODBCVER */ + p = fi ? (fi->alias[0] ? fi->alias : fi->name) : QR_get_fieldname(SC_get_Curres(stmt), col_idx); mylog("PGAPI_ColAttr: COLUMN_NAME = '%s'\n", p); break; case SQL_COLUMN_LENGTH: - value = (parse_ok) ? stmt->fi[icol]->length : pgtype_length(stmt, field_type, icol, unknown_sizes); + value = fi ? fi->length : pgtype_length(stmt, field_type, col_idx, unknown_sizes); - mylog("PGAPI_ColAttributes: col %d, length = %d\n", icol, value); + mylog("PGAPI_ColAttributes: col %d, length = %d\n", col_idx, value); break; - case SQL_COLUMN_MONEY: + case SQL_COLUMN_MONEY: /* == SQL_DESC_FIXED_PREC_SCALE */ value = pgtype_money(stmt, field_type); break; +#if (ODBCVER >= 0x0300) + case SQL_DESC_NULLABLE: +#else case SQL_COLUMN_NULLABLE: - value = (parse_ok) ? stmt->fi[icol]->nullable : pgtype_nullable(stmt, field_type); +#endif /* ODBCVER */ + value = fi ? fi->nullable : pgtype_nullable(stmt, field_type); break; - case SQL_COLUMN_OWNER_NAME: + case SQL_COLUMN_OWNER_NAME: /* == SQL_DESC_SCHEMA_NAME */ p = ""; break; case SQL_COLUMN_PRECISION: - value = (parse_ok) ? stmt->fi[icol]->precision : pgtype_precision(stmt, field_type, icol, unknown_sizes); + value = fi ? fi->precision : pgtype_precision(stmt, field_type, col_idx, unknown_sizes); - mylog("PGAPI_ColAttributes: col %d, precision = %d\n", icol, value); + mylog("PGAPI_ColAttributes: col %d, precision = %d\n", col_idx, value); break; - case SQL_COLUMN_QUALIFIER_NAME: + case SQL_COLUMN_QUALIFIER_NAME: /* == SQL_DESC_CATALOG_NAME */ p = ""; break; case SQL_COLUMN_SCALE: - value = pgtype_scale(stmt, field_type, icol); + value = pgtype_scale(stmt, field_type, col_idx); break; - case SQL_COLUMN_SEARCHABLE: + case SQL_COLUMN_SEARCHABLE: /* SQL_DESC_SEARCHABLE */ value = pgtype_searchable(stmt, field_type); break; - case SQL_COLUMN_TABLE_NAME: - p = (parse_ok && stmt->fi[icol]->ti) ? stmt->fi[icol]->ti->name : ""; + case SQL_COLUMN_TABLE_NAME: /* == SQL_DESC_TABLE_NAME */ + p = fi && (fi->ti) ? fi->ti->name : ""; mylog("PGAPI_ColAttr: TABLE_NAME = '%s'\n", p); break; - case SQL_COLUMN_TYPE: + case SQL_COLUMN_TYPE: /* == SQL_DESC_CONCISE_TYPE */ value = pgtype_to_sqltype(stmt, field_type); break; - case SQL_COLUMN_TYPE_NAME: + case SQL_COLUMN_TYPE_NAME: /* == SQL_DESC_TYPE_NAME */ p = pgtype_to_name(stmt, field_type); break; - case SQL_COLUMN_UNSIGNED: + case SQL_COLUMN_UNSIGNED: /* == SQL_DESC_UNSINGED */ value = pgtype_unsigned(stmt, field_type); if (value == -1) /* non-numeric becomes TRUE (ODBC Doc) */ value = TRUE; break; - case SQL_COLUMN_UPDATABLE: + case SQL_COLUMN_UPDATABLE: /* == SQL_DESC_UPDATABLE */ /* * Neither Access or Borland care about this. @@ -604,6 +659,60 @@ PGAPI_ColAttributes( mylog("PGAPI_ColAttr: UPDATEABLE = %d\n", value); break; +#if (ODBCVER >= 0x0300) + case SQL_DESC_BASE_COLUMN_NAME: + + p = fi ? fi->name : QR_get_fieldname(SC_get_Curres(stmt), col_idx); + + mylog("PGAPI_ColAttr: BASE_COLUMN_NAME = '%s'\n", p); + break; + case SQL_DESC_BASE_TABLE_NAME: /* the same as TABLE_NAME ok ? */ + p = fi && (fi->ti) ? fi->ti->name : ""; + + mylog("PGAPI_ColAttr: BASE_TABLE_NAME = '%s'\n", p); + break; + case SQL_DESC_LENGTH: /* different from SQL_COLUMN_LENGTH */ + value = fi ? fi->length : pgtype_length(stmt, field_type, col_idx, unknown_sizes); + + mylog("PGAPI_ColAttributes: col %d, length = %d\n", col_idx, value); + break; + case SQL_DESC_OCTET_LENGTH: + value = fi ? fi->length : pgtype_length(stmt, field_type, col_idx, unknown_sizes); + + mylog("PGAPI_ColAttributes: col %d, octet_length = %d\n", col_idx, value); + break; + case SQL_DESC_PRECISION: /* different from SQL_COLUMN_PRECISION */ + value = fi ? fi->precision : pgtype_precision(stmt, field_type, col_idx, unknown_sizes); + + mylog("PGAPI_ColAttributes: col %d, desc_precision = %d\n", col_idx, value); + break; + case SQL_DESC_SCALE: /* different from SQL_COLUMN_SCALE */ + value = pgtype_scale(stmt, field_type, col_idx); + break; + case SQL_DESC_LOCAL_TYPE_NAME: + p = pgtype_to_name(stmt, field_type); + break; + case SQL_DESC_TYPE: + value = pgtype_to_sqltype(stmt, field_type); + switch (value) + { + case SQL_TYPE_DATE: + case SQL_TYPE_TIME: + case SQL_TYPE_TIMESTAMP: + value = SQL_DATETIME; + break; + } + break; + case SQL_DESC_LITERAL_PREFIX: + case SQL_DESC_LITERAL_SUFFIX: + case SQL_DESC_NUM_PREC_RADIX: + case SQL_DESC_UNNAMED: +#endif /* ODBCVER */ + default: + stmt->errornumber = STMT_INVALID_OPTION_IDENTIFIER; + stmt->errormsg = "ColAttribute for this type not implemented yet"; + SC_log_error(func, "", stmt); + return SQL_ERROR; } result = SQL_SUCCESS; @@ -614,6 +723,14 @@ PGAPI_ColAttributes( if (rgbDesc) { +#ifdef UNICODE_SUPPORT + if (conn->unicode) + { + len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbDesc, cbDescMax / 2); + len *= 2; + } + else +#endif /* UNICODE_SUPPORT */ strncpy_null((char *) rgbDesc, p, (size_t) cbDescMax); if (len >= cbDescMax) @@ -667,7 +784,7 @@ PGAPI_GetData( return SQL_INVALID_HANDLE; } ci = &(SC_get_conn(stmt)->connInfo); - res = stmt->result; + res = SC_get_Curres(stmt); if (STMT_EXECUTING == stmt->status) { @@ -834,7 +951,7 @@ PGAPI_Fetch( StatementClass *stmt = (StatementClass *) hstmt; QResultClass *res; - mylog("PGAPI_Fetch: stmt = %u, stmt->result= %u\n", stmt, stmt->result); + mylog("PGAPI_Fetch: stmt = %u, stmt->result= %u\n", stmt, SC_get_Curres(stmt)); if (!stmt) { @@ -844,7 +961,7 @@ PGAPI_Fetch( SC_clear_error(stmt); - if (!(res = stmt->result)) + if (!(res = SC_get_Curres(stmt))) { stmt->errormsg = "Null statement result in PGAPI_Fetch."; stmt->errornumber = STMT_SEQUENCE_ERROR; @@ -935,7 +1052,7 @@ PGAPI_ExtendedFetch( SC_clear_error(stmt); - if (!(res = stmt->result)) + if (!(res = SC_get_Curres(stmt))) { stmt->errormsg = "Null statement result in PGAPI_ExtendedFetch."; stmt->errornumber = STMT_SEQUENCE_ERROR; @@ -1214,6 +1331,15 @@ RETCODE SQL_API PGAPI_MoreResults( HSTMT hstmt) { + const char *func = "PGAPI_MoreResults"; + StatementClass *stmt = (StatementClass *) hstmt; + QResultClass *res; + + mylog("%s: entering...\n", func); + if (stmt && (res = SC_get_Curres(stmt))) + SC_get_Curres(stmt) = res->next; + if (SC_get_Curres(stmt)) + return SQL_SUCCESS; return SQL_NO_DATA_FOUND; } @@ -1243,12 +1369,7 @@ positioned_load(StatementClass *stmt, BOOL latest, int res_cols, UInt4 oid, cons } sprintf(selstr, "%s oid = %u", selstr, oid), mylog("selstr=%s\n", selstr); - qres = CC_send_query(SC_get_conn(stmt), selstr, NULL); - if (qres && QR_aborted(qres)) - { - QR_Destructor(qres); - qres = (QResultClass *) 0; - } + qres = CC_send_query(SC_get_conn(stmt), selstr, NULL, TRUE); return qres; } @@ -1270,7 +1391,7 @@ SC_pos_reload(StatementClass *stmt, UWORD irow, UWORD *count) rcnt = 0; if (count) *count = 0; - if (!(res = stmt->result)) + if (!(res = SC_get_Curres(stmt))) return SQL_ERROR; if (!stmt->ti) parse_statement(stmt); /* not preferable */ @@ -1339,7 +1460,7 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, const char *tidval) RETCODE ret = SQL_ERROR; mylog("positioned new fi=%x ti=%x\n", stmt->fi, stmt->ti); - if (!(res = stmt->result)) + if (!(res = SC_get_Curres(stmt))) return SQL_ERROR; if (!stmt->ti) parse_statement(stmt); /* not preferable */ @@ -1401,6 +1522,41 @@ SC_pos_newload(StatementClass *stmt, UInt4 oid, const char *tidval) return ret; } +static RETCODE SQL_API +irow_update(RETCODE ret, StatementClass *stmt, UWORD irow) +{ + if (ret != SQL_ERROR) + { + int updcnt; + const char *cmdstr = QR_get_command(SC_get_Curres(stmt)); + + if (cmdstr && + sscanf(cmdstr, "UPDATE %d", &updcnt) == 1) + { + if (updcnt == 1) + SC_pos_reload(stmt, irow, (UWORD *) 0); + else if (updcnt == 0) + { + stmt->errornumber = STMT_ROW_VERSION_CHANGED; + stmt->errormsg = "the content was changed before updation"; + ret = SQL_ERROR; + if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN) + SC_pos_reload(stmt, irow, (UWORD *) 0); + } + else + ret = SQL_ERROR; + stmt->currTuple = stmt->rowset_start + irow; + } + else + ret = SQL_ERROR; + if (ret == SQL_ERROR && stmt->errornumber == 0) + { + stmt->errornumber = STMT_ERROR_TAKEN_FROM_BACKEND; + stmt->errormsg = "SetPos update return error"; + } + } + return ret; +} RETCODE SQL_API SC_pos_update(StatementClass *stmt, UWORD irow) @@ -1419,8 +1575,8 @@ SC_pos_update(StatementClass *stmt, UInt4 offset; Int4 *used; - mylog("POS UPDATE %d+%d fi=%x ti=%x\n", irow, stmt->result->base, stmt->fi, stmt->ti); - if (!(res = stmt->result)) + mylog("POS UPDATE %d+%d fi=%x ti=%x\n", irow, SC_get_Curres(stmt)->base, stmt->fi, stmt->ti); + if (!(res = SC_get_Curres(stmt))) return SQL_ERROR; if (!stmt->ti) parse_statement(stmt); /* not preferable */ @@ -1510,40 +1666,12 @@ SC_pos_update(StatementClass *stmt, stmt->errormsg = "SetPos with data_at_exec not yet supported"; ret = SQL_ERROR; } - if (ret != SQL_ERROR) - { - int updcnt; - const char *cmdstr = QR_get_command(qstmt->result); - - if (cmdstr && - sscanf(cmdstr, "UPDATE %d", &updcnt) == 1) - { - if (updcnt == 1) - SC_pos_reload(stmt, irow, (UWORD *) 0); - else if (updcnt == 0) - { - stmt->errornumber = STMT_ROW_VERSION_CHANGED; - stmt->errormsg = "the content was changed before updation"; - ret = SQL_ERROR; - if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN) - SC_pos_reload(stmt, irow, (UWORD *) 0); - } - else - ret = SQL_ERROR; - stmt->currTuple = stmt->rowset_start + irow; - } - else - ret = SQL_ERROR; - if (ret == SQL_ERROR && stmt->errornumber == 0) - { - stmt->errornumber = STMT_ERROR_TAKEN_FROM_BACKEND; - stmt->errormsg = "SetPos update return error"; - } - } + ret = irow_update(ret, qstmt, irow); PGAPI_FreeStmt(hstmt, SQL_DROP); } else ret = SQL_SUCCESS_WITH_INFO; +#if (ODBCVER >= 0x0300) if (stmt->options.rowStatusArray) { switch (ret) @@ -1556,6 +1684,7 @@ SC_pos_update(StatementClass *stmt, break; } } +#endif /* ODBCVER */ return ret; } @@ -1573,7 +1702,7 @@ SC_pos_delete(StatementClass *stmt, char *oidval; mylog("POS DELETE fi=%x ti=%x\n", stmt->fi, stmt->ti); - if (!(res = stmt->result)) + if (!(res = SC_get_Curres(stmt))) return SQL_ERROR; if (!stmt->ti) parse_statement(stmt); /* not preferable */ @@ -1591,11 +1720,11 @@ SC_pos_delete(StatementClass *stmt, } sprintf(dltstr, "delete from \"%s\" where ctid = '%s' and oid = %s", stmt->ti[0]->name, - QR_get_value_backend_row(stmt->result, global_ridx, res_cols - 2), + QR_get_value_backend_row(SC_get_Curres(stmt), global_ridx, res_cols - 2), oidval); mylog("dltstr=%s\n", dltstr); - qres = CC_send_query(SC_get_conn(stmt), dltstr, NULL); + qres = CC_send_query(SC_get_conn(stmt), dltstr, NULL, TRUE); if (qres && QR_command_successful(qres)) { int dltcnt; @@ -1630,6 +1759,7 @@ SC_pos_delete(StatementClass *stmt, } if (qres) QR_Destructor(qres); +#if (ODBCVER >= 0x0300) if (stmt->options.rowStatusArray) { switch (ret) @@ -1642,6 +1772,40 @@ SC_pos_delete(StatementClass *stmt, break; } } +#endif /* ODBCVER */ + return ret; +} + +static RETCODE SQL_API +irow_insert(RETCODE ret, StatementClass *stmt, int addpos) +{ + if (ret != SQL_ERROR) + { + int addcnt; + UInt4 oid; + const char *cmdstr = QR_get_command(SC_get_Curres(stmt)); + + if (cmdstr && + sscanf(cmdstr, "INSERT %u %d", &oid, &addcnt) == 2 && + addcnt == 1) + { + SC_pos_newload(stmt, oid, NULL); + if (stmt->bookmark.buffer) + { + char buf[32]; + + sprintf(buf, "%ld", addpos); + copy_and_convert_field(stmt, 0, buf, + SQL_C_ULONG, stmt->bookmark.buffer, + 0, stmt->bookmark.used); + } + } + else + { + stmt->errornumber = STMT_ERROR_TAKEN_FROM_BACKEND; + stmt->errormsg = "SetPos insert return error"; + } + } return ret; } RETCODE SQL_API @@ -1661,7 +1825,7 @@ SC_pos_add(StatementClass *stmt, Int4 *used; mylog("POS ADD fi=%x ti=%x\n", stmt->fi, stmt->ti); - if (!(res = stmt->result)) + if (!(res = SC_get_Curres(stmt))) return SQL_ERROR; if (!stmt->ti) parse_statement(stmt); /* not preferable */ @@ -1721,50 +1885,24 @@ SC_pos_add(StatementClass *stmt, mylog("addstr=%s\n", addstr); qstmt->exec_start_row = qstmt->exec_end_row = irow; ret = PGAPI_ExecDirect(hstmt, addstr, strlen(addstr)); - if (ret == SQL_NEED_DATA) /* must be fixed */ - { - stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; - stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR; - stmt->errormsg = "SetPos with data_at_exec not yet supported"; - ret = SQL_ERROR; - } if (ret == SQL_ERROR) { stmt->errornumber = qstmt->errornumber; stmt->errormsg = qstmt->errormsg; } - else + else if (ret == SQL_NEED_DATA) /* must be fixed */ { - int addcnt; - UInt4 oid; - const char *cmdstr = QR_get_command(qstmt->result); - - if (cmdstr && - sscanf(cmdstr, "INSERT %u %d", &oid, &addcnt) == 2 && - addcnt == 1) - { - SC_pos_newload(stmt, oid, NULL); - if (stmt->bookmark.buffer) - { - char buf[32]; - - sprintf(buf, "%ld", res->fcount); - copy_and_convert_field(stmt, 0, buf, - SQL_C_ULONG, stmt->bookmark.buffer, - 0, stmt->bookmark.used); - } - } - else - { - stmt->errornumber = STMT_ERROR_TAKEN_FROM_BACKEND; - stmt->errormsg = "SetPos insert return error"; - ret = SQL_ERROR; - } + stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY; + stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR; + stmt->errormsg = "SetPos with data_at_exec not yet supported"; + ret = SQL_ERROR; } + ret = irow_insert(ret, qstmt, res->fcount); } else ret = SQL_SUCCESS_WITH_INFO; PGAPI_FreeStmt(hstmt, SQL_DROP); +#if (ODBCVER >= 0x0300) if (stmt->options.rowStatusArray) { switch (ret) @@ -1777,6 +1915,8 @@ SC_pos_add(StatementClass *stmt, break; } } +#endif /* ODBCVER */ + return ret; } @@ -1823,7 +1963,7 @@ PGAPI_SetPos( return SQL_ERROR; } - if (!(res = stmt->result)) + if (!(res = SC_get_Curres(stmt))) { stmt->errormsg = "Null statement result in PGAPI_SetPos."; stmt->errornumber = STMT_SEQUENCE_ERROR; diff --git a/src/interfaces/odbc/setup.c b/src/interfaces/odbc/setup.c index 6bcc01bd892..0175d69f32b 100644 --- a/src/interfaces/odbc/setup.c +++ b/src/interfaces/odbc/setup.c @@ -90,7 +90,6 @@ ConfigDSN(HWND hwnd, if (!hglbAttr) return FALSE; lpsetupdlg = (LPSETUPDLG) GlobalLock(hglbAttr); - /* Parse attribute string */ if (lpszAttributes) ParseAttributes(lpszAttributes, lpsetupdlg); @@ -339,7 +338,7 @@ ParseAttributes(LPCSTR lpszAttributes, LPSETUPDLG lpsetupdlg) int cbKey; char value[MAXPGPATH]; - memset(&lpsetupdlg->ci, 0, sizeof(ConnInfo)); + CC_conninfo_init(&(lpsetupdlg->ci)); for (lpsz = lpszAttributes; *lpsz; lpsz++) { diff --git a/src/interfaces/odbc/statement.c b/src/interfaces/odbc/statement.c index 2b2e5f0634e..513c916019a 100644 --- a/src/interfaces/odbc/statement.c +++ b/src/interfaces/odbc/statement.c @@ -159,10 +159,10 @@ PGAPI_FreeStmt(HSTMT hstmt, } /* Free any cursors and discard any result info */ - if (stmt->result) + if (SC_get_Result(stmt)) { - QR_Destructor(stmt->result); - stmt->result = NULL; + QR_Destructor(SC_get_Result(stmt)); + SC_set_Result(stmt, NULL); } } @@ -230,6 +230,7 @@ SC_Constructor(void) rv->hdbc = NULL; /* no connection associated yet */ rv->phstmt = NULL; rv->result = NULL; + rv->curres = NULL; rv->manual_result = FALSE; rv->prepare = FALSE; rv->status = STMT_ALLOCATED; @@ -238,7 +239,6 @@ SC_Constructor(void) rv->errormsg = NULL; rv->errornumber = 0; rv->errormsg_created = FALSE; - rv->errormsg_malloced = FALSE; rv->statement = NULL; rv->stmt_with_params = NULL; @@ -292,7 +292,9 @@ SC_Constructor(void) char SC_Destructor(StatementClass *self) { - mylog("SC_Destructor: self=%u, self->result=%u, self->hdbc=%u\n", self, self->result, self->hdbc); + QResultClass *res = SC_get_Result(self); + + mylog("SC_Destructor: self=%u, self->result=%u, self->hdbc=%u\n", self, res, self->hdbc); SC_clear_error(self); if (STMT_EXECUTING == self->status) { @@ -301,12 +303,12 @@ SC_Destructor(StatementClass *self) return FALSE; } - if (self->result) + if (res) { if (!self->hdbc) - self->result->conn = NULL; /* prevent any dbase activity */ + res->conn = NULL; /* prevent any dbase activity */ - QR_Destructor(self->result); + QR_Destructor(res); } if (self->statement) @@ -442,6 +444,7 @@ char SC_recycle_statement(StatementClass *self) { ConnectionClass *conn; + QResultClass *res; mylog("recycle statement: self= %u\n", self); @@ -514,10 +517,10 @@ SC_recycle_statement(StatementClass *self) self->parse_status = STMT_PARSE_NONE; /* Free any cursors */ - if (self->result) + if (res = SC_get_Result(self), res) { - QR_Destructor(self->result); - self->result = NULL; + QR_Destructor(res); + SC_set_Result(self, NULL); } self->inaccurate_result = FALSE; @@ -533,12 +536,9 @@ SC_recycle_statement(StatementClass *self) self->bind_row = 0; self->last_fetch_count = 0; - if (self->errormsg_malloced && self->errormsg) - free(self->errormsg); self->errormsg = NULL; self->errornumber = 0; self->errormsg_created = FALSE; - self->errormsg_malloced = FALSE; self->lobj_fd = -1; @@ -583,8 +583,8 @@ SC_pre_execute(StatementClass *self) } if (!SC_is_pre_executable(self)) { - self->result = QR_Constructor(); - QR_set_status(self->result, PGRES_TUPLES_OK); + SC_set_Result(self, QR_Constructor()); + QR_set_status(SC_get_Result(self), PGRES_TUPLES_OK); self->inaccurate_result = TRUE; self->status = STMT_PREMATURE; } @@ -617,12 +617,11 @@ SC_unbind_cols(StatementClass *self) void SC_clear_error(StatementClass *self) { - if (self->errormsg_malloced && self->errormsg) - free(self->errormsg); self->errornumber = 0; self->errormsg = NULL; self->errormsg_created = FALSE; - self->errormsg_malloced = FALSE; + self->errorpos = 0; + self->error_recsize = -1; } @@ -633,7 +632,7 @@ SC_clear_error(StatementClass *self) char * SC_create_errormsg(StatementClass *self) { - QResultClass *res = self->result; + QResultClass *res = SC_get_Curres(self); ConnectionClass *conn = self->hdbc; int pos; static char msg[4096]; @@ -642,10 +641,21 @@ SC_create_errormsg(StatementClass *self) if (res && res->message) strcpy(msg, res->message); - else if (self->errormsg) strcpy(msg, self->errormsg); + if (!msg[0] && res && QR_get_notice(res)) + { + char *notice = QR_get_notice(res); + int len = strlen(notice); + if (len < sizeof(msg)) + { + memcpy(msg, notice, len); + msg[len] = '\0'; + } + else + return notice; + } if (conn) { SocketClass *sock = conn->sock; @@ -653,7 +663,7 @@ SC_create_errormsg(StatementClass *self) if (conn->errormsg && conn->errormsg[0] != '\0') { pos = strlen(msg); - sprintf(&msg[pos], ";\n%s", conn->errormsg); + /*sprintf(&msg[pos], ";\n%s", conn->errormsg);*/ } if (sock && sock->errormsg && sock->errormsg[0] != '\0') @@ -662,9 +672,6 @@ SC_create_errormsg(StatementClass *self) sprintf(&msg[pos], ";\n%s", sock->errormsg); } } - if (!msg[0] && res && QR_get_notice(res)) - return QR_get_notice(res); - return msg; } @@ -679,18 +686,17 @@ SC_get_error(StatementClass *self, int *number, char **message) { self->errormsg = SC_create_errormsg(self); self->errormsg_created = TRUE; + self->errorpos = 0; + self->error_recsize = -1; } if (self->errornumber) { *number = self->errornumber; *message = self->errormsg; - if (!self->errormsg_malloced) - self->errormsg = NULL; } rv = (self->errornumber != 0); - self->errornumber = 0; return rv; } @@ -712,7 +718,7 @@ RETCODE SC_fetch(StatementClass *self) { static char *func = "SC_fetch"; - QResultClass *res = self->result; + QResultClass *res = SC_get_Curres(self); int retval, result; @@ -901,6 +907,7 @@ SC_execute(StatementClass *self) static char *func = "SC_execute"; ConnectionClass *conn; char was_ok, was_nonfatal; + QResultClass *res = NULL; Int2 oldstatus, numcols; QueryInfo qi; @@ -952,12 +959,12 @@ SC_execute(StatementClass *self) mylog(" Sending SELECT statement on stmt=%u, cursor_name='%s'\n", self, self->cursor_name); /* send the declare/select */ - self->result = CC_send_query(conn, self->stmt_with_params, NULL); + res = CC_send_query(conn, self->stmt_with_params, NULL, TRUE); - if (SC_is_fetchcursor(self) && self->result != NULL && - QR_command_successful(self->result)) + if (SC_is_fetchcursor(self) && res != NULL && + QR_command_successful(res)) { - QR_Destructor(self->result); + QR_Destructor(res); /* * That worked, so now send the fetch to start getting data @@ -976,7 +983,7 @@ SC_execute(StatementClass *self) */ sprintf(fetch, "fetch %d in %s", qi.row_size, self->cursor_name); - self->result = CC_send_query(conn, fetch, &qi); + res = CC_send_query(conn, fetch, &qi, FALSE); } mylog(" done sending the query:\n"); } @@ -984,7 +991,7 @@ SC_execute(StatementClass *self) { /* not a SELECT statement so don't use a cursor */ mylog(" it's NOT a select statement: stmt=%u\n", self); - self->result = CC_send_query(conn, self->stmt_with_params, NULL); + res = CC_send_query(conn, self->stmt_with_params, NULL, FALSE); /* * We shouldn't send COMMIT. Postgres backend does the autocommit @@ -1003,10 +1010,10 @@ SC_execute(StatementClass *self) self->status = STMT_FINISHED; /* Check the status of the result */ - if (self->result) + if (res) { - was_ok = QR_command_successful(self->result); - was_nonfatal = QR_command_nonfatal(self->result); + was_ok = QR_command_successful(res); + was_nonfatal = QR_command_nonfatal(res); if (was_ok) self->errornumber = STMT_OK; @@ -1018,24 +1025,30 @@ SC_execute(StatementClass *self) self->current_col = -1; self->rowset_start = -1; - /* see if the query did return any result columns */ - numcols = QR_NumResultCols(self->result); - - /* now allocate the array to hold the binding info */ - if (numcols > 0) + /* issue "ABORT" when query aborted */ + if (QR_get_aborted(res)) { - extend_bindings(self, numcols); - if (self->bindings == NULL) + if (!self->internal) + CC_abort(conn); + } + else + { + /* see if the query did return any result columns */ + numcols = QR_NumResultCols(res); + /* now allocate the array to hold the binding info */ + if (numcols > 0) { - self->errornumber = STMT_NO_MEMORY_ERROR; - self->errormsg = "Could not get enough free memory to store the binding information"; - SC_log_error(func, "", self); - return SQL_ERROR; + extend_bindings(self, numcols); + if (self->bindings == NULL) + { + QR_Destructor(res); + self->errornumber = STMT_NO_MEMORY_ERROR; + self->errormsg = "Could not get enough free memory to store the binding information"; + SC_log_error(func, "", self); + return SQL_ERROR; + } } } - /* issue "ABORT" when query aborted */ - if (QR_get_aborted(self->result) && !self->internal) - CC_abort(conn); } else { @@ -1061,6 +1074,15 @@ SC_execute(StatementClass *self) if (!self->internal) CC_abort(conn); } + if (!SC_get_Result(self)) + SC_set_Result(self, res); + else + { + QResultClass *last; + for (last = SC_get_Result(self); last->next; last = last->next) + ; + last->next = res; + } if (self->statement_type == STMT_TYPE_PROCCALL && (self->errornumber == STMT_OK || @@ -1095,7 +1117,8 @@ SC_execute(StatementClass *self) return SQL_SUCCESS_WITH_INFO; else { - self->errormsg = "Error while executing the query"; + if (!self->errormsg || !self->errormsg[0]) + self->errormsg = "Error while executing the query"; SC_log_error(func, "", self); return SQL_ERROR; } @@ -1103,17 +1126,19 @@ SC_execute(StatementClass *self) void -SC_log_error(char *func, char *desc, StatementClass *self) +SC_log_error(const char *func, const char *desc, const StatementClass *self) { #ifdef PRN_NULLCHECK #define nullcheck(a) (a ? a : "(NULL)") #endif if (self) { + QResultClass *res = SC_get_Result(self); + qlog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg)); mylog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg)); qlog(" ------------------------------------------------------------\n"); - qlog(" hdbc=%u, stmt=%u, result=%u\n", self->hdbc, self, self->result); + qlog(" hdbc=%u, stmt=%u, result=%u\n", self->hdbc, self, res); qlog(" manual_result=%d, prepare=%d, internal=%d\n", self->manual_result, self->prepare, self->internal); qlog(" bindings=%u, bindings_allocated=%d\n", self->bindings, self->bindings_allocated); qlog(" parameters=%u, parameters_allocated=%d\n", self->parameters, self->parameters_allocated); @@ -1126,10 +1151,8 @@ SC_log_error(char *func, char *desc, StatementClass *self) qlog(" ----------------QResult Info -------------------------------\n"); - if (self->result) + if (res) { - QResultClass *res = self->result; - qlog(" fields=%u, manual_tuples=%u, backend_tuples=%u, tupleField=%d, conn=%u\n", res->fields, res->manual_tuples, res->backend_tuples, res->tupleField, res->conn); qlog(" fetch_count=%d, fcount=%d, num_fields=%d, cursor='%s'\n", res->fetch_count, res->fcount, res->num_fields, nullcheck(res->cursor)); qlog(" message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice)); @@ -1140,6 +1163,9 @@ SC_log_error(char *func, char *desc, StatementClass *self) CC_log_error(func, desc, self->hdbc); } else + { qlog("INVALID STATEMENT HANDLE ERROR: func=%s, desc='%s'\n", func, desc); + mylog("INVALID STATEMENT HANDLE ERROR: func=%s, desc='%s'\n", func, desc); + } #undef PRN_NULLCHECK } diff --git a/src/interfaces/odbc/statement.h b/src/interfaces/odbc/statement.h index 534c8db4d8a..cf104aa7d13 100644 --- a/src/interfaces/odbc/statement.h +++ b/src/interfaces/odbc/statement.h @@ -103,7 +103,7 @@ enum STMT_PARSE_NONE = 0, STMT_PARSE_COMPLETE, STMT_PARSE_INCOMPLETE, - STMT_PARSE_FATAL + STMT_PARSE_FATAL, }; /* Result style */ @@ -111,7 +111,7 @@ enum { STMT_FETCH_NONE = 0, STMT_FETCH_NORMAL, - STMT_FETCH_EXTENDED + STMT_FETCH_EXTENDED, }; typedef struct @@ -147,6 +147,7 @@ struct StatementClass_ ConnectionClass *hdbc; /* pointer to ConnectionClass this * statement belongs to */ QResultClass *result; /* result of the current statement */ + QResultClass *curres; /* the current result in the chain */ HSTMT FAR *phstmt; StatementOptions options; @@ -215,14 +216,15 @@ struct StatementClass_ char pre_executing; /* This statement is prematurely executing */ char inaccurate_result; /* Current status is PREMATURE but * result is inaccurate */ - char errormsg_malloced; /* Current error message is - * malloed (not in a static - * variable) ? */ char miscinfo; + SWORD errorpos; + SWORD error_recsize; }; #define SC_get_conn(a) (a->hdbc) -#define SC_get_Result(a) (a->result); +#define SC_set_Result(a, b) (a->result = a->curres = b) +#define SC_get_Result(a) (a->result) +#define SC_get_Curres(a) (a->curres) /* options for SC_free_params() */ #define STMT_FREE_PARAMS_ALL 0 @@ -252,7 +254,7 @@ char *SC_create_errormsg(StatementClass *self); RETCODE SC_execute(StatementClass *self); RETCODE SC_fetch(StatementClass *self); void SC_free_params(StatementClass *self, char option); -void SC_log_error(char *func, char *desc, StatementClass *self); +void SC_log_error(const char *func, const char *desc, const StatementClass *self); unsigned long SC_get_bookmark(StatementClass *self); #endif diff --git a/src/interfaces/odbc/win32.mak b/src/interfaces/odbc/win32.mak index 1d92eec1bb4..637e3763376 100644 --- a/src/interfaces/odbc/win32.mak +++ b/src/interfaces/odbc/win32.mak @@ -31,7 +31,7 @@ CFG=Release !MESSAGE "Release" (Win32 Release DLL) !MESSAGE "Debug" (Win32 Debug DLL) !MESSAGE "MultibyteRelease" (Win32 Release DLL with Multibyte support) -!MESSAGE "MultibyteDebug" (Win32 Release DLL with Multibyte support) +!MESSAGE "MultibyteDebug" (Win32 Debug DLL with Multibyte support) !MESSAGE !ERROR An invalid configuration was specified. !ENDIF @@ -46,13 +46,15 @@ NULL=nul !IF "$(CFG)" == "MultibyteRelease" OUTDIR=.\MultibyteRelease +OUTDIRBIN=.\MultibyteRelease INTDIR=.\MultibyteRelease !ELSE OUTDIR=.\Release +OUTDIRBIN=.\Release INTDIR=.\Release !ENDIF -ALL : "$(OUTDIR)\psqlodbc.dll" +ALL : "$(OUTDIRBIN)\psqlodbc.dll" CLEAN : @@ -64,7 +66,6 @@ CLEAN : -@erase "$(INTDIR)\drvconn.obj" -@erase "$(INTDIR)\environ.obj" -@erase "$(INTDIR)\execute.obj" - -@erase "$(INTDIR)\gpps.obj" -@erase "$(INTDIR)\info.obj" -@erase "$(INTDIR)\lobj.obj" -@erase "$(INTDIR)\win_md5.obj" @@ -139,7 +140,7 @@ BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc" BSC32_SBRS= \ LINK32=link.exe -LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\psqlodbc.pdb" /machine:I386 /def:"psqlodbc_win32.def" /out:"$(OUTDIR)\psqlodbc.dll" /implib:"$(OUTDIR)\psqlodbc.lib" +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\psqlodbc.pdb" /machine:I386 /def:"psqlodbc_win32.def" /out:"$(OUTDIRBIN)\psqlodbc.dll" /implib:"$(OUTDIR)\psqlodbc.lib" DEF_FILE= "psqlodbc_win32.def" LINK32_OBJS= \ "$(INTDIR)\bind.obj" \ @@ -150,7 +151,6 @@ LINK32_OBJS= \ "$(INTDIR)\drvconn.obj" \ "$(INTDIR)\environ.obj" \ "$(INTDIR)\execute.obj" \ - "$(INTDIR)\gpps.obj" \ "$(INTDIR)\info.obj" \ "$(INTDIR)\lobj.obj" \ "$(INTDIR)\win_md5.obj" \ @@ -172,7 +172,7 @@ LINK32_OBJS= \ "$(INTDIR)\odbcapi.obj" \ "$(INTDIR)\psqlodbc.res" -"$(OUTDIR)\psqlodbc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) +"$(OUTDIRBIN)\psqlodbc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) $(LINK32) @<< $(LINK32_FLAGS) $(LINK32_OBJS) << @@ -199,7 +199,6 @@ CLEAN : -@erase "$(INTDIR)\drvconn.obj" -@erase "$(INTDIR)\environ.obj" -@erase "$(INTDIR)\execute.obj" - -@erase "$(INTDIR)\gpps.obj" -@erase "$(INTDIR)\info.obj" -@erase "$(INTDIR)\lobj.obj" -@erase "$(INTDIR)\win_md5.obj" @@ -288,7 +287,6 @@ LINK32_OBJS= \ "$(INTDIR)\drvconn.obj" \ "$(INTDIR)\environ.obj" \ "$(INTDIR)\execute.obj" \ - "$(INTDIR)\gpps.obj" \ "$(INTDIR)\info.obj" \ "$(INTDIR)\lobj.obj" \ "$(INTDIR)\win_md5.obj" @@ -367,12 +365,6 @@ SOURCE=execute.c $(CPP) $(CPP_PROJ) $(SOURCE) -SOURCE=gpps.c - -"$(INTDIR)\gpps.obj" : $(SOURCE) "$(INTDIR)" - $(CPP) $(CPP_PROJ) $(SOURCE) - - SOURCE=info.c "$(INTDIR)\info.obj" : $(SOURCE) "$(INTDIR)" diff --git a/src/interfaces/odbc/win32_30.mak b/src/interfaces/odbc/win32_30.mak index 021b22c3bd1..355d5a3a1ab 100755 --- a/src/interfaces/odbc/win32_30.mak +++ b/src/interfaces/odbc/win32_30.mak @@ -88,6 +88,7 @@ CLEAN : -@erase "$(INTDIR)\tuplelist.obj" -@erase "$(INTDIR)\odbcapi.obj" -@erase "$(INTDIR)\odbcapi30.obj" + -@erase "$(INTDIR)\pgapi30.obj" -@erase "$(INTDIR)\vc60.idb" -@erase "$(OUTDIR)\psqlodbc30.dll" -@erase "$(OUTDIR)\psqlodbc.exp" @@ -174,6 +175,7 @@ LINK32_OBJS= \ "$(INTDIR)\tuplelist.obj" \ "$(INTDIR)\odbcapi.obj" \ "$(INTDIR)\odbcapi30.obj" \ + "$(INTDIR)\pgapi30.obj" \ "$(INTDIR)\psqlodbc.res" "$(OUTDIRBIN)\psqlodbc30.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) @@ -225,6 +227,7 @@ CLEAN : -@erase "$(INTDIR)\tuplelist.obj" -@erase "$(INTDIR)\odbcapi.obj" -@erase "$(INTDIR)\odbcapi30.obj" + -@erase "$(INTDIR)\pgapi30.obj" -@erase "$(INTDIR)\vc60.idb" -@erase "$(INTDIR)\vc60.pdb" -@erase "$(OUTDIR)\psqlodbc30.dll" @@ -314,6 +317,7 @@ LINK32_OBJS= \ "$(INTDIR)\tuplelist.obj" \ "$(INTDIR)\odbcapi.obj" \ "$(INTDIR)\odbcapi30.obj" \ + "$(INTDIR)\pgapi30.obj" \ "$(INTDIR)\psqlodbc.res" "$(OUTDIR)\psqlodbc30.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) @@ -513,7 +517,10 @@ SOURCE=odbcapi30.c "$(INTDIR)\odbcapi30.obj" : $(SOURCE) "$(INTDIR)" $(CPP) $(CPP_PROJ) $(SOURCE) +SOURCE=pgcapi30.c +"$(INTDIR)\pgcapi30.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) !ENDIF diff --git a/src/interfaces/odbc/win32_30w.mak b/src/interfaces/odbc/win32_30w.mak new file mode 100644 index 00000000000..4455069fdad --- /dev/null +++ b/src/interfaces/odbc/win32_30w.mak @@ -0,0 +1,508 @@ +# +# File: win32_30w.mak +# +# Description: psqlodbc30 Unicode version Makefile for Win32. +# +# Configurations: Unicode30Debug, Unicode30 +# Build Types: ALL, CLEAN +# Usage: NMAKE /f win32_30.mak CFG=[Unicode30 | Unicode30Debug] [ALL | CLEAN] +# +# Comments: Created by Dave Page, 2001-02-12 +# + +!MESSAGE Building the PostgreSQL Unicode 3.0 Driver for Win32... +!MESSAGE +!IF "$(CFG)" == "" +CFG=Unicode30 +!MESSAGE No configuration specified. Defaulting to Unicode30. +!MESSAGE +!ENDIF + +!IF "$(CFG)" != "Unicode30" && "$(CFG)" != "Unicode30Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f win32_30.mak CFG=[Unicode30 | Unicode30Debug] [ALL | CLEAN] +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Unicode30" (Win32 Release DLL) +!MESSAGE "Unicode30Debug" (Win32 Debug DLL) +!MESSAGE +!ERROR An invalid configuration was specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "Unicode30" + +OUTDIR=.\Unicode30 +OUTDIRBIN=.\Unicode30 +INTDIR=.\Unicode30 + +ALL : "$(OUTDIRBIN)\psqlodbc30.dll" + + +CLEAN : + -@erase "$(INTDIR)\bind.obj" + -@erase "$(INTDIR)\columninfo.obj" + -@erase "$(INTDIR)\connection.obj" + -@erase "$(INTDIR)\convert.obj" + -@erase "$(INTDIR)\dlg_specific.obj" + -@erase "$(INTDIR)\drvconn.obj" + -@erase "$(INTDIR)\environ.obj" + -@erase "$(INTDIR)\execute.obj" + -@erase "$(INTDIR)\info.obj" + -@erase "$(INTDIR)\info30.obj" + -@erase "$(INTDIR)\lobj.obj" + -@erase "$(INTDIR)\win_md5.obj" + -@erase "$(INTDIR)\misc.obj" + -@erase "$(INTDIR)\pgapi30.obj" + -@erase "$(INTDIR)\multibyte.obj" + -@erase "$(INTDIR)\odbcapiw.obj" + -@erase "$(INTDIR)\odbcapi30w.obj" + -@erase "$(INTDIR)\win_unicode.obj" + -@erase "$(INTDIR)\options.obj" + -@erase "$(INTDIR)\parse.obj" + -@erase "$(INTDIR)\pgtypes.obj" + -@erase "$(INTDIR)\psqlodbc.obj" + -@erase "$(INTDIR)\psqlodbc.res" + -@erase "$(INTDIR)\qresult.obj" + -@erase "$(INTDIR)\results.obj" + -@erase "$(INTDIR)\setup.obj" + -@erase "$(INTDIR)\socket.obj" + -@erase "$(INTDIR)\statement.obj" + -@erase "$(INTDIR)\tuple.obj" + -@erase "$(INTDIR)\tuplelist.obj" + -@erase "$(INTDIR)\odbcapi.obj" + -@erase "$(INTDIR)\odbcapi30.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\psqlodbc30.dll" + -@erase "$(OUTDIR)\psqlodbc.exp" + -@erase "$(OUTDIR)\psqlodbc.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "ODBCVER=0x0300" /D "MULTIBYTE" /D "UNICODE_SUPPORT" /D "DRIVER_CURSOR_IMPLEMENT" /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +RSC_PROJ=/l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "NDEBUG" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\psqlodbc.pdb" /machine:I386 /def:"psqlodbc_api30w.def" /out:"$(OUTDIRBIN)\psqlodbc30.dll" /implib:"$(OUTDIR)\psqlodbc.lib" +DEF_FILE= "psqlodbc_api30w.def" +LINK32_OBJS= \ + "$(INTDIR)\bind.obj" \ + "$(INTDIR)\columninfo.obj" \ + "$(INTDIR)\connection.obj" \ + "$(INTDIR)\convert.obj" \ + "$(INTDIR)\dlg_specific.obj" \ + "$(INTDIR)\drvconn.obj" \ + "$(INTDIR)\environ.obj" \ + "$(INTDIR)\execute.obj" \ + "$(INTDIR)\info.obj" \ + "$(INTDIR)\info30.obj" \ + "$(INTDIR)\lobj.obj" \ + "$(INTDIR)\win_md5.obj" \ + "$(INTDIR)\misc.obj" \ + "$(INTDIR)\pgapi30.obj" \ + "$(INTDIR)\multibyte.obj" \ + "$(INTDIR)\odbcapiw.obj" \ + "$(INTDIR)\odbcapi30w.obj" \ + "$(INTDIR)\win_unicode.obj" \ + "$(INTDIR)\options.obj" \ + "$(INTDIR)\parse.obj" \ + "$(INTDIR)\pgtypes.obj" \ + "$(INTDIR)\psqlodbc.obj" \ + "$(INTDIR)\qresult.obj" \ + "$(INTDIR)\results.obj" \ + "$(INTDIR)\setup.obj" \ + "$(INTDIR)\socket.obj" \ + "$(INTDIR)\statement.obj" \ + "$(INTDIR)\tuple.obj" \ + "$(INTDIR)\tuplelist.obj" \ + "$(INTDIR)\odbcapi.obj" \ + "$(INTDIR)\odbcapi30.obj" \ + "$(INTDIR)\psqlodbc.res" + +"$(OUTDIRBIN)\psqlodbc30.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Unicode30Debug" + +ALL : "$(OUTDIR)\psqlodbc30.dll" + + +CLEAN : + -@erase "$(INTDIR)\bind.obj" + -@erase "$(INTDIR)\columninfo.obj" + -@erase "$(INTDIR)\connection.obj" + -@erase "$(INTDIR)\convert.obj" + -@erase "$(INTDIR)\dlg_specific.obj" + -@erase "$(INTDIR)\drvconn.obj" + -@erase "$(INTDIR)\environ.obj" + -@erase "$(INTDIR)\execute.obj" + -@erase "$(INTDIR)\info.obj" + -@erase "$(INTDIR)\info30.obj" + -@erase "$(INTDIR)\lobj.obj" + -@erase "$(INTDIR)\win_md5.obj" + -@erase "$(INTDIR)\misc.obj" + -@erase "$(INTDIR)\pgapi30.obj" + -@erase "$(INTDIR)\multibyte.obj" + -@erase "$(INTDIR)\odbcapiw.obj" + -@erase "$(INTDIR)\odbcapi30w.obj" + -@erase "$(INTDIR)\win_unicode.obj" + -@erase "$(INTDIR)\options.obj" + -@erase "$(INTDIR)\parse.obj" + -@erase "$(INTDIR)\pgtypes.obj" + -@erase "$(INTDIR)\psqlodbc.obj" + -@erase "$(INTDIR)\psqlodbc.res" + -@erase "$(INTDIR)\qresult.obj" + -@erase "$(INTDIR)\results.obj" + -@erase "$(INTDIR)\setup.obj" + -@erase "$(INTDIR)\socket.obj" + -@erase "$(INTDIR)\statement.obj" + -@erase "$(INTDIR)\tuple.obj" + -@erase "$(INTDIR)\tuplelist.obj" + -@erase "$(INTDIR)\odbcapi.obj" + -@erase "$(INTDIR)\odbcapi30.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\psqlodbc30.dll" + -@erase "$(OUTDIR)\psqlodbc.exp" + -@erase "$(OUTDIR)\psqlodbc.ilk" + -@erase "$(OUTDIR)\psqlodbc.lib" + -@erase "$(OUTDIR)\psqlodbc.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "ODBCVER=0x0300" /D "MULTIBYTE" /D "UNICODE_SUPPORT" /D "DRIVER_CURSOR_IMPLEMENT" /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +RSC_PROJ=/l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "_DEBUG" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\psqlodbc.pdb" /debug /machine:I386 /def:"psqlodbc_api30w.def" /out:"$(OUTDIR)\psqlodbc30.dll" /implib:"$(OUTDIR)\psqlodbc.lib" /pdbtype:sept +DEF_FILE= "psqlodbc_api30w.def" +LINK32_OBJS= \ + "$(INTDIR)\bind.obj" \ + "$(INTDIR)\columninfo.obj" \ + "$(INTDIR)\connection.obj" \ + "$(INTDIR)\convert.obj" \ + "$(INTDIR)\dlg_specific.obj" \ + "$(INTDIR)\drvconn.obj" \ + "$(INTDIR)\environ.obj" \ + "$(INTDIR)\execute.obj" \ + "$(INTDIR)\info.obj" \ + "$(INTDIR)\info30.obj" \ + "$(INTDIR)\lobj.obj" \ + "$(INTDIR)\win_md5.obj" + "$(INTDIR)\misc.obj" \ + "$(INTDIR)\pgapi30.obj" \ + "$(INTDIR)\multibyte.obj" \ + "$(INTDIR)\odbcapiw.obj" \ + "$(INTDIR)\odbcapi30w.obj" \ + "$(INTDIR)\win_unicode.obj" \ + "$(INTDIR)\options.obj" \ + "$(INTDIR)\parse.obj" \ + "$(INTDIR)\pgtypes.obj" \ + "$(INTDIR)\psqlodbc.obj" \ + "$(INTDIR)\qresult.obj" \ + "$(INTDIR)\results.obj" \ + "$(INTDIR)\setup.obj" \ + "$(INTDIR)\socket.obj" \ + "$(INTDIR)\statement.obj" \ + "$(INTDIR)\tuple.obj" \ + "$(INTDIR)\tuplelist.obj" \ + "$(INTDIR)\odbcapi.obj" \ + "$(INTDIR)\odbcapi30.obj" \ + "$(INTDIR)\psqlodbc.res" + +"$(OUTDIR)\psqlodbc30.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +!IF "$(CFG)" == "Unicode30" || "$(CFG)" == "Unicode30Debug" + +SOURCE=bind.c + +"$(INTDIR)\bind.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=columninfo.c + +"$(INTDIR)\columninfo.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=connection.c + +"$(INTDIR)\connection.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=convert.c + +"$(INTDIR)\convert.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=dlg_specific.c + +"$(INTDIR)\dlg_specific.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=drvconn.c + +"$(INTDIR)\drvconn.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=environ.c + +"$(INTDIR)\environ.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=execute.c + +"$(INTDIR)\execute.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=info.c + +"$(INTDIR)\info.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=info30.c + +"$(INTDIR)\info30.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=lobj.c + +"$(INTDIR)\lobj.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=misc.c + +"$(INTDIR)\misc.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=multibyte.c + +"$(INTDIR)\multibyte.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + +SOURCE=odbcapiw.c + +"$(INTDIR)\odbcapiw.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + +SOURCE=pgapi30.c + +"$(INTDIR)\pgapi30.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + +SOURCE=odbcapi30w.c + +"$(INTDIR)\odbcapi30w.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + +SOURCE=win_unicode.c + +"$(INTDIR)\win_unicode.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=options.c + +"$(INTDIR)\options.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=parse.c + +"$(INTDIR)\parse.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=pgtypes.c + +"$(INTDIR)\pgtypes.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=psqlodbc.c + +"$(INTDIR)\psqlodbc.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=psqlodbc.rc + +!IF "$(CFG)" == "Unicode30" +"$(INTDIR)\psqlodbc.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "NDEBUG" /d "MULTIBYTE" $(SOURCE) +!ENDIF + +!IF "$(CFG)" == "Unicode30Debug" +"$(INTDIR)\psqlodbc.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "_DEBUG" $(SOURCE) +!ENDIF + + +SOURCE=qresult.c + +"$(INTDIR)\qresult.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=results.c + +"$(INTDIR)\results.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=setup.c + +"$(INTDIR)\setup.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=socket.c + +"$(INTDIR)\socket.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=statement.c + +"$(INTDIR)\statement.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=tuple.c + +"$(INTDIR)\tuple.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=tuplelist.c + +"$(INTDIR)\tuplelist.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=win_md5.c + +"$(INTDIR)\win_md5.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=odbcapi.c + +"$(INTDIR)\odbcapi.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=odbcapi30.c + +"$(INTDIR)\odbcapi30.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + + + +!ENDIF diff --git a/src/interfaces/odbc/win32w.mak b/src/interfaces/odbc/win32w.mak new file mode 100644 index 00000000000..24a57a129bf --- /dev/null +++ b/src/interfaces/odbc/win32w.mak @@ -0,0 +1,478 @@ +# +# File: win32w.mak +# +# Description: psqlodbc Unicode version Makefile for Win32. +# +# Configurations: UnicodeDebug, Unicode +# Build Types: ALL, CLEAN +# Usage: NMAKE /f win32w.mak CFG=[Unicode | UnicodeDebug] [ALL | CLEAN] +# +# Comments: Created by Dave Page, 2001-02-12 +# + +!MESSAGE Building the PostgreSQL Unicode Driver for Win32... +!MESSAGE +!IF "$(CFG)" == "" +CFG=Unicode +!MESSAGE No configuration specified. Defaulting to Unicode. +!MESSAGE +!ENDIF + +!IF "$(CFG)" != "Unicode" && "$(CFG)" != "UnicodeDebug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f win32w.mak CFG=[Unicode | UnicodeDebug] [ALL | CLEAN] +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Unicode" (Win32 Release DLL) +!MESSAGE "UnicodeDebug" (Win32 Debug DLL) +!MESSAGE +!ERROR An invalid configuration was specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "Unicode" + +OUTDIR=.\Unicode +OUTDIRBIN=.\Unicode +INTDIR=.\Unicode + +ALL : "$(OUTDIRBIN)\psqlodbc.dll" + + +CLEAN : + -@erase "$(INTDIR)\bind.obj" + -@erase "$(INTDIR)\columninfo.obj" + -@erase "$(INTDIR)\connection.obj" + -@erase "$(INTDIR)\convert.obj" + -@erase "$(INTDIR)\dlg_specific.obj" + -@erase "$(INTDIR)\drvconn.obj" + -@erase "$(INTDIR)\environ.obj" + -@erase "$(INTDIR)\execute.obj" + -@erase "$(INTDIR)\info.obj" + -@erase "$(INTDIR)\lobj.obj" + -@erase "$(INTDIR)\win_md5.obj" + -@erase "$(INTDIR)\misc.obj" + -@erase "$(INTDIR)\multibyte.obj" + -@erase "$(INTDIR)\odbcapiw.obj" + -@erase "$(INTDIR)\odbcapi25w.obj" + -@erase "$(INTDIR)\win_unicode.obj" + -@erase "$(INTDIR)\options.obj" + -@erase "$(INTDIR)\parse.obj" + -@erase "$(INTDIR)\pgtypes.obj" + -@erase "$(INTDIR)\psqlodbc.obj" + -@erase "$(INTDIR)\psqlodbc.res" + -@erase "$(INTDIR)\qresult.obj" + -@erase "$(INTDIR)\results.obj" + -@erase "$(INTDIR)\setup.obj" + -@erase "$(INTDIR)\socket.obj" + -@erase "$(INTDIR)\statement.obj" + -@erase "$(INTDIR)\tuple.obj" + -@erase "$(INTDIR)\tuplelist.obj" + -@erase "$(INTDIR)\odbcapi.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\psqlodbc.dll" + -@erase "$(OUTDIR)\psqlodbc.exp" + -@erase "$(OUTDIR)\psqlodbc.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "ODBCVER=0x0250" /D "MULTIBYTE" /D "UNICODE_SUPPORT" /D "DRIVER_CURSOR_IMPLEMENT" /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +RSC_PROJ=/l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "NDEBUG" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\psqlodbc.pdb" /machine:I386 /def:"psqlodbc_apiw.def" /out:"$(OUTDIRBIN)\psqlodbc.dll" /implib:"$(OUTDIR)\psqlodbc.lib" +DEF_FILE= "psqlodbc_apiw.def" +LINK32_OBJS= \ + "$(INTDIR)\bind.obj" \ + "$(INTDIR)\columninfo.obj" \ + "$(INTDIR)\connection.obj" \ + "$(INTDIR)\convert.obj" \ + "$(INTDIR)\dlg_specific.obj" \ + "$(INTDIR)\drvconn.obj" \ + "$(INTDIR)\environ.obj" \ + "$(INTDIR)\execute.obj" \ + "$(INTDIR)\info.obj" \ + "$(INTDIR)\lobj.obj" \ + "$(INTDIR)\win_md5.obj" \ + "$(INTDIR)\misc.obj" \ + "$(INTDIR)\multibyte.obj" \ + "$(INTDIR)\odbcapiw.obj" \ + "$(INTDIR)\odbcapi25w.obj" \ + "$(INTDIR)\win_unicode.obj" \ + "$(INTDIR)\options.obj" \ + "$(INTDIR)\parse.obj" \ + "$(INTDIR)\pgtypes.obj" \ + "$(INTDIR)\psqlodbc.obj" \ + "$(INTDIR)\qresult.obj" \ + "$(INTDIR)\results.obj" \ + "$(INTDIR)\setup.obj" \ + "$(INTDIR)\socket.obj" \ + "$(INTDIR)\statement.obj" \ + "$(INTDIR)\tuple.obj" \ + "$(INTDIR)\tuplelist.obj" \ + "$(INTDIR)\odbcapi.obj" \ + "$(INTDIR)\psqlodbc.res" + +"$(OUTDIRBIN)\psqlodbc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "UnicodeDebug" + +ALL : "$(OUTDIR)\psqlodbc.dll" + + +CLEAN : + -@erase "$(INTDIR)\bind.obj" + -@erase "$(INTDIR)\columninfo.obj" + -@erase "$(INTDIR)\connection.obj" + -@erase "$(INTDIR)\convert.obj" + -@erase "$(INTDIR)\dlg_specific.obj" + -@erase "$(INTDIR)\drvconn.obj" + -@erase "$(INTDIR)\environ.obj" + -@erase "$(INTDIR)\execute.obj" + -@erase "$(INTDIR)\info.obj" + -@erase "$(INTDIR)\lobj.obj" + -@erase "$(INTDIR)\win_md5.obj" + -@erase "$(INTDIR)\misc.obj" + -@erase "$(INTDIR)\multibyte.obj" + -@erase "$(INTDIR)\odbcapiw.obj" + -@erase "$(INTDIR)\odbcapi25w.obj" + -@erase "$(INTDIR)\win_unicode.obj" + -@erase "$(INTDIR)\options.obj" + -@erase "$(INTDIR)\parse.obj" + -@erase "$(INTDIR)\pgtypes.obj" + -@erase "$(INTDIR)\psqlodbc.obj" + -@erase "$(INTDIR)\psqlodbc.res" + -@erase "$(INTDIR)\qresult.obj" + -@erase "$(INTDIR)\results.obj" + -@erase "$(INTDIR)\setup.obj" + -@erase "$(INTDIR)\socket.obj" + -@erase "$(INTDIR)\statement.obj" + -@erase "$(INTDIR)\tuple.obj" + -@erase "$(INTDIR)\tuplelist.obj" + -@erase "$(INTDIR)\odbcapi.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\psqlodbc.dll" + -@erase "$(OUTDIR)\psqlodbc.exp" + -@erase "$(OUTDIR)\psqlodbc.ilk" + -@erase "$(OUTDIR)\psqlodbc.lib" + -@erase "$(OUTDIR)\psqlodbc.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "ODBCVER=0x0250" /D "MULTIBYTE" /D "UNICODE_SUPPORT" /D "DRIVER_CURSOR_IMPLEMENT" /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +RSC_PROJ=/l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "_DEBUG" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\psqlodbc.pdb" /debug /machine:I386 /def:"psqlodbc_apiw.def" /out:"$(OUTDIR)\psqlodbc.dll" /implib:"$(OUTDIR)\psqlodbc.lib" /pdbtype:sept +DEF_FILE= "psqlodbc_apiw.def" +LINK32_OBJS= \ + "$(INTDIR)\bind.obj" \ + "$(INTDIR)\columninfo.obj" \ + "$(INTDIR)\connection.obj" \ + "$(INTDIR)\convert.obj" \ + "$(INTDIR)\dlg_specific.obj" \ + "$(INTDIR)\drvconn.obj" \ + "$(INTDIR)\environ.obj" \ + "$(INTDIR)\execute.obj" \ + "$(INTDIR)\info.obj" \ + "$(INTDIR)\lobj.obj" \ + "$(INTDIR)\win_md5.obj" + "$(INTDIR)\misc.obj" \ + "$(INTDIR)\multibyte.obj" \ + "$(INTDIR)\odbcapiw.obj" \ + "$(INTDIR)\odbcapi25w.obj" \ + "$(INTDIR)\win_unicode.obj" \ + "$(INTDIR)\options.obj" \ + "$(INTDIR)\parse.obj" \ + "$(INTDIR)\pgtypes.obj" \ + "$(INTDIR)\psqlodbc.obj" \ + "$(INTDIR)\qresult.obj" \ + "$(INTDIR)\results.obj" \ + "$(INTDIR)\setup.obj" \ + "$(INTDIR)\socket.obj" \ + "$(INTDIR)\statement.obj" \ + "$(INTDIR)\tuple.obj" \ + "$(INTDIR)\tuplelist.obj" \ + "$(INTDIR)\odbcapi.obj" \ + "$(INTDIR)\psqlodbc.res" + +"$(OUTDIR)\psqlodbc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +!IF "$(CFG)" == "Unicode" || "$(CFG)" == "UnicodeDebug" + +SOURCE=bind.c + +"$(INTDIR)\bind.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=columninfo.c + +"$(INTDIR)\columninfo.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=connection.c + +"$(INTDIR)\connection.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=convert.c + +"$(INTDIR)\convert.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=dlg_specific.c + +"$(INTDIR)\dlg_specific.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=drvconn.c + +"$(INTDIR)\drvconn.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=environ.c + +"$(INTDIR)\environ.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=execute.c + +"$(INTDIR)\execute.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=info.c + +"$(INTDIR)\info.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=lobj.c + +"$(INTDIR)\lobj.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=misc.c + +"$(INTDIR)\misc.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=multibyte.c + +"$(INTDIR)\multibyte.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + +SOURCE=odbcapiw.c + +"$(INTDIR)\odbcapiw.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + +SOURCE=odbcapi25w.c + +"$(INTDIR)\odbcapi25w.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + +SOURCE=win_unicode.c + +"$(INTDIR)\win_unicode.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=options.c + +"$(INTDIR)\options.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=parse.c + +"$(INTDIR)\parse.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=pgtypes.c + +"$(INTDIR)\pgtypes.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=psqlodbc.c + +"$(INTDIR)\psqlodbc.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=psqlodbc.rc + +!IF "$(CFG)" == "Unicode" +"$(INTDIR)\psqlodbc.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "NDEBUG" /d "MULTIBYTE" $(SOURCE) +!ENDIF + +!IF "$(CFG)" == "UnicodeDebug" +"$(INTDIR)\psqlodbc.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "_DEBUG" $(SOURCE) +!ENDIF + + +SOURCE=qresult.c + +"$(INTDIR)\qresult.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=results.c + +"$(INTDIR)\results.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=setup.c + +"$(INTDIR)\setup.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=socket.c + +"$(INTDIR)\socket.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=statement.c + +"$(INTDIR)\statement.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=tuple.c + +"$(INTDIR)\tuple.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=tuplelist.c + +"$(INTDIR)\tuplelist.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=win_md5.c + +"$(INTDIR)\win_md5.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=odbcapi.c + +"$(INTDIR)\odbcapi.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + + +!ENDIF diff --git a/src/interfaces/odbc/win_unicode.c b/src/interfaces/odbc/win_unicode.c index 11a8e396a59..3dfc9ff43d4 100644 --- a/src/interfaces/odbc/win_unicode.c +++ b/src/interfaces/odbc/win_unicode.c @@ -20,6 +20,13 @@ #define byte3_mask2 0x0fc0 #define byte3_mask3 0x003f +UInt4 ucs2strlen(const SQLWCHAR *ucs2str) +{ + UInt4 len; + for (len = 0; ucs2str[len]; len++) + ; + return len; +} char *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen) { char * utf8str; @@ -28,24 +35,21 @@ char *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen) if (!ucs2str) return NULL; if (ilen < 0) - { - for (ilen = 0; ucs2str[ilen]; ilen++) - ; - } + ilen = ucs2strlen(ucs2str); /*mylog(" newlen=%d", ilen);*/ utf8str = (char *) malloc(ilen * 3 + 1); if (utf8str) { int i, len = 0; - Int2 byte2code; - Int4 byte4code; - + UInt2 byte2code; + Int4 byte4code; const SQLWCHAR *wstr; + for (i = 0, wstr = ucs2str; i < ilen; i++, wstr++) { if (!*wstr) break; - else if (iswascii(*wstr)) + else if (0 == (*wstr & 0xff80)) utf8str[len++] = (char) *wstr; else if ((*wstr & byte3check) == 0) { @@ -66,7 +70,8 @@ char *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen) } } utf8str[len] = '\0'; - *olen = len; + if (olen) + *olen = len; } /*mylog(" olen=%d %s\n", *olen, utf8str ? utf8str : "");*/ return utf8str; @@ -109,7 +114,7 @@ UInt4 utf8_to_ucs2(const char *utf8str, Int4 ilen, SQLWCHAR *ucs2str, UInt4 bufc { wcode = ((((UInt4) *str) & byte3_m1) << 12) | ((((UInt4) str[1]) & byte3_m2) << 6) | - ((UInt4) str[2]) & byte3_m3; + (((UInt4) str[2]) & byte3_m3); ucs2str[ocount] = (SQLWCHAR) wcode; } ocount++; @@ -121,7 +126,7 @@ UInt4 utf8_to_ucs2(const char *utf8str, Int4 ilen, SQLWCHAR *ucs2str, UInt4 bufc if (ocount < bufcount) { wcode = ((((UInt4) *str) & byte2_m1) << 6) | - ((UInt4) str[1]) & byte2_m2; + (((UInt4) str[1]) & byte2_m2); ucs2str[ocount] = (SQLWCHAR) wcode; } ocount++; |