diff --git a/driver/convert.c b/driver/convert.c index 16854672..0608b198 100644 --- a/driver/convert.c +++ b/driver/convert.c @@ -256,7 +256,7 @@ SQLRETURN set_param_decdigits(esodbc_rec_st *irec, * SQL_INTERVAL_DAY_TO_SECOND, SQL_INTERVAL_HOUR_TO_SECOND, or * SQL_INTERVAL_MINUTE_TO_SECOND, the SQL_DESC_PRECISION field of the * IPD is set to DecimalDigits." */ - case METATYPE_DATETIME: + case METATYPE_DATE_TIME: if (irec->concise_type == SQL_TYPE_DATE) { break; } @@ -293,7 +293,7 @@ SQLSMALLINT get_param_decdigits(esodbc_rec_st *irec) assert(irec->desc->type == DESC_TYPE_IPD); switch(irec->meta_type) { - case METATYPE_DATETIME: + case METATYPE_DATE_TIME: if (irec->concise_type == SQL_TYPE_DATE) { break; } @@ -327,7 +327,7 @@ SQLRETURN set_param_size(esodbc_rec_st *irec, * IPD is set to the value of [s]ize." */ case METATYPE_STRING: case METATYPE_BIN: - case METATYPE_DATETIME: + case METATYPE_DATE_TIME: case METATYPE_INTERVAL_WSEC: case METATYPE_INTERVAL_WOSEC: return EsSQLSetDescFieldW(irec->desc, param_no, SQL_DESC_LENGTH, @@ -363,7 +363,7 @@ SQLULEN get_param_size(esodbc_rec_st *irec) switch (irec->meta_type) { case METATYPE_STRING: case METATYPE_BIN: - case METATYPE_DATETIME: + case METATYPE_DATE_TIME: case METATYPE_INTERVAL_WSEC: case METATYPE_INTERVAL_WOSEC: return irec->length; @@ -1466,7 +1466,7 @@ static SQLRETURN wstr_to_wstr(esodbc_rec_st *arec, esodbc_rec_st *irec, return transfer_xstr0(arec, irec, &xsrc, data_ptr, octet_len_ptr); } -/* Converts an xstr to a TS. +/* Converts an ISO 8601-formated xstr to a TS. * xstr needs to be trimmed to exact data (no padding, no 0-term counted). * If ts_buff is non-NULL, the xstr will be copied (possibly W-to-C converted) * into it. */ @@ -1532,8 +1532,9 @@ static BOOL xstr_to_timestamp_struct(esodbc_stmt_st *stmt, xstr_st *xstr, return TRUE; } - -static BOOL parse_timedate(esodbc_stmt_st *stmt, xstr_st *xstr, +/* Analyzes the received string as time/date/timedate(timestamp) and parses it + * into received 'tss' struct, indicating detected format in 'format'. */ +static BOOL parse_date_time_ts(esodbc_stmt_st *stmt, xstr_st *xstr, TIMESTAMP_STRUCT *tss, SQLSMALLINT *format, cstr_st *ts_buff) { /* template buffer: date or time values will be copied in place and @@ -1641,15 +1642,16 @@ static SQLRETURN wstr_to_timestamp(esodbc_rec_st *arec, esodbc_rec_st *irec, switch (irec->concise_type) { case SQL_TYPE_TIMESTAMP: + case SQL_TYPE_DATE: /* ES/SQL passes date as DATETIME */ if (! xstr_to_timestamp_struct(stmt, &xstr, tss, NULL)) { RET_HDIAGS(stmt, SQL_STATE_22018); } if (format) { - *format = SQL_TYPE_TIMESTAMP; + *format = irec->concise_type; } break; case SQL_VARCHAR: - if (! parse_timedate(stmt, &xstr, tss, format, NULL)) { + if (! parse_date_time_ts(stmt, &xstr, tss, format, NULL)) { RET_HDIAGS(stmt, SQL_STATE_22018); } break; @@ -1658,7 +1660,6 @@ static SQLRETURN wstr_to_timestamp(esodbc_rec_st *arec, esodbc_rec_st *irec, case SQL_LONGVARCHAR: case SQL_WCHAR: case SQL_WLONGVARCHAR: - case SQL_TYPE_DATE: case SQL_TYPE_TIME: BUGH(stmt, "unexpected (but permitted) SQL type."); RET_HDIAGS(stmt, SQL_STATE_HY004); @@ -1685,6 +1686,7 @@ static SQLRETURN wstr_to_date(esodbc_rec_st *arec, esodbc_rec_st *irec, TIMESTAMP_STRUCT tss; SQLRETURN ret; SQLSMALLINT fmt; + esodbc_state_et state; if (octet_len_ptr) { *octet_len_ptr = sizeof(*ds); @@ -1703,8 +1705,15 @@ static SQLRETURN wstr_to_date(esodbc_rec_st *arec, esodbc_rec_st *irec, ds->month = tss.month; ds->day = tss.day; if (tss.hour || tss.minute || tss.second || tss.fraction) { - /* value's truncated */ - RET_HDIAGS(stmt, SQL_STATE_01S07); + if (fmt == SQL_TYPE_TIMESTAMP) { + /* value's truncated */ + state = SQL_STATE_01S07; + } else { + ERRH(stmt, "DATE type value contains non-zero time " + "components: `" LWPDL "`.", chars_0 - 1, wstr); + state = SQL_STATE_22018; + } + RET_HDIAGS(stmt, state); } } else { DBGH(stmt, "REC@0x%p, NULL data_ptr", arec); @@ -2796,8 +2805,7 @@ SQLRETURN sql2c_string(esodbc_rec_st *arec, esodbc_rec_st *irec, if (irec->type != SQL_INTERVAL) { \ break; \ } \ - ret = interval_iso8601_to_sql(arec, irec, wstr, &chars_0, \ - buff); \ + ret = interval_iso8601_to_sql(arec, irec, wstr, &chars_0, buff); \ if (! SQL_SUCCEEDED(ret)) { \ return ret; \ } \ @@ -3636,7 +3644,7 @@ static SQLRETURN convert_str_to_timestamp(esodbc_stmt_st *stmt, assert(dest); ts_buff.str = dest; ts_buff.cnt = sizeof(ESODBC_ISO8601_TEMPLATE) - 1; - if (! parse_timedate(stmt, &xstr, &tss, &format, &ts_buff)) { + if (! parse_date_time_ts(stmt, &xstr, &tss, &format, &ts_buff)) { ERRH(stmt, "failed to parse input as Time/Date/Timestamp"); RET_HDIAGS(stmt, SQL_STATE_22008); } else if (format == SQL_TYPE_TIME) { diff --git a/driver/defs.h b/driver/defs.h index 35ac37d1..7e44bb76 100644 --- a/driver/defs.h +++ b/driver/defs.h @@ -273,9 +273,8 @@ * Timedate functions support: * - supported: DAYNAME, DAYOFMONTH, DAYOFWEEK, DAYOFYEAR, EXTRACT, HOUR, * MINUTE, MONTH, MONTHNAME, QUARTER, SECOND, WEEK, YEAR, NOW, - * CURRENT_TIMESTAMP; - * - not supported: CURRENT_DATE, CURRENT_TIME, CURDATE, - * CURTIME, TIMESTAMPADD, TIMESTAMPDIFF. + * CURRENT_TIMESTAMP, CURRENT_DATE, CURDATE; + * - not supported: CURRENT_TIME, CURTIME, TIMESTAMPADD, TIMESTAMPDIFF. */ #define ESODBC_TIMEDATE_FUNCTIONS (0LU | \ SQL_FN_TD_DAYNAME | SQL_FN_TD_DAYOFMONTH | SQL_FN_TD_DAYOFWEEK | \ diff --git a/driver/handles.c b/driver/handles.c index 83a1b009..5eeaa0fa 100644 --- a/driver/handles.c +++ b/driver/handles.c @@ -1963,7 +1963,7 @@ static void set_defaults_from_meta_type(esodbc_rec_st *rec) rec->length = ESODBC_DEF_STRING_LENGTH; rec->precision = ESODBC_DEF_STRING_PRECISION; break; - case METATYPE_DATETIME: + case METATYPE_DATE_TIME: if (rec->datetime_interval_code == SQL_CODE_DATE || rec->datetime_interval_code == SQL_CODE_TIME) { rec->precision = ESODBC_DEF_DATETIME_PRECISION; @@ -2048,7 +2048,7 @@ static esodbc_metatype_et sqltype_to_meta(SQLSMALLINT concise) case SQL_TYPE_TIMESTAMP: // case SQL_TYPE_UTCDATETIME: // case SQL_TYPE_UTCTIME: - return METATYPE_DATETIME; + return METATYPE_DATE_TIME; /* interval (note: SQL_INTERVAL is verbose, not concise) */ case SQL_INTERVAL_MONTH: @@ -2134,7 +2134,7 @@ static esodbc_metatype_et sqlctype_to_meta(SQLSMALLINT concise) case SQL_C_TYPE_TIMESTAMP: // case SQL_C_TYPE_TIME_WITH_TIMEZONE: // case SQL_C_TYPE_TIMESTAMP_WITH_TIMEZONE: - return METATYPE_DATETIME; + return METATYPE_DATE_TIME; /* interval */ case SQL_C_INTERVAL_DAY: @@ -2216,7 +2216,7 @@ static BOOL consistency_check(esodbc_rec_st *rec) /* check SQL_DESC_PRECISION field */ /* "a time or timestamp data type" */ - case METATYPE_DATETIME: + case METATYPE_DATE_TIME: if (rec->concise_type == SQL_TYPE_DATE) { break; } @@ -2233,7 +2233,7 @@ static BOOL consistency_check(esodbc_rec_st *rec) return FALSE; } } - if (rec->meta_type == METATYPE_DATETIME) { + if (rec->meta_type == METATYPE_DATE_TIME) { break; } /* check SQL_DESC_DATETIME_INTERVAL_PRECISION */ diff --git a/driver/handles.h b/driver/handles.h index 5efb34b0..0f342bce 100644 --- a/driver/handles.h +++ b/driver/handles.h @@ -64,7 +64,7 @@ typedef enum { METATYPE_FLOAT_NUMERIC, METATYPE_STRING, METATYPE_BIN, - METATYPE_DATETIME, + METATYPE_DATE_TIME, METATYPE_INTERVAL_WSEC, METATYPE_INTERVAL_WOSEC, METATYPE_BIT, @@ -335,8 +335,10 @@ typedef struct struct_stmt { * returning to the application." */ SQLULEN query_timeout; - /* [current] result set (= one answer from ES/SQL; can contain a cursor) */ + /* [current] result set (= one page from ES/SQL; can contain a cursor) */ resultset_st rset; + /* count of result sets fetched */ + size_t nset; /* total count of fetched rows for one statement (sum(resultset.nrows)) */ size_t tf_rows; /* SQL data types conversion to SQL C compatibility (IRD.SQL -> ARD.C) */ diff --git a/driver/log.h b/driver/log.h index 5f53da89..2ec9157f 100644 --- a/driver/log.h +++ b/driver/log.h @@ -44,7 +44,7 @@ /* macro for logging of Xstr_st objects */ #define LWSTR(_wptr) (int)(_wptr)->cnt, (_wptr)->str -#define LCSTR(_wptr) (int)(_wptr)->cnt, (_wptr)->str +#define LCSTR(_cptr) (int)(_cptr)->cnt, (_cptr)->str #ifdef UNICODE # define LTSTR LWSTR diff --git a/driver/queries.c b/driver/queries.c index 90a4d54d..c5f5d38f 100644 --- a/driver/queries.c +++ b/driver/queries.c @@ -79,7 +79,7 @@ static void set_col_size(esodbc_rec_st *rec) case METATYPE_BIN: /* "The defined or maximum length in bytes of the column " */ /* no break */ - case METATYPE_DATETIME: + case METATYPE_DATE_TIME: /* "number of characters in the character representation" */ rec->length = rec->es_type->column_size; break; @@ -281,6 +281,7 @@ SQLRETURN TEST_API attach_answer(esodbc_stmt_st *stmt, char *buff, size_t blen) stmt->rset.nrows = 0; #endif /*0*/ } else { + stmt->nset ++; /* the cast is made safe by the decoding format indicator for array */ stmt->rset.nrows = (size_t)UJLengthArray(rows); stmt->tf_rows += stmt->rset.nrows; @@ -934,8 +935,8 @@ SQLRETURN EsSQLFetch(SQLHSTMT StatementHandle) DBGH(stmt, "ES/app data/buffer types found compatible."); } - DBGH(stmt, "(`" LCPDL "`); cursor @ %zd / %zd.", LCSTR(&stmt->u8sql), - stmt->rset.vrows, stmt->rset.nrows); + DBGH(stmt, "cursor @ row %zu / %zu in page #%zu. (SQL: `" LCPDL "`).", + stmt->rset.vrows, stmt->rset.nrows, stmt->nset, LCSTR(&stmt->u8sql)); /* reset SQLGetData state, to reset fetch position */ STMT_GD_RESET(stmt); @@ -1513,7 +1514,7 @@ static esodbc_estype_st *match_es_type(esodbc_rec_st *arec, case METATYPE_BIN: /* SQL_VARBINARY == -3 == ES/SQL BINARY */ return lookup_es_type(dbc, SQL_VARBINARY, /*no prec*/0); - case METATYPE_DATETIME: + case METATYPE_DATE_TIME: assert(irec->concise_type == SQL_TYPE_DATE || irec->concise_type == SQL_TYPE_TIME); return lookup_es_type(dbc, SQL_TYPE_TIMESTAMP, /*no prec*/0); @@ -2059,6 +2060,9 @@ SQLRETURN TEST_API serialize_statement(esodbc_stmt_st *stmt, cstr_st *buff) memcpy(body + pos, dbc->fetch.str, dbc->fetch.slen); pos += dbc->fetch.slen; } + + /* reset the page counter when the params change */ + stmt->nset = 0; } /* "mode": */ memcpy(body + pos, JSON_KEY_VAL_MODE, sizeof(JSON_KEY_VAL_MODE) - 1); @@ -2176,7 +2180,7 @@ SQLRETURN EsSQLExecDirectW if (SQL_SUCCEEDED(ret)) { ret = EsSQLExecute(stmt); } -#ifndef NDEBUG +#ifdef NDEBUG /* no reason to keep it (it can't be re-executed), except for debugging */ detach_sql(stmt); #endif /* NDEBUG */ @@ -2235,7 +2239,7 @@ static inline SQLULEN get_col_size(esodbc_rec_st *rec) case METATYPE_STRING: case METATYPE_BIN: - case METATYPE_DATETIME: + case METATYPE_DATE_TIME: case METATYPE_INTERVAL_WSEC: case METATYPE_INTERVAL_WOSEC: case METATYPE_BIT: @@ -2255,7 +2259,7 @@ static inline SQLSMALLINT get_col_decdigits(esodbc_rec_st *rec) assert(DESC_TYPE_IS_IMPLEMENTATION(rec->desc->type)); switch (rec->meta_type) { - case METATYPE_DATETIME: + case METATYPE_DATE_TIME: case METATYPE_INTERVAL_WSEC: return ESODBC_MAX_SEC_PRECISION;