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 ¶m) 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