Skip to content

Add an early execution mode for prepared statements #227

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 24, 2020
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
3 changes: 3 additions & 0 deletions driver/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -1402,6 +1402,9 @@ SQLRETURN config_dbc(esodbc_dbc_st *dbc, esodbc_dsn_attrs_st *attrs)
/* "apply TZ" param for time conversions */
dbc->apply_tz = wstr2bool(&attrs->apply_tz);
INFOH(dbc, "apply TZ: %s.", dbc->apply_tz ? "true" : "false");
/* early execution */
dbc->early_exec = wstr2bool(&attrs->early_exec);
INFOH(dbc, "early execution: %s.", dbc->early_exec ? "true" : "false");

/* how to print the floats? */
assert(1 <= attrs->sci_floats.cnt); /* default should apply */
Expand Down
2 changes: 2 additions & 0 deletions driver/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@
#define ESODBC_DEF_TRACE_LEVEL "WARN"
/* default TZ handling */
#define ESODBC_DEF_APPLY_TZ "no"
/* default early execution flag */
#define ESODBC_DEF_EARLY_EXEC "yes"
/* default of scientific floats printing */
#define ESODBC_DEF_SCI_FLOATS ESODBC_DSN_FLTS_DEF
#define ESODBC_PWD_VAL_SUBST "<redacted>"
Expand Down
10 changes: 10 additions & 0 deletions driver/dsn.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ int assign_dsn_attr(esodbc_dsn_attrs_st *attrs,
{&MK_WSTR(ESODBC_DSN_MAX_FETCH_SIZE), &attrs->max_fetch_size},
{&MK_WSTR(ESODBC_DSN_MAX_BODY_SIZE_MB), &attrs->max_body_size},
{&MK_WSTR(ESODBC_DSN_APPLY_TZ), &attrs->apply_tz},
{&MK_WSTR(ESODBC_DSN_EARLY_EXEC), &attrs->early_exec},
{&MK_WSTR(ESODBC_DSN_SCI_FLOATS), &attrs->sci_floats},
{&MK_WSTR(ESODBC_DSN_VERSION_CHECKING), &attrs->version_checking},
{&MK_WSTR(ESODBC_DSN_MFIELD_LENIENT), &attrs->mfield_lenient},
Expand Down Expand Up @@ -411,6 +412,7 @@ long TEST_API write_00_list(esodbc_dsn_attrs_st *attrs,
{&MK_WSTR(ESODBC_DSN_MAX_FETCH_SIZE), &attrs->max_fetch_size},
{&MK_WSTR(ESODBC_DSN_MAX_BODY_SIZE_MB), &attrs->max_body_size},
{&MK_WSTR(ESODBC_DSN_APPLY_TZ), &attrs->apply_tz},
{&MK_WSTR(ESODBC_DSN_EARLY_EXEC), &attrs->early_exec},
{&MK_WSTR(ESODBC_DSN_SCI_FLOATS), &attrs->sci_floats},
{&MK_WSTR(ESODBC_DSN_VERSION_CHECKING), &attrs->version_checking},
{&MK_WSTR(ESODBC_DSN_MFIELD_LENIENT), &attrs->mfield_lenient},
Expand Down Expand Up @@ -675,6 +677,10 @@ BOOL write_system_dsn(esodbc_dsn_attrs_st *new_attrs,
&MK_WSTR(ESODBC_DSN_APPLY_TZ), &new_attrs->apply_tz,
old_attrs ? &old_attrs->apply_tz : NULL
},
{
&MK_WSTR(ESODBC_DSN_EARLY_EXEC), &new_attrs->early_exec,
old_attrs ? &old_attrs->early_exec : NULL
},
{
&MK_WSTR(ESODBC_DSN_SCI_FLOATS), &new_attrs->sci_floats,
old_attrs ? &old_attrs->sci_floats : NULL
Expand Down Expand Up @@ -786,6 +792,7 @@ long TEST_API write_connection_string(esodbc_dsn_attrs_st *attrs,
{&attrs->max_fetch_size, &MK_WSTR(ESODBC_DSN_MAX_FETCH_SIZE)},
{&attrs->max_body_size, &MK_WSTR(ESODBC_DSN_MAX_BODY_SIZE_MB)},
{&attrs->apply_tz, &MK_WSTR(ESODBC_DSN_APPLY_TZ)},
{&attrs->early_exec, &MK_WSTR(ESODBC_DSN_EARLY_EXEC)},
{&attrs->sci_floats, &MK_WSTR(ESODBC_DSN_SCI_FLOATS)},
{&attrs->version_checking, &MK_WSTR(ESODBC_DSN_VERSION_CHECKING)},
{&attrs->mfield_lenient, &MK_WSTR(ESODBC_DSN_MFIELD_LENIENT)},
Expand Down Expand Up @@ -884,6 +891,9 @@ void assign_dsn_defaults(esodbc_dsn_attrs_st *attrs)
res |= assign_dsn_attr(attrs,
&MK_WSTR(ESODBC_DSN_APPLY_TZ), &MK_WSTR(ESODBC_DEF_APPLY_TZ),
/*overwrite?*/FALSE);
res |= assign_dsn_attr(attrs,
&MK_WSTR(ESODBC_DSN_EARLY_EXEC), &MK_WSTR(ESODBC_DEF_EARLY_EXEC),
/*overwrite?*/FALSE);
res |= assign_dsn_attr(attrs,
&MK_WSTR(ESODBC_DSN_SCI_FLOATS), &MK_WSTR(ESODBC_DEF_SCI_FLOATS),
/*overwrite?*/FALSE);
Expand Down
4 changes: 3 additions & 1 deletion driver/dsn.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#define ESODBC_DSN_MAX_FETCH_SIZE "MaxFetchSize"
#define ESODBC_DSN_MAX_BODY_SIZE_MB "MaxBodySizeMB"
#define ESODBC_DSN_APPLY_TZ "ApplyTZ"
#define ESODBC_DSN_EARLY_EXEC "EarlyExecution"
#define ESODBC_DSN_SCI_FLOATS "ScientificFloats"
#define ESODBC_DSN_VERSION_CHECKING "VersionChecking"
#define ESODBC_DSN_MFIELD_LENIENT "MultiFieldLenient"
Expand Down Expand Up @@ -78,6 +79,7 @@ typedef struct {
wstr_st max_fetch_size;
wstr_st max_body_size;
wstr_st apply_tz;
wstr_st early_exec;
wstr_st sci_floats;
wstr_st version_checking;
wstr_st mfield_lenient;
Expand All @@ -86,7 +88,7 @@ typedef struct {
wstr_st trace_enabled;
wstr_st trace_file;
wstr_st trace_level;
#define ESODBC_DSN_ATTRS_COUNT 28
#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 */
#if SHRT_MAX < ESODBC_DSN_ATTRS_COUNT * ESODBC_DSN_MAX_ATTR_LEN
Expand Down
1 change: 1 addition & 0 deletions driver/handles.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ static void init_stmt(esodbc_stmt_st *stmt, SQLHANDLE InputHandle)
* set at connection level. */
stmt->metadata_id = DBCH(InputHandle)->metadata_id;
stmt->sql2c_conversion = CONVERSION_UNCHECKED;
stmt->early_executed = FALSE;
}

void dump_record(esodbc_rec_st *rec)
Expand Down
3 changes: 3 additions & 0 deletions driver/handles.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ typedef struct struct_dbc {
ESODBC_CMPSS_AUTO,
} compression;
BOOL apply_tz; /* should the times be converted from UTC to local TZ? */
BOOL early_exec; /* should prepared, non-param queries be exec'd early? */
enum {
ESODBC_FLTS_DEFAULT = 0,
ESODBC_FLTS_SCIENTIFIC,
Expand Down Expand Up @@ -391,6 +392,8 @@ typedef struct struct_stmt {
CONVERSION_SUPPORTED,
CONVERSION_SKIPPED, /* used with driver's meta queries */
} sql2c_conversion;
/* early execution */
BOOL early_executed;

/* SQLGetData state members */
SQLINTEGER gd_col; /* current column to get from, if positive */
Expand Down
40 changes: 38 additions & 2 deletions driver/queries.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
/* fwd decl */
static SQLRETURN statement_params_len_cbor(esodbc_stmt_st *stmt,
size_t *enc_len, size_t *conv_len);
static SQLRETURN count_param_markers(esodbc_stmt_st *stmt, SQLSMALLINT *p_cnt);

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

return SQL_SUCCESS;
}
Expand Down Expand Up @@ -2407,6 +2409,7 @@ SQLRETURN EsSQLPrepareW
{
esodbc_stmt_st *stmt = STMH(hstmt);
SQLRETURN ret;
SQLSMALLINT markers;

if (cchSqlStr == SQL_NTS) {
cchSqlStr = (SQLINTEGER)wcslen(szSqlStr);
Expand All @@ -2420,7 +2423,29 @@ SQLRETURN EsSQLPrepareW
ret = EsSQLFreeStmt(stmt, ESODBC_SQL_CLOSE);
assert(SQL_SUCCEEDED(ret)); /* can't return error */

return attach_sql(stmt, szSqlStr, cchSqlStr);
ret = attach_sql(stmt, szSqlStr, cchSqlStr);
/* if early execution mode is on and the statement has no parameter
* markers, execute the query right away */
if (HDRH(stmt)->dbc->early_exec && SQL_SUCCEEDED(ret)) {
assert(! stmt->early_executed); /* cleared by now */
if (! SQL_SUCCEEDED(count_param_markers(stmt, &markers))) {
ERRH(stmt, "failed to count parameter markers in query. "
"Early execution disabled.");
/* clear set diagnostic */
init_diagnostic(&HDRH(stmt)->diag);
return ret;
}
if (0 < markers) {
INFOH(stmt, "query contains %hd parameter markers -- early "
"execution disabled.", markers);
return ret;
}
ret = EsSQLExecute(hstmt);
if (SQL_SUCCEEDED(ret)) {
stmt->early_executed = true;
}
}
return ret;
}


Expand Down Expand Up @@ -3604,7 +3629,18 @@ SQLRETURN EsSQLExecute(SQLHSTMT hstmt)
char buff[ESODBC_BODY_BUF_START_SIZE];
cstr_st body = {buff, sizeof(buff)};

DBGH(stmt, "executing SQL: [%zd] `" LCPDL "`.", stmt->u8sql.cnt,
if (stmt->early_executed) {
stmt->early_executed = false; /* re-enable subsequent executions */
if (STMT_HAS_RESULTSET(stmt)) {
DBGH(stmt, "query early executed: [%zd] `" LCPDL "`.",
stmt->u8sql.cnt, LCSTR(&stmt->u8sql));
return SQL_SUCCESS;
} else {
WARNH(stmt, "query `" LCPDL "` early executed, but lacking result"
" set.", LCSTR(&stmt->u8sql));
}
}
DBGH(stmt, "executing query: [%zd] `" LCPDL "`.", stmt->u8sql.cnt,
LCSTR(&stmt->u8sql));

ret = serialize_statement(stmt, &body);
Expand Down