Skip to content

Commit 290e287

Browse files
authored
Update type selection for string parameters (#218)
* proper cleans all builds When invoking 'proper', the build script now invokes the build scripts for both x86 and x64, if any of them are present. * inc uninstallation timeout while integ-testing wmi application used to uninstall driver by name during integration testing can take over 1.5 minutes on slower VMs with many installed applications. * extend logging buffers for (CBOR) hex printers When extended logging debugging define is enabled, the hex dumping of binary buffers (used for CBOR replies logging) are now also dynamically allocated and significantly larger (4k -> 4M). This allows easier troubleshooting. * change the ES type selection for text parameters This commit changes the way a parameter's SQL type is resolved to an ES type. So far, the size of the parameter was taking into account, to select the ES type with the lowest "precision" that would accomodate it. This worked well so far because IP type was having a precision of 0. This precision for IP type had been updated in Elasticsearch (to maximum IP length), which would lead to the driver tagging small length strings as IP types. With current change, all string type parameterss are considered as TEXT types, leaving Elasticsearch/SQL to apply a better, context-informed conversion.
1 parent 6096873 commit 290e287

File tree

12 files changed

+126
-69
lines changed

12 files changed

+126
-69
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ installer/src/Installer/driver/
88
dsneditor/EsOdbcDsnEditor/Debug/
99
dsneditor/EsOdbcDsnEditorLauncher/bin/
1010
dsneditor/EsOdbcDsnEditorLauncher/obj/
11+
libs/zlib/zlib.lib
1112

1213
# User-specific files
1314
*.suo

build.bat

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -334,11 +334,17 @@ REM CTESTS function: run CI testing
334334
REM PROPER function: clean up the build and libs dir.
335335
:PROPER
336336
echo %~nx0: cleaning libs.
337-
if exist %BUILD_DIR%\zlibclean.vcxproj (
338-
MSBuild %BUILD_DIR%\zlibclean.vcxproj
337+
if exist %BUILDS_DIR%\x86\zlibclean.vcxproj (
338+
MSBuild %BUILDS_DIR%\x86\zlibclean.vcxproj
339339
)
340-
if exist %BUILD_DIR%\curlclean.vcxproj (
341-
MSBuild %BUILD_DIR%\curlclean.vcxproj
340+
if exist %BUILDS_DIR%\x64\zlibclean.vcxproj (
341+
MSBuild %BUILDS_DIR%\x64\zlibclean.vcxproj
342+
)
343+
if exist %BUILDS_DIR%\x86\curlclean.vcxproj (
344+
MSBuild %BUILDS_DIR%\x86\curlclean.vcxproj
345+
)
346+
if exist %BUILDS_DIR%\x64\curlclean.vcxproj (
347+
MSBuild %BUILDS_DIR%\x64\curlclean.vcxproj
342348
)
343349
call:CLEAN
344350
REM delete VisualStudio files

driver/connect.c

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2581,26 +2581,36 @@ static void set_es_types(esodbc_dbc_st *dbc, SQLULEN rows_fetched,
25812581
esodbc_estype_st *types)
25822582
{
25832583
SQLULEN i;
2584+
SQLINTEGER max_float_size, max_varchar_size;
25842585

2585-
assert(!dbc->max_float_size && !dbc->max_varchar_size);
2586+
dbc->es_types = types;
2587+
dbc->no_types = rows_fetched;
2588+
2589+
assert(dbc->max_float_type == NULL);
2590+
assert(dbc->max_varchar_type == NULL);
25862591

25872592
for (i = 0; i < rows_fetched; i ++) {
25882593
if (types[i].data_type == SQL_FLOAT) {
2589-
if (dbc->max_float_size < types[i].column_size) {
2590-
dbc->max_float_size = types[i].column_size;
2594+
max_float_size = dbc->max_float_type ?
2595+
dbc->max_float_type->column_size : 0;
2596+
if (max_float_size < types[i].column_size) {
2597+
dbc->max_float_type = &types[i];
25912598
}
25922599
} else if (types[i].data_type == SQL_VARCHAR) {
2593-
if (dbc->max_varchar_size < types[i].column_size) {
2594-
dbc->max_varchar_size = types[i].column_size;
2600+
max_varchar_size = dbc->max_varchar_type ?
2601+
dbc->max_varchar_type->column_size : 0;
2602+
if (max_varchar_size < types[i].column_size) {
2603+
dbc->max_varchar_type = &types[i];
25952604
}
25962605
}
25972606
}
25982607

2599-
DBGH(dbc, "%llu ES/SQL types available, maximum sizes supported for: "
2600-
"SQL_FLOAT: %ld, SQL_VARCHAR: %ld.", rows_fetched,
2601-
dbc->max_float_size, dbc->max_varchar_size);
2602-
dbc->es_types = types;
2603-
dbc->no_types = rows_fetched;
2608+
assert(dbc->max_float_type);
2609+
assert(dbc->max_varchar_type);
2610+
2611+
DBGH(dbc, "%lu ES/SQL types available, maximum sizes supported for: "
2612+
"SQL_FLOAT: %ld, SQL_VARCHAR: %ld.", (unsigned long)rows_fetched,
2613+
dbc->max_float_type->column_size, dbc->max_varchar_type->column_size);
26042614
}
26052615

26062616
/*

driver/defs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
/* Tracing log buffer size. */
1515
#define ESODBC_LOG_BUF_SIZE (4 * 1024)
16+
#ifdef WITH_EXTENDED_BUFF_LOG
17+
# define ESODBC_EXT_LOG_BUF_SIZE (ESODBC_LOG_BUF_SIZE * 1024)
18+
#endif /* WITH_EXTENDED_BUFF_LOG */
1619
/* Log file prefix. The format is: prefix_datime */
1720
#define ESODBC_LOG_FILE_PREFIX "esodbc"
1821
#define ESODBC_LOG_FILE_SUFFIX ".log"

driver/handles.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2281,7 +2281,7 @@ static BOOL consistency_check(esodbc_rec_st *rec)
22812281
dbc = HDRH(HDRH(desc)->stmt)->dbc;
22822282
if (rec->concise_type == SQL_FLOAT) {
22832283
assert(desc->type == DESC_TYPE_IPD);
2284-
column_size = dbc->max_float_size;
2284+
column_size = dbc->max_float_type->column_size;
22852285
} else {
22862286
if (DESC_TYPE_IS_APPLICATION(desc->type)) {
22872287
concise_type = sqlctype_to_es(rec->concise_type);

driver/handles.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ typedef struct struct_dbc {
173173
esodbc_estype_st *es_types; /* array with ES types */
174174
SQLULEN no_types; /* number of types in array */
175175
/* maximum precision/length of types using same SQL data type ID */
176-
SQLINTEGER max_float_size;
177-
SQLINTEGER max_varchar_size;
176+
esodbc_estype_st *max_varchar_type; /* pointer to TEXT type */
177+
esodbc_estype_st *max_float_type; /* pointer to DOUBLE type */
178178

179179
CURL *curl; /* cURL handle */
180180
CURLcode curl_err;

driver/log.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
esodbc_filelog_st *_gf_log = NULL;
3333

3434
#ifdef WITH_EXTENDED_BUFF_LOG
35-
#define ESODBC_EXT_LOG_BUF_SIZE (ESODBC_LOG_BUF_SIZE * 1024)
3635
static char **log_buffs = NULL;
3736
static size_t log_buffs_cnt = 0;
3837
static esodbc_mutex_lt log_buffs_mux = ESODBC_MUX_SINIT;
@@ -111,6 +110,7 @@ void log_cleanup()
111110
free(log_buffs);
112111
log_buffs = NULL;
113112
log_buffs_cnt = 0;
113+
ESODBC_MUX_DEL(&log_buffs_mux);
114114
}
115115
# endif /* WITH_EXTENDED_BUFF_LOG */
116116

driver/odbc.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ static void driver_cleanup()
5757
{
5858
connect_cleanup();
5959
tinycbor_cleanup();
60+
61+
# ifdef WITH_EXTENDED_BUFF_LOG
62+
cstr_hex_dump(NULL); /* util.[ch] */
63+
# endif /* WITH_EXTENDED_BUFF_LOG */
6064
}
6165

6266
BOOL WINAPI DllMain(

driver/queries.c

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,7 +1305,10 @@ SQLRETURN copy_one_row_json(esodbc_stmt_st *stmt, SQLULEN pos)
13051305

13061306
ard = stmt->ard;
13071307
ird = stmt->ird;
1308-
rowno = stmt->tv_rows + /* current not yet counted */1;
1308+
rowno = stmt->tv_rows
1309+
+ STMT_GD_CALLING(stmt)
1310+
? /* SQLFetch() executed already, row counted */0
1311+
: /* SQLFetch() in progress, current row not yet counted */1;
13091312

13101313
with_info = FALSE;
13111314
/* iterate over the bound cols of one (table) row */
@@ -1496,7 +1499,10 @@ static SQLRETURN copy_one_row_cbor(esodbc_stmt_st *stmt, SQLULEN pos)
14961499

14971500
ard = stmt->ard;
14981501
ird = stmt->ird;
1499-
rowno = stmt->tv_rows + /* current row not yet counted */1;
1502+
rowno = stmt->tv_rows
1503+
+ STMT_GD_CALLING(stmt)
1504+
? /* SQLFetch() executed already, row counted */0
1505+
: /* SQLFetch() in progress, current row not yet counted */1;
15001506

15011507
with_info = FALSE;
15021508
/* iterate over the bound cols and contents of one (table) row */
@@ -2425,30 +2431,33 @@ SQLRETURN EsSQLPrepareW
24252431

24262432

24272433
/* Find the ES/SQL type given in es_type; for ID matching multiple types
2428-
* (scaled/half_float and keyword/text) use the best matching col_size, which
2429-
* is the smallest, that's still matching (<=) the given one. This assumes the
2430-
* types are ordered by it (as per the spec). */
2434+
* (scaled/half_float), but not keyword/text, use the best matching col_size,
2435+
* which is the smallest, that's still matching (<=) the given one. This
2436+
* assumes the types are ordered by it (as per the spec). */
24312437
esodbc_estype_st *lookup_es_type(esodbc_dbc_st *dbc,
24322438
SQLSMALLINT es_type, SQLULEN col_size)
24332439
{
24342440
SQLULEN i;
2441+
SQLINTEGER sz;
24352442

2443+
/* for strings, choose text straight away: some type (IP, GEO) must coform
2444+
* to a format and no content inspection is done in the driver */
2445+
if (es_type == SQL_VARCHAR) {
2446+
return dbc->max_varchar_type;
2447+
}
24362448
for (i = 0; i < dbc->no_types; i ++) {
24372449
if (dbc->es_types[i].data_type == es_type) {
24382450
if (col_size <= 0) {
24392451
return &dbc->es_types[i];
24402452
} else {
2453+
sz = dbc->es_types[i].column_size;
24412454
assert(col_size < LONG_MAX);
2442-
if ((SQLINTEGER)col_size <= dbc->es_types[i].column_size) {
2443-
return &dbc->es_types[i];
2444-
}
2445-
if (es_type == SQL_VARCHAR &&
2446-
dbc->es_types[i].column_size == dbc->max_varchar_size) {
2455+
if ((SQLINTEGER)col_size <= sz) {
24472456
return &dbc->es_types[i];
24482457
}
24492458
if (es_type == SQL_FLOAT &&
2450-
dbc->es_types[i].column_size == dbc->max_float_size) {
2451-
return &dbc->es_types[i];
2459+
sz == dbc->max_float_type->column_size) {
2460+
return dbc->max_float_type;
24522461
}
24532462
}
24542463
}
@@ -2460,51 +2469,44 @@ esodbc_estype_st *lookup_es_type(esodbc_dbc_st *dbc,
24602469

24612470
/* find the matching ES/SQL type for app's SQL type, which can be an exact
24622471
* match against ES/SQL types, but also some other valid SQL type. */
2463-
static esodbc_estype_st *match_es_type(esodbc_rec_st *arec,
2464-
esodbc_rec_st *irec)
2472+
static esodbc_estype_st *match_es_type(esodbc_rec_st *irec)
24652473
{
2466-
SQLULEN i, length;
2467-
esodbc_dbc_st *dbc = arec->desc->hdr.stmt->hdr.dbc;
2474+
SQLULEN i;
2475+
SQLINTEGER col_sz;
2476+
esodbc_dbc_st *dbc = irec->desc->hdr.stmt->hdr.dbc;
24682477

24692478
for (i = 0; i < dbc->no_types; i ++) {
24702479
if (dbc->es_types[i].data_type == irec->concise_type) {
24712480
switch (irec->concise_type) {
2472-
/* For SQL types mappign to more than one ES/SQL type, choose
2481+
/* For SQL types mapping to more than one ES/SQL type, choose
24732482
* the ES/SQL type with smallest "size" that covers user given
24742483
* precision OR that has maximum precision (in case user's is
24752484
* larger than max ES/SQL offers. */
24762485
case SQL_FLOAT: /* HALF_FLOAT, SCALED_FLOAT */
2477-
if (irec->precision <= dbc->es_types[i].column_size ||
2478-
dbc->es_types[i].column_size == dbc->max_float_size) {
2479-
return &dbc->es_types[i];
2480-
}
2481-
break;
2482-
case SQL_VARCHAR: /* KEYWORD, TEXT */
2483-
length = irec->length ? irec->length : arec->octet_length;
2484-
assert(length < LONG_MAX);
2485-
if ((SQLINTEGER)length <= dbc->es_types[i].column_size ||
2486-
dbc->es_types[i].column_size==dbc->max_varchar_size) {
2486+
col_sz = dbc->es_types[i].column_size;
2487+
if (irec->precision <= col_sz ||
2488+
col_sz == dbc->max_float_type->column_size) {
24872489
return &dbc->es_types[i];
24882490
}
24892491
break;
2492+
case SQL_VARCHAR: /* IP, CONSTANT_KEYWORD, KEYWORD, TEXT */
2493+
return lookup_es_type(dbc, SQL_VARCHAR, irec->precision);
24902494
default:
24912495
/* unequivocal match */
24922496
return &dbc->es_types[i];
24932497
}
24942498
}
24952499
}
24962500

2497-
/* app specified an SQL type with no direct mapping to an ES/SQL type
2498-
* TODO: IP, GEO? */
2501+
/* app specified an SQL type with no direct mapping to an ES/SQL type */
24992502
switch (irec->meta_type) {
25002503
case METATYPE_EXACT_NUMERIC:
25012504
assert(irec->concise_type == SQL_DECIMAL ||
25022505
irec->concise_type == SQL_NUMERIC);
25032506
return lookup_es_type(dbc, SQL_FLOAT, irec->precision);
25042507

25052508
case METATYPE_STRING:
2506-
length = irec->length ? irec->length : arec->octet_length;
2507-
return lookup_es_type(dbc, SQL_VARCHAR, length);
2509+
return lookup_es_type(dbc, SQL_VARCHAR, irec->precision);
25082510
case METATYPE_BIN:
25092511
return lookup_es_type(dbc, SQL_BINARY, /*no prec*/0);
25102512
case METATYPE_DATE_TIME:
@@ -2698,7 +2700,7 @@ SQLRETURN EsSQLBindParameter(
26982700
}
26992701

27002702
arec = get_record(stmt->apd, ParameterNumber, /*grow?*/FALSE);
2701-
irec->es_type = match_es_type(arec, irec);
2703+
irec->es_type = match_es_type(irec);
27022704
if (! irec->es_type) {
27032705
/* validation shoudl have been done earlier on meta type setting
27042706
* (SQL_DESC_CONCISE_TYPE) */

driver/util.c

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -741,13 +741,39 @@ BOOL TEST_API metadata_id_escape(wstr_st *src, wstr_st *dst, BOOL force)
741741
* Returns (thread local static) printed buffer, always 0-term'd. */
742742
char *cstr_hex_dump(const cstr_st *buff)
743743
{
744+
# ifndef WITH_EXTENDED_BUFF_LOG
744745
static thread_local char dest[ESODBC_LOG_BUF_SIZE];
746+
const size_t dest_sz = sizeof(dest);
747+
# else /* !WITH_EXTENDED_BUFF_LOG */
748+
static char *dest = NULL;
749+
static esodbc_mutex_lt dest_mux = ESODBC_MUX_SINIT;
750+
const size_t dest_sz = ESODBC_EXT_LOG_BUF_SIZE;
751+
# endif /* !WITH_EXTENDED_BUFF_LOG */
745752
char *to, *from;
746753
char *to_end, *from_end;
747754
int n;
748755

756+
757+
# ifdef WITH_EXTENDED_BUFF_LOG
758+
ESODBC_MUX_LOCK(&dest_mux);
759+
if (! buff) { /* free resorces */
760+
if (dest) {
761+
free(dest);
762+
dest = NULL;
763+
}
764+
ESODBC_MUX_DEL(&dest_mux);
765+
goto end;
766+
} else if (! dest) {
767+
if (! (dest = malloc(dest_sz))) {
768+
ERRN("OOM for %zd bytes.", dest_sz);
769+
ESODBC_MUX_UNLOCK(&dest_mux);
770+
return "<OOM>";
771+
}
772+
}
773+
# endif /* WITH_EXTENDED_BUFF_LOG */
774+
749775
to = dest;
750-
to_end = dest + sizeof(dest);
776+
to_end = dest + dest_sz;
751777
from = buff->str;
752778
from_end = buff->str + buff->cnt;
753779
int i = 0;
@@ -761,10 +787,15 @@ char *cstr_hex_dump(const cstr_st *buff)
761787
}
762788
/* add the 0-terminator */
763789
if (to < to_end) { /* still space for it? */
764-
*to ++ = 0;
790+
*to ++ = '\0';
765791
} else { /* == */
766-
dest[sizeof(dest) - 1] = 0; /* overwrite last position */
792+
dest[dest_sz - 1] = '\0'; /* overwrite last position */
767793
}
794+
795+
# ifdef WITH_EXTENDED_BUFF_LOG
796+
end:
797+
ESODBC_MUX_UNLOCK(&dest_mux);
798+
# endif /* WITH_EXTENDED_BUFF_LOG */
768799
return dest;
769800
}
770801

test/integration/install.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
from elasticsearch import Elasticsearch
1717

1818
DRIVER_BASE_NAME = "Elasticsearch ODBC Driver"
19-
# Uninstallation can take quite a long time (over 10s)
20-
INSTALLATION_TIMEOUT = 60
19+
# Uninstallation can take quite a long time on VMs
20+
INSTALLATION_TIMEOUT = 120
2121

2222
class Installer(object):
2323
_driver_path = None

0 commit comments

Comments
 (0)