Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions driver/catalogue.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ SQLSMALLINT fetch_server_attr(esodbc_dbc_st *dbc, SQLINTEGER attr_id,
} else {
if (1 < row_cnt) {
WARNH(dbc, "more than one value (%lld) available for "
"attribute %ld; picking first.", row_cnt, attr_id);
"attribute %ld; picking first.", (int64_t)row_cnt, attr_id);
}

if (! SQL_SUCCEEDED(EsSQLBindCol(stmt, /*col#*/1, SQL_C_WCHAR, buff,
Expand Down Expand Up @@ -522,7 +522,7 @@ static SQLRETURN copy_one_cell(esodbc_stmt_st *stmt, wstr_st *dest,
/* fetch data's length (always converted to w-string) */
ret = EsSQLGetData(stmt, col_idx, SQL_C_WCHAR, dest->str, 0, &len_ind);
if (! SQL_SUCCEEDED(ret)) {
ERRH(stmt, "failed to get data lenght for cell@[%ld, %hd].",
ERRH(stmt, "failed to get data length for cell@[%ld, %hd].",
row_cnt, col_idx);
return ret;
}
Expand Down Expand Up @@ -577,17 +577,17 @@ SQLRETURN TEST_API update_varchar_defs(esodbc_stmt_st *stmt)
"{\"name\":\"TABLE_SCHEM\", \"type\":\"keyword\"},"
"{\"name\":\"TABLE_NAME\", \"type\":\"keyword\"},"
"{\"name\":\"COLUMN_NAME\", \"type\":\"keyword\"},"
"{\"name\":\"DATA_TYPE\", \"type\":\"integer\"},"
"{\"name\":\"DATA_TYPE\", \"type\":\"short\"},"
"{\"name\":\"TYPE_NAME\", \"type\":\"keyword\"},"
"{\"name\":\"COLUMN_SIZE\", \"type\":\"integer\"},"
"{\"name\":\"BUFFER_LENGTH\", \"type\":\"integer\"},"
"{\"name\":\"DECIMAL_DIGITS\", \"type\":\"integer\"},"
"{\"name\":\"NUM_PREC_RADIX\", \"type\":\"integer\"},"
"{\"name\":\"NULLABLE\", \"type\":\"integer\"},"
"{\"name\":\"DECIMAL_DIGITS\", \"type\":\"short\"},"
"{\"name\":\"NUM_PREC_RADIX\", \"type\":\"short\"},"
"{\"name\":\"NULLABLE\", \"type\":\"short\"},"
"{\"name\":\"REMARKS\", \"type\":\"keyword\"},"
"{\"name\":\"COLUMN_DEF\", \"type\":\"keyword\"},"
"{\"name\":\"SQL_DATA_TYPE\", \"type\":\"integer\"},"
"{\"name\":\"SQL_DATETIME_SUB\", \"type\":\"integer\"},"
"{\"name\":\"SQL_DATA_TYPE\", \"type\":\"short\"},"
"{\"name\":\"SQL_DATETIME_SUB\", \"type\":\"short\"},"
"{\"name\":\"CHAR_OCTET_LENGTH\", \"type\":\"integer\"},"
"{\"name\":\"ORDINAL_POSITION\", \"type\":\"integer\"},"
"{\"name\":\"IS_NULLABLE\", \"type\":\"keyword\"}"
Expand All @@ -605,9 +605,15 @@ SQLRETURN TEST_API update_varchar_defs(esodbc_stmt_st *stmt)
long row_cnt;
wstr_st dest = {0};
size_t pos;
SQLULEN max_length;
cstr_st u8mb;
wstr_st *lim = &HDRH(stmt)->dbc->varchar_limit_str;

/* save and reset SQL_ATTR_MAX_LENGTH attribute, it'll interfere with
* reading length of avail data with SQLGetData() otherwise. */
max_length = stmt->max_length;
stmt->max_length = 0;

/* check that we have as many columns as members in target row struct */
ret = EsSQLNumResultCols(stmt, &col_cnt);
if (! SQL_SUCCEEDED(ret)) {
Expand Down Expand Up @@ -689,6 +695,8 @@ SQLRETURN TEST_API update_varchar_defs(esodbc_stmt_st *stmt)
free(dest.str);
dest.cnt = 0;
}
/* reinstate any saved SQL_ATTR_MAX_LENGTH value */
stmt->max_length = max_length;
return ret;
}

Expand Down
4 changes: 2 additions & 2 deletions driver/convert.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ static thread_local struct tm today;
} while (0)

#define DBL_BASE10_MAX_LEN /*-0.*/3 + DBL_DIG - DBL_MIN_10_EXP
/* maximum lenght of an interval literal (with terminator; both ISO and SQL),
/* maximum length of an interval literal (with terminator; both ISO and SQL),
* with no field sanity checks: five longs with separators and sign */
#define INTERVAL_VAL_MAX_LEN (5 * sizeof("4294967295"))

Expand Down Expand Up @@ -2836,7 +2836,7 @@ static size_t print_interval_sec(esodbc_rec_st *rec, SQL_INTERVAL_STRUCT *ivl,

if (wide) {
wfmt[2] = L'0' + rec->precision;
/* printf's limits: max lenght of '<second>.<fraction>', accounted
/* printf's limits: max length of '<second>.<fraction>', accounted
* in buffer's max len estimation. */
res = swprintf((wchar_t *)dest, 2 * sizeof("4294967295") + 1,
wfmt, dbl);
Expand Down
2 changes: 1 addition & 1 deletion driver/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
*/
/* maximum URL size */
#define ESODBC_MAX_URL_LEN 2048
/* maximum DNS attribute value lenght (should be long enought to accomodate a
/* maximum DNS attribute value length (should be long enought to accomodate a
* decently long FQ file path name) */
#define ESODBC_DSN_MAX_ATTR_LEN 1024

Expand Down
4 changes: 2 additions & 2 deletions driver/dsn.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ int assign_dsn_attr(esodbc_dsn_attrs_st *attrs,
ESODBC_DSN_ATTRS_COUNT);

if (ESODBC_DSN_MAX_ATTR_LEN < value->cnt) {
ERR("attribute value lenght too large: %zu; max=%zu.", value->cnt,
ERR("attribute value length too large: %zu; max=%zu.", value->cnt,
ESODBC_DSN_MAX_ATTR_LEN);
return -1;
}
Expand Down Expand Up @@ -356,7 +356,7 @@ BOOL TEST_API parse_00_list(esodbc_dsn_attrs_st *attrs, SQLWCHAR *list00)
cnt = wcslen(pos);

if (SHRT_MAX < cnt) {
ERR("invalid list lenght (%zu).", cnt);
ERR("invalid list length (%zu).", cnt);
return FALSE;
}
if (! parse_connection_string(attrs, pos, (SQLSMALLINT)cnt)) {
Expand Down
2 changes: 1 addition & 1 deletion driver/dsn.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ typedef struct {
wstr_st trace_level;
#define ESODBC_DSN_ATTRS_COUNT 29
SQLWCHAR buff[ESODBC_DSN_ATTRS_COUNT * ESODBC_DSN_MAX_ATTR_LEN];
/* DSN reading/writing functions are passed a SQLSMALLINT lenght param */
/* DSN reading/writing functions are passed a SQLSMALLINT length param */
#if SHRT_MAX < ESODBC_DSN_ATTRS_COUNT * ESODBC_DSN_MAX_ATTR_LEN
#error "attrs buffer too large"
#endif
Expand Down
2 changes: 1 addition & 1 deletion driver/handles.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ typedef struct struct_dbc {
/* maximum precision/length of types using same SQL data type ID */
esodbc_estype_st *max_varchar_type; /* pointer to TEXT type */
esodbc_estype_st *max_float_type; /* pointer to DOUBLE type */
/* configuration imposed lenghts for the ES/SQL string types */
/* configuration imposed lengths for the ES/SQL string types */
SQLUINTEGER varchar_limit;
wstr_st varchar_limit_str; /* convenience w-string of varchar limit */

Expand Down
2 changes: 1 addition & 1 deletion driver/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ char *cstr_hex_dump(const cstr_st *buff);
#endif /* _WIN32 */


/* ISO time formats lenghts.
/* ISO time formats lengths.
* ES/SQL interface should only use UTC ('Z'ulu offset). */
#define ISO8601_TIMESTAMP_LEN(prec) \
(sizeof("yyyy-mm-ddThh:mm:ss+hh:mm") - /*\0*/1 + /*'.'*/!!prec + prec)
Expand Down
25 changes: 25 additions & 0 deletions test/test_catalogue.cc
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ TEST_F(Catalogue, Columns_update_varchar_defs) {
"]"
"}";

/* setting this attribute should not affect the outcome */
ret = SQLSetStmtAttr(stmt, SQL_ATTR_MAX_LENGTH, (SQLPOINTER)INT_MAX,
SQL_IS_UINTEGER);
ASSERT_TRUE(SQL_SUCCEEDED(ret));

prepareStatement(response);

/* needs to be lower than ESODBC_MAX_KEYWORD_PRECISION (~32k) */
Expand Down Expand Up @@ -120,6 +125,26 @@ TEST_F(Catalogue, Columns_update_varchar_defs) {
ASSERT_EQ(val, VARCHAR_LIMIT);
}

/* above SYS COLUMNS result contains wrong (integer) type for the following
* columns that should be short */
const SQLUSMALLINT short_cols[] = {
SQLCOLS_IDX_DATA_TYPE,
SQLCOLS_IDX_DECIMAL_DIGITS,
SQLCOLS_IDX_NUM_PREC_RADIX,
SQLCOLS_IDX_NULLABLE,
SQLCOLS_IDX_SQL_DATA_TYPE,
SQLCOLS_IDX_SQL_DATETIME_SUB
};
SQLWCHAR col_name[128];
SQLSMALLINT col_name_len, sql_type, scale, nullable;
SQLULEN col_size;
for (size_t i = 0; i < sizeof(short_cols)/sizeof(short_cols[0]); i ++) {
ret = SQLDescribeCol(stmt, short_cols[i], col_name, sizeof(col_name),
&col_name_len, &sql_type, &col_size, &scale, &nullable);
ASSERT_TRUE(SQL_SUCCEEDED(ret));
ASSERT_EQ(sql_type, SQL_SMALLINT);
}

HDRH(stmt)->dbc->varchar_limit = 0;
memset(&HDRH(stmt)->dbc->varchar_limit_str, 0, sizeof(wstr_st));

Expand Down
60 changes: 60 additions & 0 deletions test/test_queries.cc
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,66 @@ TEST_F(Queries, SQLDescribeCol_char) {
ASSERT_EQ(nullable, SQL_NULLABLE_UNKNOWN);
}

TEST_F(Queries, SQLDescribeCol_varchar_lim) {

# undef COL_NAME
# define COL_NAME "SQLDescribeCol_varchar_lim"
# define VARCHAR_LIMIT 333
# define CONN_STR CONNECT_STRING "VarcharLimit=" STR(VARCHAR_LIMIT) ";"

const char json_answer[] = "\
{\
\"columns\": [\
{\"name\": \"" COL_NAME "\", \"type\": \"text\"},\
{\"name\": \"binary\", \"type\": \"binary\"}\
],\
\"rows\": [\
[\"foo\", \"binary\"]\
]\
}\
";

/* set varchar limit: this is set onto the varchar types structures, so the
* DBC needs "reconnecting" and the corresponding DSN param set */
ret = SQLFreeHandle(SQL_HANDLE_STMT, stmt);
assert(SQL_SUCCEEDED(ret));
ret = SQLFreeHandle(SQL_HANDLE_DBC, dbc);
assert(SQL_SUCCEEDED(ret));
ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
assert(SQL_SUCCEEDED(ret));
cstr_st types = {0};
types.str = (SQLCHAR *)strdup(SYSTYPES_ANSWER);
assert(types.str != NULL);
types.cnt = sizeof(SYSTYPES_ANSWER) - 1;
ret = SQLDriverConnect(dbc, (SQLHWND)&types, (SQLWCHAR *)CONN_STR,
sizeof(CONN_STR) / sizeof(CONN_STR[0]) - 1, NULL, 0, NULL,
ESODBC_SQL_DRIVER_TEST);
assert(SQL_SUCCEEDED(ret));
ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
assert(SQL_SUCCEEDED(ret));
assert(stmt != NULL);

prepareStatement(json_answer);

SQLWCHAR col_name[sizeof(COL_NAME)];
SQLSMALLINT col_name_len, sql_type, scale, nullable;
SQLULEN col_size;
/* text column */
ret = SQLDescribeCol(stmt, /*col#*/1, col_name, sizeof(col_name),
&col_name_len, &sql_type, &col_size, &scale, &nullable);
ASSERT_TRUE(SQL_SUCCEEDED(ret));
ASSERT_EQ(col_name_len, sizeof(COL_NAME) - 1);
ASSERT_STREQ(col_name, MK_WPTR(COL_NAME));
ASSERT_EQ(sql_type, ES_WVARCHAR_SQL);
ASSERT_EQ(col_size, VARCHAR_LIMIT); /* limit enforced */
ASSERT_EQ(nullable, SQL_NULLABLE_UNKNOWN);

/* binary column */
ret = SQLDescribeCol(stmt, /*col#*/2, col_name, sizeof(col_name),
&col_name_len, &sql_type, &col_size, &scale, &nullable);
ASSERT_TRUE(SQL_SUCCEEDED(ret));
ASSERT_EQ(col_size, INT_MAX); /* binary col's length must not be affected */
}

} // test namespace

Expand Down