forked from osm2pgsql-dev/osm2pgsql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpgsql.cpp
More file actions
196 lines (166 loc) · 5.62 KB
/
Copy pathpgsql.cpp
File metadata and controls
196 lines (166 loc) · 5.62 KB
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/* Helper functions for the postgresql connections */
#include "format.hpp"
#include "pgsql.hpp"
#include "util.hpp"
#include <array>
#include <cstdarg>
#include <cstdio>
pg_conn_t::pg_conn_t(std::string const &conninfo)
: m_conn(PQconnectdb(conninfo.c_str()))
{
if (PQstatus(m_conn.get()) != CONNECTION_OK) {
fmt::print(stderr, "Connection to database failed: {}\n", error_msg());
throw std::runtime_error{"Connecting to database."};
}
}
char const *pg_conn_t::error_msg() const noexcept
{
return PQerrorMessage(m_conn.get());
}
pg_result_t pg_conn_t::query(ExecStatusType expect, char const *sql) const
{
#ifdef DEBUG_PGSQL
fmt::print(stderr, "Executing: {}\n", sql);
#endif
pg_result_t res{PQexec(m_conn.get(), sql)};
if (PQresultStatus(res.get()) != expect) {
fmt::print(stderr, "SQL command failed: {}\nFull query: {}\n",
error_msg(), sql);
throw std::runtime_error{"Executing SQL"};
}
return res;
}
pg_result_t pg_conn_t::query(ExecStatusType expect,
std::string const &sql) const
{
return query(expect, sql.c_str());
}
void pg_conn_t::set_config(char const *setting, char const *value) const
{
// Update pg_settings instead of using SET because it does not yield
// errors on older versions of PostgreSQL where the settings are not
// implemented.
auto const sql =
"UPDATE pg_settings SET setting = '{}' WHERE name = '{}'"_format(
setting, value);
query(PGRES_TUPLES_OK, sql);
}
void pg_conn_t::exec(char const *sql) const { query(PGRES_COMMAND_OK, sql); }
void pg_conn_t::exec(std::string const &sql) const
{
query(PGRES_COMMAND_OK, sql.c_str());
}
void pg_conn_t::copy_data(std::string const &sql,
std::string const &context) const
{
#ifdef DEBUG_PGSQL
fmt::print(stderr, "{}>>> {}\n", context, sql);
#endif
int const r = PQputCopyData(m_conn.get(), sql.c_str(), (int)sql.size());
if (r == 1) {
return; // success
}
switch (r) {
case 0: // need to wait for write ready
fmt::print(stderr, "{} - COPY unexpectedly busy\n", context);
break;
case -1: // error occurred
fmt::print(stderr, "{} - error on COPY: {}\n", context, error_msg());
break;
}
if (sql.size() < 1100) {
fmt::print(stderr, "Data:\n{}\n", sql);
} else {
fmt::print(stderr, "Data:\n{}\n...\n{}\n", std::string(sql, 0, 500),
std::string(sql, sql.size() - 500));
}
throw std::runtime_error{"COPYing data to Postgresql."};
}
void pg_conn_t::end_copy(std::string const &context) const
{
if (PQputCopyEnd(m_conn.get(), nullptr) != 1) {
fmt::print(stderr, "COPY END for {} failed: {}\n", context,
error_msg());
throw std::runtime_error{"Ending COPY mode"};
}
pg_result_t const res{PQgetResult(m_conn.get())};
if (PQresultStatus(res.get()) != PGRES_COMMAND_OK) {
fmt::print(stderr, "result COPY END for {} failed: {}\n", context,
error_msg());
throw std::runtime_error{"Ending COPY mode"};
}
}
pg_result_t
pg_conn_t::exec_prepared_internal(char const *stmt, int num_params,
char const *const *param_values) const
{
#ifdef DEBUG_PGSQL
fmt::print(stderr, "ExecPrepared: {}\n", stmt);
#endif
pg_result_t res{PQexecPrepared(m_conn.get(), stmt, num_params, param_values,
nullptr, nullptr, 0)};
if (PQresultStatus(res.get()) != PGRES_TUPLES_OK) {
fmt::print(stderr, "Prepared statement failed with: {} ({})\n",
error_msg(), PQresultStatus(res.get()));
fmt::print(stderr, "Query: {}\n", stmt);
if (num_params) {
fmt::print(stderr, "with arguments:\n");
for (int i = 0; i < num_params; ++i) {
fmt::print(stderr, " {}: {}\n, ", i,
param_values[i] ? param_values[i] : "<NULL>");
}
}
throw std::runtime_error{"Executing prepared statement"};
}
return res;
}
pg_result_t pg_conn_t::exec_prepared(char const *stmt, char const *p1, char const *p2) const
{
std::array<const char *, 2> params{{p1, p2}};
return exec_prepared_internal(stmt, params.size(), params.data());
}
pg_result_t pg_conn_t::exec_prepared(char const *stmt, char const *param) const
{
return exec_prepared_internal(stmt, 1, ¶m);
}
pg_result_t pg_conn_t::exec_prepared(char const *stmt,
std::string const ¶m) const
{
return exec_prepared(stmt, param.c_str());
}
pg_result_t pg_conn_t::exec_prepared(char const *stmt, osmid_t id) const
{
util::integer_to_buffer buffer{id};
return exec_prepared(stmt, buffer.c_str());
}
std::string tablespace_clause(std::string const &name)
{
std::string sql;
if (!name.empty()) {
sql += " TABLESPACE \"";
sql += name;
sql += '"';
}
return sql;
}
std::string qualified_name(std::string const &schema, std::string const &name)
{
std::string result{"\""};
if (!schema.empty()) {
result.reserve(schema.size() + name.size() + 5);
result += schema;
result += "\".\"";
} else {
result.reserve(name.size() + 2);
}
result += name;
result += '"';
return result;
}
postgis_version get_postgis_version(pg_conn_t const &db_connection) {
auto const res = db_connection.query(
PGRES_TUPLES_OK,
"SELECT regexp_split_to_table(postgis_lib_version(), '\\.')");
return {std::stoi(res.get_value_as_string(0, 0)),
std::stoi(res.get_value_as_string(1, 0))};
}