Mercurial > code
annotate C++/DriverPostgres.cpp @ 189:cc1e5fe1ee2c
Update drivers to style and using instead of typedefs
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 26 Nov 2013 20:36:59 +0100 |
parents | 4c746050969a |
children | d263f85f43a4 |
rev | line source |
---|---|
171 | 1 /* |
2 * DriverPostgres.cpp -- PostgreSQL driver | |
3 * | |
4 * Copyright (c) 2013, David Demelier <markand@malikania.fr> | |
5 * | |
6 * Permission to use, copy, modify, and/or distribute this software for any | |
7 * purpose with or without fee is hereby granted, provided that the above | |
8 * copyright notice and this permission notice appear in all copies. | |
9 * | |
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 */ | |
18 | |
19 #include <sstream> | |
20 | |
172
a61cddaf7547
Rename Driver postgres
David Demelier <markand@malikania.fr>
parents:
171
diff
changeset
|
21 #include "DriverPostgres.h" |
171 | 22 |
23 /* -------------------------------------------------------- | |
24 * Query PostgreSQL (protected methods) | |
25 * -------------------------------------------------------- */ | |
26 | |
177 | 27 bool QueryPostgres::getBoolean(int row, const std::string &column) |
171 | 28 { |
177 | 29 int idx = PQfnumber(m_result.get(), column.c_str()); |
30 std::string code = PQgetvalue(m_result.get(), row, idx); | |
171 | 31 |
177 | 32 return code[0] == 't'; |
33 } | |
171 | 34 |
177 | 35 Date QueryPostgres::getDate(int row, const std::string &column) |
36 { | |
37 int idx = PQfnumber(m_result.get(), column.c_str()); | |
38 long timestamp = static_cast<long>(time(0)); | |
39 | |
184
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
40 try { |
177 | 41 std::ostringstream oss; |
42 std::string value, req; | |
43 | |
44 value = PQgetvalue(m_result.get(), row, idx); | |
45 | |
46 /* | |
47 * Convert the date using the SQL function so that user does | |
48 * not require any explicit conversion itself. | |
49 */ | |
50 oss << "Select EXTRACT(EPOCH FROM TIMESTAMP '"; | |
51 oss << value; | |
52 oss << "') AS RESULT"; | |
53 req = oss.str(); | |
54 | |
55 Query::Ptr result = m_driver->query(req); | |
56 timestamp = result->get<double>(0, "RESULT"); | |
184
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
57 } catch (...) { } |
171 | 58 |
177 | 59 return Date(static_cast<time_t>(timestamp)); |
60 } | |
61 | |
62 double QueryPostgres::getDouble(int row, const std::string &column) | |
63 { | |
64 int idx = PQfnumber(m_result.get(), column.c_str()); | |
65 | |
66 return std::stod(PQgetvalue(m_result.get(), row, idx)); | |
67 } | |
171 | 68 |
177 | 69 int QueryPostgres::getInt(int row, const std::string &column) |
70 { | |
71 int idx = PQfnumber(m_result.get(), column.c_str()); | |
72 | |
73 return std::stoi(PQgetvalue(m_result.get(), row, idx)); | |
74 } | |
75 | |
76 std::string QueryPostgres::getString(int row, const std::string &column) | |
77 { | |
78 int idx = PQfnumber(m_result.get(), column.c_str()); | |
79 | |
80 return std::string(PQgetvalue(m_result.get(), row, idx)); | |
171 | 81 } |
82 | |
83 /* -------------------------------------------------------- | |
84 * Query PostgreSQL (public methods) | |
85 * -------------------------------------------------------- */ | |
86 | |
177 | 87 QueryPostgres::QueryPostgres(Driver::Ptr driver, PostgresResult result) |
171 | 88 { |
177 | 89 m_driver = driver; |
171 | 90 m_result = std::move(result); |
91 } | |
92 | |
172
a61cddaf7547
Rename Driver postgres
David Demelier <markand@malikania.fr>
parents:
171
diff
changeset
|
93 QueryPostgres::~QueryPostgres() |
171 | 94 { |
95 } | |
96 | |
177 | 97 ColumnType QueryPostgres::type(const std::string &column) const |
98 { | |
99 ColumnType type; | |
100 int pqType, index; | |
101 | |
102 index = PQfnumber(m_result.get(), column.c_str()); | |
103 pqType = PQftype(m_result.get(), index); | |
189
cc1e5fe1ee2c
Update drivers to style and using instead of typedefs
David Demelier <markand@malikania.fr>
parents:
184
diff
changeset
|
104 switch (pqType) { |
177 | 105 case 16: |
106 type = ColumnType::Boolean; | |
107 break; | |
108 case 1082: | |
109 case 1083: | |
110 case 1114: | |
111 type = ColumnType::Date; | |
112 break; | |
113 case 1700: | |
114 case 700: | |
115 case 701: | |
116 type = ColumnType::Double; | |
117 break; | |
118 case 20: | |
119 case 21: | |
120 case 23: | |
121 type = ColumnType::Integer; | |
122 break; | |
123 case 25: | |
124 case 1042: | |
125 case 1043: | |
126 type = ColumnType::String; | |
127 break; | |
128 default: | |
129 type = ColumnType::Invalid; | |
130 } | |
131 | |
132 return type; | |
133 } | |
134 | |
172
a61cddaf7547
Rename Driver postgres
David Demelier <markand@malikania.fr>
parents:
171
diff
changeset
|
135 int QueryPostgres::countRows() |
171 | 136 { |
137 return PQntuples(m_result.get()); | |
138 } | |
139 | |
172
a61cddaf7547
Rename Driver postgres
David Demelier <markand@malikania.fr>
parents:
171
diff
changeset
|
140 int QueryPostgres::countColumns() |
171 | 141 { |
142 return PQnfields(m_result.get()); | |
143 } | |
144 | |
172
a61cddaf7547
Rename Driver postgres
David Demelier <markand@malikania.fr>
parents:
171
diff
changeset
|
145 bool QueryPostgres::isNull(int row, const std::string &column) |
171 | 146 { |
147 int idx = PQfnumber(m_result.get(), column.c_str()); | |
148 | |
149 return PQgetisnull(m_result.get(), row, idx) == 1; | |
150 } | |
151 | |
172
a61cddaf7547
Rename Driver postgres
David Demelier <markand@malikania.fr>
parents:
171
diff
changeset
|
152 void QueryPostgres::dump(void) |
171 | 153 { |
154 std::cout << "Dumping PostgreSQL result, "; | |
155 std::cout << countRows() << " rows, "; | |
156 std::cout << countColumns() << " columns" << std::endl; | |
157 | |
189
cc1e5fe1ee2c
Update drivers to style and using instead of typedefs
David Demelier <markand@malikania.fr>
parents:
184
diff
changeset
|
158 for (int r = 0; r < countRows(); ++r) { |
171 | 159 std::cout << "Dumping row " << r << std::endl; |
160 std::cout << "==============================" << std::endl; | |
161 | |
189
cc1e5fe1ee2c
Update drivers to style and using instead of typedefs
David Demelier <markand@malikania.fr>
parents:
184
diff
changeset
|
162 for (int c = 0; c < countColumns(); ++c) { |
171 | 163 std::cout << "\t" << PQfname(m_result.get(), c); |
164 std::cout << " = " << PQgetvalue(m_result.get(), r, c) << std::endl; | |
165 } | |
166 } | |
167 } | |
168 | |
169 /* -------------------------------------------------------- | |
184
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
170 * Request PostgreSQL |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
171 * -------------------------------------------------------- */ |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
172 |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
173 RequestPostgres::RequestPostgres(const std::string &command) |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
174 : Request(command) |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
175 { |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
176 } |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
177 |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
178 std::string RequestPostgres::bindBoolean(bool value) |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
179 { |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
180 return (value) ? "'t'" : "'f'"; |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
181 } |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
182 |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
183 std::string RequestPostgres::bindDate(Date value) |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
184 { |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
185 std::ostringstream oss; |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
186 |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
187 oss << "to_timestamp("; |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
188 oss << value.getTimestamp(); |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
189 oss << ")"; |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
190 |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
191 return oss.str(); |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
192 } |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
193 |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
194 std::string RequestPostgres::bindDouble(double value) |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
195 { |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
196 return std::to_string(value); |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
197 } |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
198 |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
199 std::string RequestPostgres::bindInt(int value) |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
200 { |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
201 return std::to_string(value); |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
202 } |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
203 |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
204 std::string RequestPostgres::bindString(std::string value) |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
205 { |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
206 std::ostringstream oss; |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
207 |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
208 oss << "'"; |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
209 for (auto c : value) { |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
210 if (c == '\'') |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
211 oss << "\\'"; |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
212 else |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
213 oss << c; |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
214 } |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
215 |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
216 oss << "'"; |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
217 |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
218 return oss.str(); |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
219 } |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
220 |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
221 /* -------------------------------------------------------- |
171 | 222 * Driver PostgreSQL |
223 * -------------------------------------------------------- */ | |
224 | |
172
a61cddaf7547
Rename Driver postgres
David Demelier <markand@malikania.fr>
parents:
171
diff
changeset
|
225 DriverPostgres::DriverPostgres() |
171 | 226 { |
227 } | |
228 | |
172
a61cddaf7547
Rename Driver postgres
David Demelier <markand@malikania.fr>
parents:
171
diff
changeset
|
229 DriverPostgres::~DriverPostgres() |
171 | 230 { |
231 } | |
232 | |
172
a61cddaf7547
Rename Driver postgres
David Demelier <markand@malikania.fr>
parents:
171
diff
changeset
|
233 std::string DriverPostgres::convert(Params ¶ms) |
171 | 234 { |
235 std::ostringstream oss; | |
236 | |
237 oss << "host = " << params["host"] << " "; | |
238 oss << "port = " << params["port"] << " "; | |
239 oss << "user = " << params["user"] << " "; | |
240 oss << "dbname = " << params["database"] << " "; | |
241 oss << "password = " << params["password"]; | |
242 | |
243 return oss.str(); | |
244 } | |
245 | |
172
a61cddaf7547
Rename Driver postgres
David Demelier <markand@malikania.fr>
parents:
171
diff
changeset
|
246 bool DriverPostgres::connect(const Params ¶ms) |
171 | 247 { |
248 Params copy = params; | |
249 PGconn *conn = PQconnectdb(convert(copy).c_str()); | |
250 | |
189
cc1e5fe1ee2c
Update drivers to style and using instead of typedefs
David Demelier <markand@malikania.fr>
parents:
184
diff
changeset
|
251 if (conn == nullptr) { |
171 | 252 m_error = strerror(ENOMEM); |
253 return false; | |
254 } | |
255 | |
189
cc1e5fe1ee2c
Update drivers to style and using instead of typedefs
David Demelier <markand@malikania.fr>
parents:
184
diff
changeset
|
256 if (PQstatus(conn) == CONNECTION_BAD) { |
171 | 257 m_error = PQerrorMessage(conn); |
258 PQfinish(conn); | |
259 | |
260 return false; | |
261 } | |
262 | |
263 m_connection = PostgresConn(conn); | |
264 | |
265 return true; | |
266 } | |
267 | |
184
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
268 Request::Ptr DriverPostgres::prepare(const std::string &command) |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
269 { |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
270 return std::make_shared<RequestPostgres>(command); |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
271 } |
4c746050969a
Add support for request (PostgreSQL done)
David Demelier <markand@malikania.fr>
parents:
177
diff
changeset
|
272 |
177 | 273 Query::Ptr DriverPostgres::query(const std::string &cmd) |
171 | 274 { |
275 PGresult *info; | |
276 | |
277 // If NULL, the libpq said no memory | |
278 info = PQexec(m_connection.get(), cmd.c_str()); | |
279 if (info == nullptr) | |
177 | 280 throw Query::Error(strerror(ENOMEM)); |
171 | 281 |
282 // If an error occured | |
283 int errorCode = PQresultStatus(info); | |
189
cc1e5fe1ee2c
Update drivers to style and using instead of typedefs
David Demelier <markand@malikania.fr>
parents:
184
diff
changeset
|
284 if (errorCode != PGRES_COMMAND_OK && errorCode != PGRES_TUPLES_OK) { |
171 | 285 std::string error = PQresultErrorMessage(info); |
286 PQclear(info); | |
177 | 287 throw Query::Error(error); |
171 | 288 } |
289 | |
177 | 290 return std::unique_ptr<Query>(new QueryPostgres(shared_from_this(), |
291 QueryPostgres::PostgresResult(info))); | |
171 | 292 } |
293 | |
172
a61cddaf7547
Rename Driver postgres
David Demelier <markand@malikania.fr>
parents:
171
diff
changeset
|
294 std::string DriverPostgres::description() const |
171 | 295 { |
296 std::ostringstream oss; | |
297 | |
298 oss << "Connected on PostgreSQL database: " << std::endl; | |
299 oss << " host: " << PQhost(m_connection.get()) << std::endl; | |
300 oss << " port: " << PQport(m_connection.get()) << std::endl; | |
301 oss << " user: " << PQuser(m_connection.get()) << std::endl; | |
302 oss << " database: " << PQdb(m_connection.get()) << std::endl; | |
303 | |
304 return oss.str(); | |
305 } | |
177 | 306 |
307 std::string DriverPostgres::version() const | |
308 { | |
309 std::ostringstream oss; | |
310 | |
311 // TODO: ADD VERSION | |
312 | |
313 oss << "PostgreSQL driver"; | |
314 | |
315 return oss.str(); | |
316 } |