-
Notifications
You must be signed in to change notification settings - Fork 110
/
Copy pathodbc_connection.cpp
139 lines (123 loc) · 4.17 KB
/
odbc_connection.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include "odbc_connection.h"
#include "odbc_result.h"
#include "utils.h"
namespace odbc {
void odbc_connection::cancel_current_result() {
if (current_result_ == nullptr) {
return;
}
current_result_->statement()->cancel();
current_result_ = nullptr;
}
bool odbc_connection::has_result() const {
return current_result_ != nullptr;
}
void odbc_connection::set_current_result(odbc_result* r) {
if (r == current_result_) {
return;
}
cancel_current_result();
current_result_ = r;
}
odbc_connection::odbc_connection(
std::string const& connection_string,
std::string const& timezone,
std::string const& timezone_out,
std::string const& encoding,
std::string const& name_encoding,
bigint_map_t const& bigint_mapping,
long const& timeout,
Rcpp::Nullable<Rcpp::List> const& r_attributes,
bool const& interruptible_execution)
: current_result_(nullptr),
timezone_out_str_(timezone_out),
bigint_mapping_(bigint_mapping),
output_encoder_(nullptr),
column_name_encoder_(nullptr),
interruptible_execution_(interruptible_execution) {
output_encoder_ = std::make_shared<Iconv>(encoding, "UTF-8");
column_name_encoder_ = std::make_shared<Iconv>(name_encoding, "UTF-8");
if (!cctz::load_time_zone(timezone, &timezone_)) {
Rcpp::stop("Error loading time zone (%s)", timezone);
}
// timezone_out_ will not be used. This line is just to ensure
// the provided value is valid.
if (!cctz::load_time_zone(timezone_out, &timezone_out_)) {
Rcpp::stop("Error loading timezone_out (%s)", timezone_out);
}
try {
std::list< nanodbc::connection::attribute > attributes;
std::list< std::shared_ptr< void > > buffer_context;
utils::prepare_connection_attributes(
timeout, r_attributes, attributes, buffer_context );
c_ = std::make_shared<nanodbc::connection>(connection_string, attributes);
} catch (const nanodbc::database_error& e) {
utils::raise_error(odbc_error(e, "", *output_encoder_));
}
}
std::shared_ptr<nanodbc::connection> odbc_connection::connection() const {
return std::shared_ptr<nanodbc::connection>(c_);
}
void odbc_connection::begin() {
if (t_) {
Rcpp::stop("Double begin");
}
t_ = std::unique_ptr<nanodbc::transaction>(new nanodbc::transaction(*c_));
}
void odbc_connection::commit() {
if (!t_) {
Rcpp::stop("Commit without beginning transaction");
}
t_->commit();
t_.reset();
}
void odbc_connection::rollback() {
if (!t_) {
Rcpp::stop("Rollback without beginning transaction");
}
t_->rollback();
t_.reset();
}
bool odbc_connection::has_active_result() const {
return current_result_ != nullptr;
}
bool odbc_connection::is_current_result(odbc_result* result) const {
return current_result_ == result;
}
bool odbc_connection::supports_transactions() const {
try {
return c_->get_info<unsigned short>(SQL_TXN_CAPABLE) != SQL_TC_NONE;
} catch (const nanodbc::database_error& e) {
return false;
}
}
bool odbc_connection::get_data_any_order() const {
try {
/* In a perfect world, we would use SQL_GETDATA_EXTENSIONS to
* determine this. However, some drivers incorrectly report these
* extensions - for example FreeTDS supports out-of-order retrieval
* via SQLGetData, but reports otherwise. Therefore, at this time we
* use empirical findings - we know this to be the case for the Microsoft
* driver for SQL Server.
*/
std::string dbms = c_->get_info<std::string>(SQL_DBMS_NAME);
std::string driver = c_->get_info<std::string>(SQL_DRIVER_NAME);
if (dbms == "Microsoft SQL Server" &&
driver.find("msodbcsql") != std::string::npos) {
return false;
}
return true;
} catch (const nanodbc::database_error& e) {
return true;
}
}
cctz::time_zone odbc_connection::timezone() const { return timezone_; }
std::string odbc_connection::timezone_out_str() const {
return timezone_out_str_;
}
const std::shared_ptr<Iconv> odbc_connection::output_encoder() const { return output_encoder_; }
const std::shared_ptr<Iconv> odbc_connection::column_name_encoder() const { return column_name_encoder_; }
bigint_map_t odbc_connection::get_bigint_mapping() const {
return bigint_mapping_;
}
} // namespace odbc