Skip to content

Commit 5a1d4be

Browse files
authored
Implement an early execution mode (#227)
This commit adds an early execution mode for prepared queries. Applications generally prepare a statement, optionally reading result set attributes - like columns count and their characteristics (types and names) - before executing. A subset of these apps (generally the ones following older API usage patterns) will fail the entire operation if these column characteristics aren't available before execution. Elasticsearch/SQL doesn't support the concept of prepared statements. What the driver will now do if this mode is enabled (=the new default) is to execute the query right away, in case this lacks any parameters. In case the parameter marks are present, the early execution is disabled for the statement (and potentially the query will fail). However, most patterns of Elasticsearch/ODBC usage don't involve paramters and/or repeated executions. This change should allow more applications interop with Elasticsearch/SQL.
1 parent 290e287 commit 5a1d4be

File tree

7 files changed

+60
-3
lines changed

7 files changed

+60
-3
lines changed

driver/connect.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,6 +1402,9 @@ SQLRETURN config_dbc(esodbc_dbc_st *dbc, esodbc_dsn_attrs_st *attrs)
14021402
/* "apply TZ" param for time conversions */
14031403
dbc->apply_tz = wstr2bool(&attrs->apply_tz);
14041404
INFOH(dbc, "apply TZ: %s.", dbc->apply_tz ? "true" : "false");
1405+
/* early execution */
1406+
dbc->early_exec = wstr2bool(&attrs->early_exec);
1407+
INFOH(dbc, "early execution: %s.", dbc->early_exec ? "true" : "false");
14051408

14061409
/* how to print the floats? */
14071410
assert(1 <= attrs->sci_floats.cnt); /* default should apply */

driver/defs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@
176176
#define ESODBC_DEF_TRACE_LEVEL "WARN"
177177
/* default TZ handling */
178178
#define ESODBC_DEF_APPLY_TZ "no"
179+
/* default early execution flag */
180+
#define ESODBC_DEF_EARLY_EXEC "yes"
179181
/* default of scientific floats printing */
180182
#define ESODBC_DEF_SCI_FLOATS ESODBC_DSN_FLTS_DEF
181183
#define ESODBC_PWD_VAL_SUBST "<redacted>"

driver/dsn.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ int assign_dsn_attr(esodbc_dsn_attrs_st *attrs,
7676
{&MK_WSTR(ESODBC_DSN_MAX_FETCH_SIZE), &attrs->max_fetch_size},
7777
{&MK_WSTR(ESODBC_DSN_MAX_BODY_SIZE_MB), &attrs->max_body_size},
7878
{&MK_WSTR(ESODBC_DSN_APPLY_TZ), &attrs->apply_tz},
79+
{&MK_WSTR(ESODBC_DSN_EARLY_EXEC), &attrs->early_exec},
7980
{&MK_WSTR(ESODBC_DSN_SCI_FLOATS), &attrs->sci_floats},
8081
{&MK_WSTR(ESODBC_DSN_VERSION_CHECKING), &attrs->version_checking},
8182
{&MK_WSTR(ESODBC_DSN_MFIELD_LENIENT), &attrs->mfield_lenient},
@@ -411,6 +412,7 @@ long TEST_API write_00_list(esodbc_dsn_attrs_st *attrs,
411412
{&MK_WSTR(ESODBC_DSN_MAX_FETCH_SIZE), &attrs->max_fetch_size},
412413
{&MK_WSTR(ESODBC_DSN_MAX_BODY_SIZE_MB), &attrs->max_body_size},
413414
{&MK_WSTR(ESODBC_DSN_APPLY_TZ), &attrs->apply_tz},
415+
{&MK_WSTR(ESODBC_DSN_EARLY_EXEC), &attrs->early_exec},
414416
{&MK_WSTR(ESODBC_DSN_SCI_FLOATS), &attrs->sci_floats},
415417
{&MK_WSTR(ESODBC_DSN_VERSION_CHECKING), &attrs->version_checking},
416418
{&MK_WSTR(ESODBC_DSN_MFIELD_LENIENT), &attrs->mfield_lenient},
@@ -675,6 +677,10 @@ BOOL write_system_dsn(esodbc_dsn_attrs_st *new_attrs,
675677
&MK_WSTR(ESODBC_DSN_APPLY_TZ), &new_attrs->apply_tz,
676678
old_attrs ? &old_attrs->apply_tz : NULL
677679
},
680+
{
681+
&MK_WSTR(ESODBC_DSN_EARLY_EXEC), &new_attrs->early_exec,
682+
old_attrs ? &old_attrs->early_exec : NULL
683+
},
678684
{
679685
&MK_WSTR(ESODBC_DSN_SCI_FLOATS), &new_attrs->sci_floats,
680686
old_attrs ? &old_attrs->sci_floats : NULL
@@ -786,6 +792,7 @@ long TEST_API write_connection_string(esodbc_dsn_attrs_st *attrs,
786792
{&attrs->max_fetch_size, &MK_WSTR(ESODBC_DSN_MAX_FETCH_SIZE)},
787793
{&attrs->max_body_size, &MK_WSTR(ESODBC_DSN_MAX_BODY_SIZE_MB)},
788794
{&attrs->apply_tz, &MK_WSTR(ESODBC_DSN_APPLY_TZ)},
795+
{&attrs->early_exec, &MK_WSTR(ESODBC_DSN_EARLY_EXEC)},
789796
{&attrs->sci_floats, &MK_WSTR(ESODBC_DSN_SCI_FLOATS)},
790797
{&attrs->version_checking, &MK_WSTR(ESODBC_DSN_VERSION_CHECKING)},
791798
{&attrs->mfield_lenient, &MK_WSTR(ESODBC_DSN_MFIELD_LENIENT)},
@@ -884,6 +891,9 @@ void assign_dsn_defaults(esodbc_dsn_attrs_st *attrs)
884891
res |= assign_dsn_attr(attrs,
885892
&MK_WSTR(ESODBC_DSN_APPLY_TZ), &MK_WSTR(ESODBC_DEF_APPLY_TZ),
886893
/*overwrite?*/FALSE);
894+
res |= assign_dsn_attr(attrs,
895+
&MK_WSTR(ESODBC_DSN_EARLY_EXEC), &MK_WSTR(ESODBC_DEF_EARLY_EXEC),
896+
/*overwrite?*/FALSE);
887897
res |= assign_dsn_attr(attrs,
888898
&MK_WSTR(ESODBC_DSN_SCI_FLOATS), &MK_WSTR(ESODBC_DEF_SCI_FLOATS),
889899
/*overwrite?*/FALSE);

driver/dsn.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#define ESODBC_DSN_MAX_FETCH_SIZE "MaxFetchSize"
3636
#define ESODBC_DSN_MAX_BODY_SIZE_MB "MaxBodySizeMB"
3737
#define ESODBC_DSN_APPLY_TZ "ApplyTZ"
38+
#define ESODBC_DSN_EARLY_EXEC "EarlyExecution"
3839
#define ESODBC_DSN_SCI_FLOATS "ScientificFloats"
3940
#define ESODBC_DSN_VERSION_CHECKING "VersionChecking"
4041
#define ESODBC_DSN_MFIELD_LENIENT "MultiFieldLenient"
@@ -78,6 +79,7 @@ typedef struct {
7879
wstr_st max_fetch_size;
7980
wstr_st max_body_size;
8081
wstr_st apply_tz;
82+
wstr_st early_exec;
8183
wstr_st sci_floats;
8284
wstr_st version_checking;
8385
wstr_st mfield_lenient;
@@ -86,7 +88,7 @@ typedef struct {
8688
wstr_st trace_enabled;
8789
wstr_st trace_file;
8890
wstr_st trace_level;
89-
#define ESODBC_DSN_ATTRS_COUNT 28
91+
#define ESODBC_DSN_ATTRS_COUNT 29
9092
SQLWCHAR buff[ESODBC_DSN_ATTRS_COUNT * ESODBC_DSN_MAX_ATTR_LEN];
9193
/* DSN reading/writing functions are passed a SQLSMALLINT lenght param */
9294
#if SHRT_MAX < ESODBC_DSN_ATTRS_COUNT * ESODBC_DSN_MAX_ATTR_LEN

driver/handles.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ static void init_stmt(esodbc_stmt_st *stmt, SQLHANDLE InputHandle)
170170
* set at connection level. */
171171
stmt->metadata_id = DBCH(InputHandle)->metadata_id;
172172
stmt->sql2c_conversion = CONVERSION_UNCHECKED;
173+
stmt->early_executed = FALSE;
173174
}
174175

175176
void dump_record(esodbc_rec_st *rec)

driver/handles.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ typedef struct struct_dbc {
161161
ESODBC_CMPSS_AUTO,
162162
} compression;
163163
BOOL apply_tz; /* should the times be converted from UTC to local TZ? */
164+
BOOL early_exec; /* should prepared, non-param queries be exec'd early? */
164165
enum {
165166
ESODBC_FLTS_DEFAULT = 0,
166167
ESODBC_FLTS_SCIENTIFIC,
@@ -391,6 +392,8 @@ typedef struct struct_stmt {
391392
CONVERSION_SUPPORTED,
392393
CONVERSION_SKIPPED, /* used with driver's meta queries */
393394
} sql2c_conversion;
395+
/* early execution */
396+
BOOL early_executed;
394397

395398
/* SQLGetData state members */
396399
SQLINTEGER gd_col; /* current column to get from, if positive */

driver/queries.c

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
/* fwd decl */
4040
static SQLRETURN statement_params_len_cbor(esodbc_stmt_st *stmt,
4141
size_t *enc_len, size_t *conv_len);
42+
static SQLRETURN count_param_markers(esodbc_stmt_st *stmt, SQLSMALLINT *p_cnt);
4243

4344
static thread_local cstr_st tz_param;
4445
static cstr_st version = CSTR_INIT(STR(DRV_VERSION)); /* build-time define */
@@ -1103,6 +1104,7 @@ SQLRETURN TEST_API attach_sql(esodbc_stmt_st *stmt,
11031104
/* if the app correctly SQL_CLOSE'es the statement, this would not be
11041105
* needed. but just in case: re-init counter of total # of rows and sets */
11051106
STMT_ROW_CNT_RESET(stmt);
1107+
stmt->early_executed = false;
11061108

11071109
return SQL_SUCCESS;
11081110
}
@@ -2413,6 +2415,7 @@ SQLRETURN EsSQLPrepareW
24132415
{
24142416
esodbc_stmt_st *stmt = STMH(hstmt);
24152417
SQLRETURN ret;
2418+
SQLSMALLINT markers;
24162419

24172420
if (cchSqlStr == SQL_NTS) {
24182421
cchSqlStr = (SQLINTEGER)wcslen(szSqlStr);
@@ -2426,7 +2429,29 @@ SQLRETURN EsSQLPrepareW
24262429
ret = EsSQLFreeStmt(stmt, ESODBC_SQL_CLOSE);
24272430
assert(SQL_SUCCEEDED(ret)); /* can't return error */
24282431

2429-
return attach_sql(stmt, szSqlStr, cchSqlStr);
2432+
ret = attach_sql(stmt, szSqlStr, cchSqlStr);
2433+
/* if early execution mode is on and the statement has no parameter
2434+
* markers, execute the query right away */
2435+
if (HDRH(stmt)->dbc->early_exec && SQL_SUCCEEDED(ret)) {
2436+
assert(! stmt->early_executed); /* cleared by now */
2437+
if (! SQL_SUCCEEDED(count_param_markers(stmt, &markers))) {
2438+
ERRH(stmt, "failed to count parameter markers in query. "
2439+
"Early execution disabled.");
2440+
/* clear set diagnostic */
2441+
init_diagnostic(&HDRH(stmt)->diag);
2442+
return ret;
2443+
}
2444+
if (0 < markers) {
2445+
INFOH(stmt, "query contains %hd parameter markers -- early "
2446+
"execution disabled.", markers);
2447+
return ret;
2448+
}
2449+
ret = EsSQLExecute(hstmt);
2450+
if (SQL_SUCCEEDED(ret)) {
2451+
stmt->early_executed = true;
2452+
}
2453+
}
2454+
return ret;
24302455
}
24312456

24322457

@@ -3606,7 +3631,18 @@ SQLRETURN EsSQLExecute(SQLHSTMT hstmt)
36063631
char buff[ESODBC_BODY_BUF_START_SIZE];
36073632
cstr_st body = {buff, sizeof(buff)};
36083633

3609-
DBGH(stmt, "executing SQL: [%zd] `" LCPDL "`.", stmt->u8sql.cnt,
3634+
if (stmt->early_executed) {
3635+
stmt->early_executed = false; /* re-enable subsequent executions */
3636+
if (STMT_HAS_RESULTSET(stmt)) {
3637+
DBGH(stmt, "query early executed: [%zd] `" LCPDL "`.",
3638+
stmt->u8sql.cnt, LCSTR(&stmt->u8sql));
3639+
return SQL_SUCCESS;
3640+
} else {
3641+
WARNH(stmt, "query `" LCPDL "` early executed, but lacking result"
3642+
" set.", LCSTR(&stmt->u8sql));
3643+
}
3644+
}
3645+
DBGH(stmt, "executing query: [%zd] `" LCPDL "`.", stmt->u8sql.cnt,
36103646
LCSTR(&stmt->u8sql));
36113647

36123648
ret = serialize_statement(stmt, &body);

0 commit comments

Comments
 (0)