in driver/connect.cc [326:1148]
SQLRETURN DBC::connect(DataSource *dsrc, bool failover_enabled, bool is_monitor_connection)
{
SQLRETURN rc = SQL_SUCCESS;
unsigned long flags;
/* Use 'int' and fill all bits to avoid alignment Bug#25920 */
unsigned int opt_ssl_verify_server_cert = ~0;
const my_bool on = 1;
unsigned int on_int = 1;
unsigned int off_int = 0;
unsigned long max_long = ~0L;
bool initstmt_executed = false;
dbc_guard guard(this);
#ifdef WIN32
/*
Detect if we are running with ADO present, and force on the
FLAG_COLUMN_SIZE_S32 option if we are.
*/
if (GetModuleHandle("msado15.dll") != NULL)
dsrc->opt_COLUMN_SIZE_S32 = true;
/* Detect another problem specific to MS Access */
if (GetModuleHandle("msaccess.exe") != NULL)
dsrc->opt_DFLT_BIGINT_BIND_STR = true;
/* MS SQL Likes when the CHAR columns are padded */
if (GetModuleHandle("sqlservr.exe") != NULL)
dsrc->opt_PAD_SPACE = true;
#endif
this->connection_proxy->init();
flags = get_client_flags(dsrc);
/* Set other connection options */
if (dsrc->opt_BIG_PACKETS || dsrc->opt_SAFE)
#if MYSQL_VERSION_ID >= 50709
connection_proxy->options(MYSQL_OPT_MAX_ALLOWED_PACKET, &max_long);
#else
/* max_allowed_packet is a magical mysql macro. */
max_allowed_packet = ~0L;
#endif
if (dsrc->opt_NAMED_PIPE)
connection_proxy->options(MYSQL_OPT_NAMED_PIPE, NullS);
if (dsrc->opt_USE_MYCNF)
connection_proxy->options(MYSQL_READ_DEFAULT_GROUP, "odbc");
unsigned int connect_timeout, read_timeout, write_timeout;
if (failover_enabled)
{
connect_timeout = get_connect_timeout(dsrc->opt_CONNECT_TIMEOUT);
read_timeout = get_network_timeout(dsrc->opt_NETWORK_TIMEOUT);
write_timeout = read_timeout;
}
else if (is_monitor_connection)
{
connect_timeout = get_network_timeout(dsrc->opt_READTIMEOUT);
read_timeout = get_network_timeout(dsrc->opt_READTIMEOUT);
write_timeout = get_network_timeout(dsrc->opt_WRITETIMEOUT);
} else
{
connect_timeout = get_connect_timeout(login_timeout);
read_timeout = get_network_timeout(dsrc->opt_READTIMEOUT);
write_timeout = get_network_timeout(dsrc->opt_WRITETIMEOUT);
}
connection_proxy->options(MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout);
connection_proxy->options(MYSQL_OPT_READ_TIMEOUT, &read_timeout);
connection_proxy->options(MYSQL_OPT_WRITE_TIMEOUT, &write_timeout);
/*
Pluggable authentication was introduced in mysql 5.5.7
*/
#if MYSQL_VERSION_ID >= 50507
if (dsrc->opt_PLUGIN_DIR)
{
connection_proxy->options(MYSQL_PLUGIN_DIR, (const char*)dsrc->opt_PLUGIN_DIR);
}
#ifdef WIN32
else
{
/*
If plugin directory is not set we can use the dll location
for a better chance of finding plugins.
*/
connection_proxy->options(MYSQL_PLUGIN_DIR, default_plugin_location.c_str());
}
#endif
if (dsrc->opt_DEFAULT_AUTH)
{
connection_proxy->options(MYSQL_DEFAULT_AUTH, (const char*)dsrc->opt_DEFAULT_AUTH);
}
/*
* If fido callback is used the lock must remain till the end of
* the connection process.
*/
std::unique_lock<std::mutex> fido_lock(global_fido_mutex);
/*
* Set callback even if the value is NULL, but only to reset the previously
* installed callback.
*/
fido_callback_func fido_func = fido_callback;
if(!fido_func && global_fido_callback)
fido_func = global_fido_callback;
std::vector<std::string> plugin_types = {
"fido", "webauthn"
};
if (fido_func || fido_callback_is_set)
{
int plugin_load_failures = 0;
for (std::string plugin_type : plugin_types)
{
std::string plugin_name = "authentication_" + plugin_type +
"_client";
struct st_mysql_client_plugin* plugin =
connection_proxy->client_find_plugin(
plugin_name.c_str(),
MYSQL_CLIENT_AUTHENTICATION_PLUGIN);
if (plugin)
{
std::string opt_name = (plugin_type == "webauthn" ?
"plugin_authentication_webauthn_client" :
plugin_type) + "_messages_callback";
if (mysql_plugin_options(plugin, opt_name.c_str(),
(const void*)fido_func))
{
// If plugin is loaded, but the callback option fails to set
// the error is reported.
return set_error("HY000",
"Failed to set a FIDO authentication callback function", 0);
}
}
else
{
// Do not report an error yet.
// Just increment the failure count.
++plugin_load_failures;
}
}
if (plugin_load_failures == plugin_types.size())
{
// Report error only if all plugins failed to load
return set_error("HY000", "Failed to set a FIDO "
"authentication callback because none of FIDO "
"authentication plugins (fido, webauthn) could "
"be loaded", 0);
}
fido_callback_is_set = fido_func;
}
else
{
// No need to keep the lock if callback is not used.
fido_lock.unlock();
}
bool oci_config_file_set = dsrc->opt_OCI_CONFIG_FILE;
bool oci_config_profile_set = dsrc->opt_OCI_CONFIG_PROFILE;
if(oci_config_file_set || oci_config_profile_set || oci_plugin_is_loaded)
{
/* load client authentication plugin if required */
struct st_mysql_client_plugin *plugin =
connection_proxy->client_find_plugin("authentication_oci_client",
MYSQL_CLIENT_AUTHENTICATION_PLUGIN);
if(!plugin)
{
return set_error("HY000", "Couldn't load plugin authentication_oci_client", 0);
}
oci_plugin_is_loaded = true;
// Set option value or reset by giving nullptr to prevent
// re-using the value set by another connect (plugin does not
// reset its options automatically).
const void *val_to_set = oci_config_file_set ?
(const char*)dsrc->opt_OCI_CONFIG_FILE :
nullptr;
if (mysql_plugin_options(plugin, "oci-config-file", val_to_set) &&
val_to_set)
{
// Error should only be returned if setting non-null option value.
return set_error("HY000",
"Failed to set config file for authentication_oci_client plugin", 0);
}
val_to_set = oci_config_profile_set ?
(const char*)dsrc->opt_OCI_CONFIG_PROFILE :
nullptr;
if (mysql_plugin_options(plugin, "authentication-oci-client-config-profile",
val_to_set) && val_to_set)
{
return set_error("HY000",
"Failed to set config profile for authentication_oci_client plugin", 0);
}
}
if (dsrc->opt_AUTHENTICATION_KERBEROS_MODE)
{
#ifdef WIN32
/* load client authentication plugin if required */
struct st_mysql_client_plugin* plugin = connection_proxy->client_find_plugin(
"authentication_kerberos_client",
MYSQL_CLIENT_AUTHENTICATION_PLUGIN);
if (!plugin)
{
return set_error("HY000", connection_proxy->error(), 0);
}
if (mysql_plugin_options(plugin, "plugin_authentication_kerberos_client_mode",
(const char*)dsrc->opt_AUTHENTICATION_KERBEROS_MODE))
{
return set_error("HY000",
"Failed to set mode for authentication_kerberos_client plugin", 0);
}
#else
if (myodbc_strcasecmp("GSSAPI",
(const char *)dsrc->opt_AUTHENTICATION_KERBEROS_MODE))
{
return set_error("HY000",
"Invalid value for authentication-kerberos-mode. "
"Only GSSAPI is supported.", 0);
}
#endif
}
#endif
#define SSL_SET(X, Y) \
if (dsrc->opt_##X && connection_proxy->options(MYSQL_OPT_##X, \
(const char *)dsrc->opt_##X)) \
return set_error("HY000", "Failed to set " Y, 0);
#define SSL_OPTIONS_LIST(X) \
X(SSL_KEY, "the path name of the client private key file") \
X(SSL_CERT, "the path name of the client public key certificate file") \
X(SSL_CA, "the path name of the Certificate Authority (CA) certificate file") \
X(SSL_CAPATH, "the path name of the directory that contains trusted SSL CA certificate files") \
X(SSL_CIPHER, "the list of permissible ciphers for SSL encryption") \
X(SSL_CRL, "Failed to set the certificate revocation list file") \
X(SSL_CRLPATH, "Failed to set the certificate revocation list path")
SSL_OPTIONS_LIST(SSL_SET);
#if MYSQL_VERSION_ID < 80003
if (dsrc->SSLVERIFY)
connection_proxy->options(MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
(const char *)&opt_ssl_verify_server_cert);
#endif
#if MYSQL_VERSION_ID >= 50660
if (dsrc->opt_RSAKEY)
{
/* Read the public key on the client side */
connection_proxy->options(MYSQL_SERVER_PUBLIC_KEY, (const char*)dsrc->opt_RSAKEY);
}
#endif
#if MYSQL_VERSION_ID >= 50710
{
std::string tls_options;
if (dsrc->opt_TLS_VERSIONS)
{
// If tls-versions is used the NO_TLS_X options are deactivated
tls_options = (const char*)dsrc->opt_TLS_VERSIONS;
}
else
{
std::map<std::string, bool> opts = {
{ "TLSv1.2", !dsrc->opt_NO_TLS_1_2 },
{ "TLSv1.3", !dsrc->opt_NO_TLS_1_3 },
};
for (auto &opt : opts)
{
if (!opt.second)
continue;
if (!tls_options.empty())
tls_options.append(",");
tls_options.append(opt.first);
}
}
if (!tls_options.length() ||
connection_proxy->options(MYSQL_OPT_TLS_VERSION, tls_options.c_str()))
{
return set_error("HY000",
"SSL connection error: No valid TLS version available", 0);
}
}
#endif
#if MYSQL_VERSION_ID >= 80004
if (dsrc->opt_GET_SERVER_PUBLIC_KEY)
{
/* Get the server public key */
connection_proxy->options(MYSQL_OPT_GET_SERVER_PUBLIC_KEY, (const void*)&on);
}
#endif
if (unicode)
{
/*
Get the ANSI charset info before we change connection to UTF-8.
*/
MY_CHARSET_INFO my_charset;
connection_proxy->get_character_set_info(&my_charset);
ansi_charset_info= get_charset(my_charset.number, MYF(0));
/*
We always use utf8 for the connection, and change it afterwards if needed.
*/
connection_proxy->options(MYSQL_SET_CHARSET_NAME, transport_charset);
cxn_charset_info= utf8_charset_info;
}
else
{
#ifdef _WIN32
char cpbuf[64];
const char *client_cs_name= NULL;
myodbc_snprintf(cpbuf, sizeof(cpbuf), "cp%u", GetACP());
client_cs_name= my_os_charset_to_mysql_charset(cpbuf);
if (client_cs_name)
{
connection_proxy->options(MYSQL_SET_CHARSET_NAME, client_cs_name);
ansi_charset_info= cxn_charset_info= get_charset_by_csname(client_cs_name, MYF(MY_CS_PRIMARY), MYF(0));
}
#else
MY_CHARSET_INFO my_charset;
connection_proxy->get_character_set_info(&my_charset);
ansi_charset_info= get_charset(my_charset.number, MYF(0));
#endif
}
#if MYSQL_VERSION_ID >= 50610
if (dsrc->opt_CAN_HANDLE_EXP_PWD)
{
connection_proxy->options(MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS, (char *)&on);
}
#endif
#if (MYSQL_VERSION_ID >= 50527 && MYSQL_VERSION_ID < 50600) || MYSQL_VERSION_ID >= 50607
// IAM authentication requires the plugin to be set.
if (dsrc->opt_ENABLE_CLEARTEXT_PLUGIN ||
(dsrc->opt_AUTH_MODE && !myodbc_strcasecmp(AUTH_MODE_IAM, (const char*)dsrc->opt_AUTH_MODE))
|| dsrc->opt_FED_AUTH_MODE)
{
connection_proxy->options(MYSQL_ENABLE_CLEARTEXT_PLUGIN, (char *)&on);
}
#endif
if (dsrc->opt_ENABLE_LOCAL_INFILE)
{
connection_proxy->options(MYSQL_OPT_LOCAL_INFILE, &on_int);
}
else
{
connection_proxy->options(MYSQL_OPT_LOCAL_INFILE, &off_int);
}
if (dsrc->opt_LOAD_DATA_LOCAL_DIR)
{
connection_proxy->options(MYSQL_OPT_LOAD_DATA_LOCAL_DIR, (const char*)dsrc->opt_LOAD_DATA_LOCAL_DIR);
}
// Set the connector identification attributes.
std::string attr_list[][2] = {
{"_connector_license", MYODBC_LICENSE},
{"_connector_name", "mysql-connector-odbc"},
{"_connector_type", MYODBC_STRDRIVERTYPE},
{"_connector_version", MYODBC_CONN_ATTR_VER}
};
for (auto &val : attr_list)
{
connection_proxy->options4(MYSQL_OPT_CONNECT_ATTR_ADD,
val[0].c_str(), val[1].c_str());
}
#if MFA_ENABLED
if(dsrc->pwd1 && dsrc->pwd1[0])
{
ds_get_utf8attr(dsrc->pwd1, &dsrc->pwd18);
int fator = 1;
connection_proxy->options4(MYSQL_OPT_USER_PASSWORD,
&fator,
dsrc->pwd18);
}
if(dsrc->pwd2 && dsrc->pwd2[0])
{
ds_get_utf8attr(dsrc->pwd2, &dsrc->pwd28);
int fator = 2;
connection_proxy->options4(MYSQL_OPT_USER_PASSWORD,
&fator,
dsrc->pwd28);
}
if(dsrc->pwd3 && dsrc->pwd3[0])
{
ds_get_utf8attr(dsrc->pwd3, &dsrc->pwd38);
int fator = 3;
connection_proxy->options4(MYSQL_OPT_USER_PASSWORD,
&fator,
dsrc->pwd38);
}
#endif
#if MYSQL_VERSION_ID >= 50711
if (dsrc->opt_SSL_MODE)
{
unsigned int mode = 0;
if (!myodbc_strcasecmp(ODBC_SSL_MODE_DISABLED, dsrc->opt_SSL_MODE))
mode = SSL_MODE_DISABLED;
if (!myodbc_strcasecmp(ODBC_SSL_MODE_PREFERRED, dsrc->opt_SSL_MODE))
mode = SSL_MODE_PREFERRED;
if (!myodbc_strcasecmp(ODBC_SSL_MODE_REQUIRED, dsrc->opt_SSL_MODE))
mode = SSL_MODE_REQUIRED;
if (!myodbc_strcasecmp(ODBC_SSL_MODE_VERIFY_CA, dsrc->opt_SSL_MODE))
mode = SSL_MODE_VERIFY_CA;
if (!myodbc_strcasecmp(ODBC_SSL_MODE_VERIFY_IDENTITY, dsrc->opt_SSL_MODE))
mode = SSL_MODE_VERIFY_IDENTITY;
// Don't do anything if there is no match with any of the available modes
if (mode)
connection_proxy->options(MYSQL_OPT_SSL_MODE, &mode);
}
#endif
uint16_t total_weight = 0;
std::vector<Srv_host_detail> hosts;
try {
hosts = parse_host_list(dsrc->opt_SERVER, dsrc->opt_PORT);
} catch (std::string &e)
{
return set_error("HY000", e.c_str(), 0);
}
if(!dsrc->opt_MULTI_HOST && hosts.size() > 1)
{
return set_error("HY000", "Missing option MULTI_HOST=1", 0);
}
if(dsrc->opt_ENABLE_DNS_SRV && hosts.size() > 1)
{
return set_error("HY000", "Specifying multiple hostnames with DNS SRV look up is not allowed.", 0);
}
if(dsrc->opt_ENABLE_DNS_SRV && dsrc->opt_PORT)
{
return set_error("HY000", "Specifying a port number with DNS SRV lookup is not allowed.", 0);
}
if(dsrc->opt_ENABLE_DNS_SRV)
{
if(dsrc->opt_SOCKET)
{
return set_error("HY000",
#ifdef _WIN32
"Using Named Pipes with DNS SRV lookup is not allowed.",
#else
"Using Unix domain sockets with DNS SRV lookup is not allowed",
#endif
0);
}
if(hosts.empty())
{
std::stringstream err;
err << "Unable to locate any hosts for " << (const char*)dsrc->opt_SERVER;
return set_error("HY000", err.str().c_str(), 0);
}
}
// Handle OPENTELEMETRY option.
// Note: Using while() instead of if() to be able to get out of it with
// `break` statement.
while (dsrc->opt_OPENTELEMETRY)
{
#ifndef TELEMETRY
return set_error("HY000",
"OPENTELEMETRY option is not supported on this platform."
,0);
#else
#define SET_OTEL_MODE(X,N) \
if (!myodbc_strcasecmp(#X, dsrc->opt_OPENTELEMETRY)) \
{ telemetry.set_mode(OTEL_ ## X); break; }
ODBC_OTEL_MODE(SET_OTEL_MODE)
return set_error("HY000",
"OPENTELEMETRY option can be set only to DISABLED or PREFERRED"
, 0);
#endif
}
telemetry.span_start(this);
auto do_connect = [this,&dsrc,&flags](
const char *host,
unsigned int port
) -> short
{
int protocol;
if(dsrc->opt_SOCKET)
{
#ifdef _WIN32
protocol = MYSQL_PROTOCOL_PIPE;
#else
protocol = MYSQL_PROTOCOL_SOCKET;
#endif
} else
{
protocol = MYSQL_PROTOCOL_TCP;
}
connection_proxy->options(MYSQL_OPT_PROTOCOL, &protocol);
//Setting server and port
dsrc->opt_SERVER = host;
dsrc->opt_PORT = port;
const char* user = dsrc->opt_UID;
const char* password = dsrc->opt_PWD;
const char* database = dsrc->opt_DATABASE;
const char* socket = dsrc->opt_SOCKET;
const bool connect_result = connection_proxy->connect(host, user, password, database, port, socket, flags);
if (!connect_result)
{
unsigned int native_error= connection_proxy->error_code();
/* Before 5.6.11 error returned by server was ER_MUST_CHANGE_PASSWORD(1820).
In 5.6.11 it changed to ER_MUST_CHANGE_PASSWORD_LOGIN(1862)
We must to change error for old servers in order to set correct sqlstate */
if (native_error == 1820 && ER_MUST_CHANGE_PASSWORD_LOGIN != 1820)
{
native_error= ER_MUST_CHANGE_PASSWORD_LOGIN;
}
#if MYSQL_VERSION_ID < 50610
/* In that special case when the driver was linked against old version of libmysql*/
if (native_error == ER_MUST_CHANGE_PASSWORD_LOGIN
&& dsrc->CAN_HANDLE_EXP_PWD)
{
/* The password has expired, application said it knows how to deal with
that, but the driver was linked that
does not support this option. Thus we change native error. */
/* TODO: enum/defines for driver specific errors */
return set_conn_error(dbc, MYERR_08004,
"Your password has expired, but underlying library doesn't support "
"this functionlaity", 0);
}
#endif
set_error("HY000", connection_proxy->error(), native_error);
translate_error((char*)error.sqlstate.c_str(), MYERR_S1000, native_error);
return SQL_ERROR;
}
return SQL_SUCCESS;
};
//Connect loop
{
bool connected = false;
std::random_device rd;
std::mt19937 generator(rd()); // seed the generator
while(!hosts.empty() && !connected)
{
std::uniform_int_distribution<int> distribution(
0, (int)hosts.size() - 1); // define the range of random numbers
int pos = distribution(generator);
auto el = hosts.begin();
std::advance(el, pos);
if(do_connect(el->name.c_str(), el->port) == SQL_SUCCESS)
{
connected = true;
telemetry.set_attribs(this, dsrc);
break;
}
else
{
switch (connection_proxy->error_code())
{
case ER_CON_COUNT_ERROR:
case CR_SOCKET_CREATE_ERROR:
case CR_CONNECTION_ERROR:
case CR_CONN_HOST_ERROR:
case CR_IPSOCK_ERROR:
case CR_UNKNOWN_HOST:
//On Network errors, continue
break;
default:
//If SQLSTATE not 08xxx, which is used for network errors
if(strncmp(connection_proxy->sqlstate(), "08", 2) != 0)
{
//Return error and do not try another host
return SQL_ERROR;
}
}
}
hosts.erase(el);
}
if(!connected)
{
if(dsrc->opt_ENABLE_DNS_SRV)
{
std::string err =
std::string("Unable to connect to any of the hosts of ") +
(const char*)dsrc->opt_SERVER + " SRV";
set_error("HY000", err.c_str(), 0);
}
else if (dsrc->opt_MULTI_HOST && hosts.size() > 1) {
set_error("HY000", "Unable to connect to any of the hosts", 0);
}
//The others will retrieve the error from connect
return SQL_ERROR;
}
}
has_query_attrs = connection_proxy->get_server_capabilities() & CLIENT_QUERY_ATTRIBUTES;
if (!is_minimum_version(connection_proxy->get_server_version(), "4.1.1"))
{
close();
return set_error("08001", "Driver does not support server versions under 4.1.1", 0);
}
rc = set_charset_options(dsrc->opt_CHARSET);
// It could be an error with expired password in which case we
// still try to execute init statements and retry below.
if (rc == SQL_ERROR && error.native_error != ER_MUST_CHANGE_PASSWORD)
return SQL_ERROR;
// Try running INITSTMT.
if (!SQL_SUCCEEDED(run_initstmt(this, dsrc)))
return error.retcode;
// If we had expired password error at the beginning
// try setting charset options again.
// NOTE: charset name is converted to a single-byte
// charset by previous call to ds_get_utf8attr().
if (rc == SQL_ERROR)
rc = set_charset_options((const char*)dsrc->opt_CHARSET);
if (!SQL_SUCCEEDED(rc))
{
return SQL_ERROR;
}
/*
The MySQL server has a workaround for old versions of Microsoft Access
(and possibly other products) that is no longer necessary, but is
unfortunately enabled by default. We have to turn it off, or it causes
other problems.
*/
if (!dsrc->opt_AUTO_IS_NULL &&
execute_query("SET SQL_AUTO_IS_NULL = 0", SQL_NTS, true) != SQL_SUCCESS)
{
return SQL_ERROR;
}
ds = dsrc;
/* init all needed UTF-8 strings */
const char *opt_db = ds->opt_DATABASE;
database = opt_db ? opt_db : "";
if (ds->opt_LOG_QUERY && !log_file)
log_file = init_log_file();
/* Set the statement error prefix based on the server version. */
strxmov(st_error_prefix, MYODBC_ERROR_PREFIX, "[mysqld-",
connection_proxy->get_server_version(), "]", NullS);
/*
This variable will be needed later to process possible
errors when setting MYSQL_OPT_RECONNECT when client lib
used at runtime does not support it.
*/
int set_reconnect_result = 0;
#if MYSQL_VERSION_ID < 80300
/* This needs to be set after connection, or it doesn't stick. */
if (ds->opt_AUTO_RECONNECT)
{
connection_proxy->options(MYSQL_OPT_RECONNECT, (char *)&on);
}
#else
/* MYSQL_OPT_RECONNECT doesn't exist at build time, report warning later. */
set_reconnect_result = 1;
#endif
/* Make sure autocommit is set as configured. */
if (commit_flag == CHECK_AUTOCOMMIT_OFF)
{
if (!transactions_supported() || ds->opt_NO_TRANSACTIONS)
{
commit_flag = CHECK_AUTOCOMMIT_ON;
rc = set_error(MYERR_01S02,
"Transactions are not enabled, option value "
"SQL_AUTOCOMMIT_OFF changed to SQL_AUTOCOMMIT_ON",
SQL_SUCCESS_WITH_INFO);
}
else if (autocommit_is_on() && connection_proxy->autocommit(FALSE))
{
/** @todo set error */
return SQL_ERROR;
}
}
else if ((commit_flag == CHECK_AUTOCOMMIT_ON) &&
transactions_supported() && !autocommit_is_on())
{
if (connection_proxy->autocommit(TRUE))
{
/** @todo set error */
return SQL_ERROR;
}
}
/* Set transaction isolation as configured. */
if (txn_isolation != DEFAULT_TXN_ISOLATION)
{
char buff[80];
const char *level;
if (txn_isolation & SQL_TXN_SERIALIZABLE)
level= "SERIALIZABLE";
else if (txn_isolation & SQL_TXN_REPEATABLE_READ)
level= "REPEATABLE READ";
else if (txn_isolation & SQL_TXN_READ_COMMITTED)
level= "READ COMMITTED";
else
level= "READ UNCOMMITTED";
if (transactions_supported())
{
snprintf(buff, sizeof(buff), "SET SESSION TRANSACTION ISOLATION LEVEL %s", level);
if (execute_query(buff, SQL_NTS, true) != SQL_SUCCESS)
{
return SQL_ERROR;
}
}
else
{
txn_isolation = SQL_TXN_READ_UNCOMMITTED;
rc = set_error(MYERR_01S02,
"Transactions are not enabled, so transaction isolation "
"was ignored.", SQL_SUCCESS_WITH_INFO);
}
}
/*
AUTO_RECONNECT option needs to be handled with the following
considerations:
A - version of ODBC driver code
B - version of client lib used for building ODBC driver (*)
C - version of client lib used at runtime
Note (*): As given by MYSQL_VERSION_ID macro.
The behavior should be like this:
A B C
==== ===== ===== =======================================
old * old reconnect option works
old * new reconnect option silently ignored
new old old reconnect option works
new old new reconnect option ignored with warning
new new * reconnect option ignored with warning
*/
if (ds->opt_AUTO_RECONNECT && set_reconnect_result)
{
set_error("HY000",
"The option AUTO_RECONNECT is not supported "
"by MySQL version 8.3.0 or later. "
"Please remove it from the connection string "
"or the Data Source", 0);
rc = SQL_SUCCESS_WITH_INFO;
}
connection_proxy->get_option(MYSQL_OPT_NET_BUFFER_LENGTH, &net_buffer_len);
guard.set_success(rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO);
return rc;
}