From ad3f257a5568fd73f21e391061ca76fce163a43b Mon Sep 17 00:00:00 2001 From: Hiroshi Inoue Date: Mon, 18 Dec 2006 14:45:54 +0000 Subject: [PATCH] 1. Correct the command/responce sequence of Function Call used for large object handling. 2. Add support for NaN and (-)Infinity float values. --- connection.c | 57 ++++++++++++++++++++---------- convert.c | 94 ++++++++++++++++++++++++++++++++++++++++---------- dlg_specific.c | 28 ++++++++------- statement.c | 2 ++ version.h | 2 +- 5 files changed, 133 insertions(+), 50 deletions(-) diff --git a/connection.c b/connection.c index 639780b..c41309f 100644 --- a/connection.c +++ b/connection.c @@ -1396,7 +1396,7 @@ inolog("protocol=%s version=%d,%d\n", ci->protocol, self->pg_version_major, self if (!PROTOCOL_62(ci)) { - BOOL before_64 = PG_VERSION_LT(self, 6.4), + BOOL beforeV2 = PG_VERSION_LT(self, 6.4), ReadyForQuery = FALSE, retry = FALSE; uint32 leng; @@ -1566,7 +1566,7 @@ inolog("Ekita\n"); /* * There were no ReadyForQuery responce before 6.4. */ - if (before_64 && areq == AUTH_REQ_OK) + if (beforeV2 && areq == AUTH_REQ_OK) ReadyForQuery = TRUE; } while (!ReadyForQuery); } @@ -2082,7 +2082,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag, St BOOL msg_truncated, ReadyToReturn = FALSE, query_completed = FALSE, - before_64 = PG_VERSION_LT(self, 6.4), + beforeV2 = PG_VERSION_LT(self, 6.4), aborted = FALSE, used_passed_result_object = FALSE, discard_next_begin = FALSE, @@ -2314,7 +2314,7 @@ inolog("Discarded the first SAVEPOINT\n"); QR_set_command(res, cmdbuffer); query_completed = TRUE; mylog("send_query: returning res = %p\n", res); - if (!before_64) + if (!beforeV2) break; /* @@ -2496,7 +2496,7 @@ inolog("Discarded the first SAVEPOINT\n"); /* * There was no ReadyForQuery response before 6.4. */ - if (before_64) + if (beforeV2) { if (empty_reqs == 0 && query_completed) break; @@ -2606,7 +2606,8 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_ UInt4 leng; Int4 response_length; ConnInfo *ci; - int func_cs_count = 0; + int func_cs_count = 0; + BOOL sinceV3, beforeV3, beforeV2, resultResponse; mylog("send_function(): conn=%p, fnid=%d, result_is_int=%d, nargs=%d\n", self, fnid, result_is_int, nargs); @@ -2627,7 +2628,10 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_ #define return DONT_CALL_RETURN_FROM_HERE??? ENTER_INNER_CONN_CS(self, func_cs_count); ci = &(self->connInfo); - if (PROTOCOL_74(ci)) + sinceV3 = PROTOCOL_74(ci); + beforeV3 = (!sinceV3); + beforeV2 = (beforeV3 && !PROTOCOL_64(ci)); + if (sinceV3) { leng = 4 + sizeof(uint32) + 2 + 2 + sizeof(uint16); @@ -2658,7 +2662,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_ } SOCK_put_int(sock, fnid, 4); - if (PROTOCOL_74(ci)) + if (sinceV3) { SOCK_put_int(sock, 1, 2); /* # of formats */ SOCK_put_int(sock, 1, 2); /* the format is binary */ @@ -2681,7 +2685,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_ } - if (PROTOCOL_74(ci)) + if (sinceV3) SOCK_put_int(sock, 1, 2); /* result format is binary */ mylog(" done sending args\n"); @@ -2689,6 +2693,7 @@ CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_ mylog(" after flush output\n"); done = FALSE; + resultResponse = FALSE; /* for before V3 only */ while (!done) { id = SOCK_get_id(sock); @@ -2699,16 +2704,21 @@ inolog("send_func response_length=%d\n", response_length); switch (id) { case 'G': - if (PROTOCOL_74(ci)) + if (!resultResponse) { done = TRUE; ret = FALSE; break; - } + } /* fall through */ case 'V': if ('V' == id) - if (!PROTOCOL_74(ci)) + { + if (beforeV3) /* FunctionResultResponse */ + { + resultResponse = TRUE; break; + } + } *actual_result_len = SOCK_get_int(sock, 4); if (-1 != *actual_result_len) { @@ -2719,12 +2729,14 @@ inolog("send_func response_length=%d\n", response_length); mylog(" after get result\n"); } - if (!PROTOCOL_74(ci)) + if (beforeV3) { - c = SOCK_get_char(sock); /* get the last '0' */ + c = SOCK_get_char(sock); /* get the last '0' */ + if (beforeV2) + done = TRUE; + resultResponse = FALSE; mylog(" after get 0\n"); } - done = TRUE; break; /* ok */ case 'N': @@ -2741,18 +2753,25 @@ inolog("send_func response_length=%d\n", response_length); mylog("send_function(V): 'E' - %s\n", CC_get_errormsg(self)); qlog("ERROR from backend during send_function: '%s'\n", CC_get_errormsg(self)); - done = TRUE; + if (beforeV2) + done = TRUE; ret = FALSE; break; case 'Z': EatReadyForQuery(self); - break; - - case '0': /* empty result */ done = TRUE; break; + case '0': /* empty result */ + if (resultResponse) + { + if (beforeV2) + done = TRUE; + resultResponse = FALSE; + break; + } /* fall through */ + default: /* skip the unexpected response if possible */ if (response_length >= 0) diff --git a/convert.c b/convert.c index 638dfa1..e73d731 100644 --- a/convert.c +++ b/convert.c @@ -18,6 +18,9 @@ /* Multibyte support Eiji Tokuya 2001-03-15 */ #include "convert.h" +#ifdef WIN32 +#include +#endif /* WIN32 */ #include #include @@ -44,6 +47,10 @@ #define WIN_UNICODE_SUPPORT #endif +CSTR NAN_STRING = "NaN"; +CSTR INFINITY_STRING = "Infinity"; +CSTR MINFINITY_STRING = "-Infinity"; + #ifdef __CYGWIN__ #define TIMEZONE_GLOBAL _timezone #elif defined(WIN32) || defined(HAVE_INT_TIMEZONE) @@ -336,12 +343,12 @@ stime2timestamp(const SIMPLE_TIME *st, char *str, BOOL bZone, BOOL precision) precstr[0] = '\0'; if (st->infinity > 0) { - strcpy(str, "Infinity"); + strcpy(str, INFINITY_STRING); return TRUE; } else if (st->infinity < 0) { - strcpy(str, "-Infinity"); + strcpy(str, MINFINITY_STRING); return TRUE; } if (precision && st->fr) @@ -403,6 +410,31 @@ copy_and_convert_field_bindinfo(StatementClass *stmt, OID field_type, void *valu LENADDR_SHIFT(bic->used, offset), LENADDR_SHIFT(bic->indicator, offset)); } +static double get_double_value(const char *str) +{ + if (stricmp(str, NAN_STRING) == 0) +#ifdef NAN + return (double) NAN; +#else + { + double a = .0; + return .0 / a; + } +#endif /* NAN */ + else if (stricmp(str, INFINITY_STRING) == 0) +#ifdef INFINITY + return (double) INFINITY; +#else + return (double) (HUGE_VAL * HUGE_VAL); +#endif /* INFINITY */ + else if (stricmp(str, MINFINITY_STRING) == 0) +#ifdef INFINITY + return (double) -INFINITY; +#else + return (double) -(HUGE_VAL * HUGE_VAL); +#endif /* INFINITY */ + return atof(str); +} /* This is called by SQLGetData() */ int @@ -607,7 +639,7 @@ mylog("null_cvt_date_string=%d\n", conn->connInfo.cvt_null_date_string); case PG_TYPE_TIMESTAMP: std_time.fr = 0; std_time.infinity = 0; - if (strnicmp(value, "infinity", 8) == 0) + if (strnicmp(value, INFINITY_STRING, 8) == 0) { std_time.infinity = 1; std_time.m = 12; @@ -617,7 +649,7 @@ mylog("null_cvt_date_string=%d\n", conn->connInfo.cvt_null_date_string); std_time.mm = 59; std_time.ss = 59; } - if (strnicmp(value, "-infinity", 9) == 0) + if (strnicmp(value, MINFINITY_STRING, 9) == 0) { std_time.infinity = -1; std_time.m = 0; @@ -1210,9 +1242,9 @@ inolog("2stime fr=%d\n", std_time.fr); #endif /* HAVE_LOCALE_H */ len = 4; if (bind_size > 0) - *((SFLOAT *) rgbValueBindRow) = (float) atof(neut_str); + *((SFLOAT *) rgbValueBindRow) = (float) get_double_value(neut_str); else - *((SFLOAT *) rgbValue + bind_row) = (float) atof(neut_str); + *((SFLOAT *) rgbValue + bind_row) = (float) get_double_value(neut_str); #ifdef HAVE_LOCALE_H setlocale(LC_ALL, saved_locale); free(saved_locale); @@ -1226,9 +1258,9 @@ inolog("2stime fr=%d\n", std_time.fr); #endif /* HAVE_LOCALE_H */ len = 8; if (bind_size > 0) - *((SDOUBLE *) rgbValueBindRow) = atof(neut_str); + *((SDOUBLE *) rgbValueBindRow) = get_double_value(neut_str); else - *((SDOUBLE *) rgbValue + bind_row) = atof(neut_str); + *((SDOUBLE *) rgbValue + bind_row) = get_double_value(neut_str); #ifdef HAVE_LOCALE_H setlocale(LC_ALL, saved_locale); free(saved_locale); @@ -2656,7 +2688,7 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb) mylog("%s convert_escape error\n", func); return SQL_ERROR; } - if (isalnum(F_OldPtr(qp)[1])) + if (isalnum((UCHAR)F_OldPtr(qp)[1])) CVT_APPEND_CHAR(qb, ' '); return SQL_SUCCESS; } @@ -3155,6 +3187,8 @@ ResolveOneParam(QueryBuild *qb, QueryParse *qp) ParameterInfoClass *apara; ParameterImplClass *ipara; BOOL outputDiscard, valueOutput; + SDOUBLE dbv; + SFLOAT flv; outputDiscard = (0 != (qb->flags & FLGB_DISCARD_OUTPUT)); valueOutput = (0 == (qb->flags & (FLGB_PRE_EXECUTING | FLGB_BUILDING_PREPARE_STATEMENT))); @@ -3425,13 +3459,35 @@ mylog("C_WCHAR=%s(%d)\n", buffer, used); #endif /* UNICODE_SUPPORT */ case SQL_C_DOUBLE: - sprintf(param_string, "%.15g", - *((SDOUBLE *) buffer)); + dbv = *((SDOUBLE *) buffer); +#ifdef WIN32 + if (_finite(dbv)) +#endif /* WIN32 */ + sprintf(param_string, "%.15g", dbv); +#ifdef WIN32 + else if (_isnan(dbv)) + strcpy(param_string, NAN_STRING); + else if (dbv < .0) + strcpy(param_string, MINFINITY_STRING); + else + strcpy(param_string, INFINITY_STRING); +#endif /* WIN32 */ break; case SQL_C_FLOAT: - sprintf(param_string, "%.6g", - *((SFLOAT *) buffer)); + flv = *((SFLOAT *) buffer); +#ifdef WIN32 + if (_finite(flv)) +#endif /* WIN32 */ + sprintf(param_string, "%.6g", flv); +#ifdef WIN32 + else if (_isnan(flv)) + strcpy(param_string, NAN_STRING); + else if (flv < .0) + strcpy(param_string, MINFINITY_STRING); + else + strcpy(param_string, INFINITY_STRING); +#endif /* WIN32 */ break; case SQL_C_SLONG: @@ -4042,7 +4098,7 @@ convert_escape(QueryParse *qp, QueryBuild *qb) /* Avoid the concatenation of the function name with the previous word. Aceto */ - if (F_NewPos(qb) > 0 && isalnum(F_NewPtr(qb)[-1])) + if (F_NewPos(qb) > 0 && isalnum((UCHAR)F_NewPtr(qb)[-1])) CVT_APPEND_CHAR(qb, ' '); if (stricmp(key, "d") == 0) @@ -4864,10 +4920,9 @@ convert_lo(StatementClass *stmt, const void *value, SQLSMALLINT fCType, PTR rgbV odbc_lo_lseek(conn, stmt->lobj_fd, 0L, SEEK_SET); } } - mylog("lo data left = %d\n", left); - - if (left == 0) + else if (left == 0) return COPY_NO_DATA_FOUND; + mylog("lo data left = %d\n", left); if (stmt->lobj_fd < 0) { @@ -4875,7 +4930,10 @@ convert_lo(StatementClass *stmt, const void *value, SQLSMALLINT fCType, PTR rgbV return COPY_GENERAL_ERROR; } - retval = odbc_lo_read(conn, stmt->lobj_fd, (char *) rgbValue, (Int4) (factor > 1 ? (cbValueMax - 1) / factor : cbValueMax)); + if (0 >= cbValueMax) + retval = 0; + else + retval = odbc_lo_read(conn, stmt->lobj_fd, (char *) rgbValue, (Int4) (factor > 1 ? (cbValueMax - 1) / factor : cbValueMax)); if (retval < 0) { odbc_lo_close(conn, stmt->lobj_fd); diff --git a/dlg_specific.c b/dlg_specific.c index 6257a58..94d4f98 100644 --- a/dlg_specific.c +++ b/dlg_specific.c @@ -27,8 +27,8 @@ extern GLOBAL_VALUES globals; -static void encode(const char *in, char *out); -static void decode(const char *in, char *out); +static void encode(const UCHAR *in, UCHAR *out); +static void decode(const UCHAR *in, UCHAR *out); UInt4 getExtraOptions(const ConnInfo *ci) { @@ -1319,27 +1319,29 @@ getCommonDefaults(const char *section, const char *filename, ConnInfo *ci) } static void -encode(const char *in, char *out) +encode(const UCHAR *in, UCHAR *out) { size_t i, ilen = strlen(in), o = 0; + UCHAR inc; for (i = 0; i < ilen; i++) { - if (in[i] == '+') + inc = in[i]; + if (inc == '+') { sprintf(&out[o], "%%2B"); o += 3; } - else if (isspace((UCHAR) in[i])) + else if (isspace(inc)) out[o++] = '+'; - else if (!isalnum((UCHAR) in[i])) + else if (!isalnum(inc)) { - sprintf(&out[o], "%%%02x", (UCHAR) in[i]); + sprintf(&out[o], "%%%02x", inc); o += 3; } else - out[o++] = in[i]; + out[o++] = inc; } out[o++] = '\0'; } @@ -1367,22 +1369,24 @@ conv_from_hex(const UCHAR *s) } static void -decode(const char *in, char *out) +decode(const UCHAR *in, UCHAR *out) { size_t i, ilen = strlen(in), o = 0; + UCHAR inc; for (i = 0; i < ilen; i++) { - if (in[i] == '+') + inc = in[i]; + if (inc == '+') out[o++] = ' '; - else if (in[i] == '%') + else if (inc == '%') { sprintf(&out[o++], "%c", conv_from_hex(&in[i])); i += 2; } else - out[o++] = in[i]; + out[o++] = inc; } out[o++] = '\0'; } diff --git a/statement.c b/statement.c index 4ffb585..ac7e04e 100644 --- a/statement.c +++ b/statement.c @@ -1465,6 +1465,8 @@ inolog("%s: stmt=%p ommitted++\n", func, self); /* reset for SQLGetData */ gdata->gdata[lf].data_left = -1; + if (NULL == opts->bindings) + continue; if (opts->bindings[lf].buffer != NULL) { /* this column has a binding */ diff --git a/version.h b/version.h index 8ed970c..8ddd82d 100644 --- a/version.h +++ b/version.h @@ -11,6 +11,6 @@ #define POSTGRESDRIVERVERSION "08.02.0203" #define POSTGRES_RESOURCE_VERSION "08.02.0203\0" -#define PG_DRVFILE_VERSION 8,2,02,03 +#define PG_DRVFILE_VERSION 8,2,02,03 #endif -- 2.39.5