Skip to content

Commit f234e4b

Browse files
committed
WL13322: Legacy connector support for multi-host
1 parent d9c3287 commit f234e4b

File tree

7 files changed

+304
-117
lines changed

7 files changed

+304
-117
lines changed

CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,10 @@ endif()
414414

415415
endif(BUNDLE_DEPENDENCIES)
416416

417-
# TODO: Building examples and unit tests
417+
add_config_option(WITH_JDBC_TESTS BOOL DEFAULT OFF
418+
"Build JDBC Unit tests"
419+
)
420+
418421

419422
if(jdbc_stand_alone)
420423
show_config_options()

driver/mysql_connection.cpp

Lines changed: 75 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <stdio.h>
3939
#include <map>
4040
#include <vector>
41+
#include <algorithm>
4142
#include <random>
4243
#ifdef HAVE_STDINT_H
4344
#include <stdint.h>
@@ -95,6 +96,8 @@ namespace sql
9596
namespace mysql
9697
{
9798

99+
using Host_data = MySQL_Uri::Host_data;
100+
98101
/* {{{ MySQL_Savepoint::MySQL_Savepoint() -I- */
99102
MySQL_Savepoint::MySQL_Savepoint(const sql::SQLString &savepoint):
100103
name(savepoint)
@@ -376,20 +379,15 @@ struct Prio
376379
}
377380
};
378381

379-
struct Srv_host_detail
380-
{
381-
std::string name;
382-
uint16_t port;
383-
};
384382

385383
#ifdef _WIN32
386-
std::multimap<Prio,Srv_host_detail> srv_list(const std::string &hostname,
384+
std::multimap<Prio,Host_data> srv_list(const std::string &hostname,
387385
uint16_t &total_weight)
388386
{
389387
DNS_STATUS status; //Return value of DnsQuery_A() function.
390388
PDNS_RECORD pDnsRecord =nullptr; //Pointer to DNS_RECORD structure.
391389

392-
std::multimap<Prio,Srv_host_detail> srv;
390+
std::multimap<Prio,Host_data> srv;
393391

394392
status = DnsQuery(hostname.c_str(), DNS_TYPE_SRV, DNS_QUERY_STANDARD, nullptr, &pDnsRecord, nullptr);
395393
if (!status)
@@ -401,13 +399,12 @@ std::multimap<Prio,Srv_host_detail> srv_list(const std::string &hostname,
401399
{
402400
srv.insert(std::make_pair(
403401
Prio({pRecord->Data.Srv.wPriority,
404-
pRecord->Data.Srv.wWeight}
405-
),
406-
Srv_host_detail
407-
{
408-
pRecord->Data.Srv.pNameTarget,
409-
pRecord->Data.Srv.wPort
410-
}));
402+
pRecord->Data.Srv.wWeight}),
403+
Host_data
404+
(pRecord->Data.Srv.pNameTarget,
405+
pRecord->Data.Srv.wPort)
406+
));
407+
411408
total_weight+=pRecord->Data.Srv.wWeight;
412409
}
413410
pRecord = pRecord->pNext;
@@ -419,13 +416,14 @@ std::multimap<Prio,Srv_host_detail> srv_list(const std::string &hostname,
419416
}
420417
#else
421418

