1 #ifndef OSM2PGSQL_PGSQL_HPP
2 #define OSM2PGSQL_PGSQL_HPP
3 
4 /**
5  * SPDX-License-Identifier: GPL-2.0-or-later
6  *
7  * This file is part of osm2pgsql (https://osm2pgsql.org/).
8  *
9  * Copyright (C) 2006-2021 by the osm2pgsql developer community.
10  * For a full list of authors see the git log.
11  */
12 
13 /**
14  * \file
15  *
16  * This file is part of osm2pgsql (https://github.com/openstreetmap/osm2pgsql).
17  *
18  * Helper classes and functions for PostgreSQL access.
19  */
20 
21 #include "osmtypes.hpp"
22 
23 #include <libpq-fe.h>
24 
25 #include <cassert>
26 #include <map>
27 #include <memory>
28 #include <string>
29 
30 /**
31  * PostgreSQL query result.
32  *
33  * Wraps the PGresult object of the libpq library.
34  */
35 class pg_result_t
36 {
37 public:
pg_result_t(PGresult * result)38     explicit pg_result_t(PGresult *result) noexcept : m_result(result) {}
39 
40     /// Get a pointer to the underlying PGresult object.
get() const41     PGresult *get() const noexcept { return m_result.get(); }
42 
43     /// Get the status of this result.
status() const44     ExecStatusType status() const noexcept
45     {
46         return PQresultStatus(m_result.get());
47     }
48 
49     /// The number of fields (columns) in this result.
num_fields() const50     int num_fields() const noexcept { return PQnfields(m_result.get()); }
51 
52     /// The number of tuples (rows) in this result.
num_tuples() const53     int num_tuples() const noexcept { return PQntuples(m_result.get()); }
54 
55     /// Does the field at (row, col) has the NULL value?
is_null(int row,int col) const56     bool is_null(int row, int col) const noexcept
57     {
58         assert(row < num_tuples() && col < num_fields());
59         return PQgetisnull(m_result.get(), row, col) != 0;
60     }
61 
62     /// The length of the field at (row, col) in bytes.
get_length(int row,int col) const63     int get_length(int row, int col) const noexcept
64     {
65         assert(row < num_tuples() && col < num_fields());
66         return PQgetlength(m_result.get(), row, col);
67     }
68 
69     /**
70      * Get value of the field at (row, col) as char pointer. The string is
71      * null-terminated. Only valid as long as the pg_result_t is in scope.
72      */
get_value(int row,int col) const73     char const *get_value(int row, int col) const noexcept
74     {
75         assert(row < num_tuples() && col < num_fields());
76         return PQgetvalue(m_result.get(), row, col);
77     }
78 
79     /**
80      * Create a std::string with the value of the field at (row, col). This
81      * does the correct thing for binary data.
82      */
get_value_as_string(int row,int col) const83     std::string get_value_as_string(int row, int col) const noexcept
84     {
85         return std::string(get_value(row, col),
86                            (std::size_t)get_length(row, col));
87     }
88 
89     /**
90      * Get the column number from the name. Returns -1 if there is no column
91      * of that name.
92      */
get_column_number(std::string const & name) const93     int get_column_number(std::string const &name) const noexcept
94     {
95         return PQfnumber(m_result.get(), ('"' + name + '"').c_str());
96     }
97 
98 private:
99     struct pg_result_deleter_t
100     {
operator ()pg_result_t::pg_result_deleter_t101         void operator()(PGresult *p) const noexcept { PQclear(p); }
102     };
103 
104     std::unique_ptr<PGresult, pg_result_deleter_t> m_result;
105 };
106 
107 /**
108  * PostgreSQL connection.
109  *
110  * Wraps the PGconn object of the libpq library.
111  *
112  * The connection is automatically closed when the object is destroyed or
113  * you can close it explicitly by calling close().
114  */
115 class pg_conn_t
116 {
117 public:
118     explicit pg_conn_t(std::string const &conninfo);
119 
120     /// Execute a prepared statement with one parameter.
121     pg_result_t exec_prepared(char const *stmt, char const *param) const;
122 
123     /// Execute a prepared statement with two parameters.
124     pg_result_t exec_prepared(char const *stmt, char const *p1, char const *p2) const;
125 
126     /// Execute a prepared statement with one string parameter.
127     pg_result_t exec_prepared(char const *stmt, std::string const &param) const;
128 
129     /// Execute a prepared statement with one integer parameter.
130     pg_result_t exec_prepared(char const *stmt, osmid_t id) const;
131 
132     pg_result_t query(ExecStatusType expect, char const *sql) const;
133 
134     pg_result_t query(ExecStatusType expect, std::string const &sql) const;
135 
136     void set_config(char const *setting, char const *value) const;
137 
138     void exec(char const *sql) const;
139 
140     void exec(std::string const &sql) const;
141 
142     void copy_data(std::string const &sql, std::string const &context) const;
143 
144     void end_copy(std::string const &context) const;
145 
146     char const *error_msg() const noexcept;
147 
148     /// Close database connection.
close()149     void close() noexcept { m_conn.reset(); }
150 
151 private:
152     pg_result_t exec_prepared_internal(char const *stmt, int num_params,
153                                        char const *const *param_values) const;
154 
155     struct pg_conn_deleter_t
156     {
operator ()pg_conn_t::pg_conn_deleter_t157         void operator()(PGconn *p) const noexcept { PQfinish(p); }
158     };
159 
160     std::unique_ptr<PGconn, pg_conn_deleter_t> m_conn;
161 };
162 
163 /**
164  * Return a TABLESPACE clause with the specified tablespace name or an empty
165  * string if the name is empty.
166  */
167 std::string tablespace_clause(std::string const &name);
168 
169 /**
170  * Return the possibly schema-qualified name of a table. Names are enclosed
171  * in double quotes.
172  */
173 std::string qualified_name(std::string const &schema, std::string const &name);
174 
175 struct postgis_version
176 {
177     int major;
178     int minor;
179 };
180 
181 /// Get all config settings from the database.
182 std::map<std::string, std::string>
183 get_postgresql_settings(pg_conn_t const &db_connection);
184 
185 /// Get PostGIS major and minor version.
186 postgis_version get_postgis_version(pg_conn_t const &db_connection);
187 
188 #endif // OSM2PGSQL_PGSQL_HPP
189