422-
std::multimap<Prio,Srv_host_detail> srv_list(const std::string &hostname,
419+
//QUery and interprete SRV data from DNS server
420+
std::multimap<Prio,Host_data> srv_list(const std::string &hostname,
423421
uint16_t &total_weight)
424422
{
425423
struct __res_state state {};
426424
res_ninit(&state);
427425

428-
std::multimap<Prio,Srv_host_detail> srv;
426+
std::multimap<Prio,Host_data> srv;
429427

430428
unsigned char query_buffer[NS_PACKETSZ];
431429

@@ -444,20 +442,18 @@ std::multimap<Prio,Srv_host_detail> srv_list(const std::string &hostname,
444442
auto process = [&msg, &name_buffer, &total_weight, &srv](const ns_rr &rr) -> void
445443
{
446444
const unsigned char* srv_data = ns_rr_rdata(rr);
447-
Srv_host_detail host_data;
448-
uint16_t prio, weight;
445+
uint16_t port, prio, weight;
449446

450447
//Each NS_GET16 call moves srv_data to next value
451448
NS_GET16(prio, srv_data);
452449
NS_GET16(weight, srv_data);
453-
NS_GET16(host_data.port, srv_data);
450+
NS_GET16(port, srv_data);
454451

455452
dn_expand(ns_msg_base(msg), ns_msg_end(msg),
456453
srv_data, name_buffer, sizeof(name_buffer));
457454

458-
host_data.name = name_buffer;
459-
460-
srv.insert(std::make_pair(Prio({prio, weight}), std::move(host_data)));
455+
srv.insert(std::make_pair(Prio({prio, weight}),
456+
Host_data(name_buffer, port)));
461457

462458
total_weight+=weight;
463459
};
@@ -957,7 +953,7 @@ void MySQL_Connection::init(ConnectOptionsMap & properties)
957953
}
958954
#endif
959955

960-
proxy->use_protocol(uri.Protocol());
956+
961957

962958
#if MYCPPCONN_STATIC_MYSQL_VERSION_ID < 80000
963959
try {
@@ -993,11 +989,21 @@ void MySQL_Connection::init(ConnectOptionsMap & properties)
993989
PROCESS_CONN_OPTION(int, intOptions);
994990
}
995991

996-
CPP_INFO_FMT("hostName=%s", uri.Host().c_str());
997-
CPP_INFO_FMT("user=%s", userName.c_str());
998-
CPP_INFO_FMT("port=%d", uri.Port());
999-
CPP_INFO_FMT("schema=%s", uri.Schema().c_str());
1000-
CPP_INFO_FMT("socket/pipe=%s", uri.SocketOrPipe().c_str());
992+
bool opt_multi_host = false;
993+
it = properties.find("OPT_MULTI_HOST");
994+
try {
995+
if(it != properties.end())
996+
opt_multi_host = it->second.get<bool>();
997+
} catch (sql::InvalidArgumentException&) {
998+
throw sql::InvalidArgumentException("Wrong type passed for OPT_MULTI_HOST, expected bool");
999+
}
1000+
1001+
if(!opt_multi_host && uri.size() > 1)
1002+
throw sql::InvalidArgumentException("Missing option OPT_MULTI_HOST = true");
1003+
1004+
if(opt_dns_srv && uri.size() > 1)
1005+
throw sql::InvalidArgumentException("Specifying multiple hostnames with DNS SRV look up is not allowed.");
1006+
10011007
CPP_INFO_FMT("OPT_DNS_SRV=%d", opt_dns_srv);
10021008

10031009
auto connect = [this,flags,client_exp_pwd](
@@ -1008,6 +1014,11 @@ void MySQL_Connection::init(ConnectOptionsMap & properties)
10081014
uint16_t port,
10091015
const std::string &socketOrPipe)
10101016
{
1017+
CPP_INFO_FMT("hostName=%s", host.c_str());
1018+
CPP_INFO_FMT("user=%s", user.c_str());
1019+
CPP_INFO_FMT("port=%d", port);
1020+
CPP_INFO_FMT("schema=%s", schema.c_str());
1021+
CPP_INFO_FMT("socket/pipe=%s", socketOrPipe.c_str());
10111022

10121023
if (!proxy->connect(host,
10131024
user,
@@ -1046,6 +1057,11 @@ void MySQL_Connection::init(ConnectOptionsMap & properties)
10461057
}
10471058
};
10481059

1060+
1061+
std::multimap<Prio,Host_data> host_list;
1062+
1063+
uint16_t total_weight = 0;
1064+
10491065
if(opt_dns_srv)
10501066
{
10511067
if(uri.Protocol() != NativeAPI::PROTOCOL_TCP)
@@ -1058,24 +1074,34 @@ void MySQL_Connection::init(ConnectOptionsMap & properties)
10581074
throw sql::InvalidArgumentException("Specifying a port number with DNS SRV lookup is not allowed.");
10591075
}
10601076

1077+
host_list = srv_list(uri.Host(),total_weight);
10611078

1062-
uint16_t total_weight = 0;
1063-
1064-
auto list = srv_list(uri.Host(),total_weight);
1065-
1066-
if(list.empty())
1079+
if(host_list.empty())
10671080
{
10681081
std::stringstream err;
10691082
err << "Unable to locate any hosts for " << uri.Host();
10701083
throw sql::InvalidArgumentException(err.str());
10711084
}
10721085

1086+
1087+
1088+
}
1089+
else
1090+
{
1091+
for(auto host : uri)
1092+
{
1093+
host_list.insert(std::make_pair(Prio({0, 0}), host));
1094+
}
1095+
}
1096+
1097+
//Connect loop
1098+
{
10731099
bool connected = false;
10741100

1075-
while(!list.empty() && !connected)
1101+
while(!host_list.empty() && !connected)
10761102
{
1077-
auto same_range = list.equal_range(list.begin()->first);
1078-
std::vector<Srv_host_detail*> same_prio;
1103+
auto same_range = host_list.equal_range(host_list.begin()->first);
1104+
std::vector<Host_data*> same_prio;
10791105
std::vector<uint16_t> weights;
10801106

10811107

@@ -1104,6 +1130,8 @@ void MySQL_Connection::init(ConnectOptionsMap & properties)
11041130
std::advance(weight_el, pos);
11051131
}
11061132

1133+
proxy->use_protocol(uri.Protocol());
1134+
11071135
try {
11081136
connect((*el)->name, userName,
11091137
password,
@@ -1120,35 +1148,28 @@ void MySQL_Connection::init(ConnectOptionsMap & properties)
11201148
weights.erase(weight_el);
11211149
}
11221150

1123-
list.erase(same_range.first, same_range.second);
1151+
host_list.erase(same_range.first, same_range.second);
11241152

11251153
};
11261154

11271155
if(!connected)
11281156
{
11291157
std::stringstream err;
1130-
err << "Unable to connect to any of the hosts of " << uri.Host() << " SRV";
1158+
if(opt_dns_srv)
1159+
err << "Unable to connect to any of the hosts of " << uri.Host() << " SRV";
1160+
else if (uri.size() >1) {
1161+
err << "Unable to connect to any of the hosts";
1162+
}
1163+
else {
1164+
err << "Unable to connect to " << uri.Host() << ":" << uri.Port();
1165+
}
11311166
proxy.reset();
11321167
throw sql::InvalidArgumentException(err.str());
11331168
}
1134-
1135-
}
1136-
else
1137-
{
1138-
try {
1139-
connect(uri.Host(),
1140-
userName,
1141-
password,
1142-
uri.Schema() /* schema */,
1143-
uri.Port(),
1144-
uri.SocketOrPipe() /*socket or named pipe */);
1145-
} catch (sql::SQLException&)
1146-
{
1147-
proxy.reset();
1148-
throw;
1149-
}
11501169
}
11511170

1171+
1172+
11521173
if (opt_reconnect) {
11531174
try {
11541175
proxy->options(MYSQL_OPT_RECONNECT, (const char *) &intern->reconnect);

0 commit comments

Comments
 (0)