diff --git a/src/expire-tiles.cpp b/src/expire-tiles.cpp index e6e42f4c7..4178868e8 100644 --- a/src/expire-tiles.cpp +++ b/src/expire-tiles.cpp @@ -291,8 +291,7 @@ int expire_from_result(expire_tiles *expire, pg_result_t const &result) auto const num_tuples = result.num_tuples(); for (int i = 0; i < num_tuples; ++i) { - char const *const wkb = result.get_value(i, 0); - expire->from_geometry(ewkb_to_geom(decode_hex(wkb))); + expire->from_geometry(ewkb_to_geom(result.get(i, 0))); } return num_tuples; diff --git a/src/flex-table.cpp b/src/flex-table.cpp index a2eb38635..622fa9c16 100644 --- a/src/flex-table.cpp +++ b/src/flex-table.cpp @@ -399,10 +399,10 @@ pg_result_t table_connection_t::get_geom_by_id(osmium::item_type type, assert(table().has_geom_column()); assert(m_db_connection); if (table().has_multicolumn_id_index()) { - return m_db_connection->exec_prepared("get_wkb", type_to_char(type), - id); + return m_db_connection->exec_prepared_as_binary("get_wkb", + type_to_char(type), id); } - return m_db_connection->exec_prepared("get_wkb", id); + return m_db_connection->exec_prepared_as_binary("get_wkb", id); } void table_connection_t::delete_rows_with(osmium::item_type type, osmid_t id) diff --git a/src/pgsql.cpp b/src/pgsql.cpp index 638353cdc..96caca503 100644 --- a/src/pgsql.cpp +++ b/src/pgsql.cpp @@ -132,9 +132,11 @@ static std::string concat_params(int num_params, return joiner(); } -pg_result_t -pg_conn_t::exec_prepared_internal(char const *stmt, int num_params, - char const *const *param_values) const +pg_result_t pg_conn_t::exec_prepared_internal(char const *stmt, int num_params, + char const *const *param_values, + int *param_lengths, + int *param_formats, + int result_format) const { assert(m_conn); @@ -142,8 +144,11 @@ pg_conn_t::exec_prepared_internal(char const *stmt, int num_params, log_sql("EXECUTE {}({})", stmt, concat_params(num_params, param_values)); } + pg_result_t res{PQexecPrepared(m_conn.get(), stmt, num_params, param_values, - nullptr, nullptr, 0)}; + param_lengths, param_formats, + result_format)}; + auto const status = res.status(); if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) { log_error("SQL command failed: EXECUTE {}({})", stmt, diff --git a/src/pgsql.hpp b/src/pgsql.hpp index f95220270..c21e5175b 100644 --- a/src/pgsql.hpp +++ b/src/pgsql.hpp @@ -205,7 +205,8 @@ class pg_conn_t } /** - * Run the named prepared SQL statement and return the results. + * Run the named prepared SQL statement and return the results in text + * format. * * \param stmt The name of the prepared statement. * \param params Any number of arguments (will be converted to strings @@ -215,25 +216,24 @@ class pg_conn_t template pg_result_t exec_prepared(char const *stmt, TArgs... params) const { - // We have to convert all non-string parameters into strings and - // store them somewhere. We use the exec_params vector for this. - // It needs to be large enough to hold all parameters without resizing - // so that pointers into the strings in that vector remain valid - // after new parameters have been added. - constexpr auto const total_buffers_needed = - (0 + ... + detail::exec_arg::buffers_needed); - std::vector exec_params; - exec_params.reserve(total_buffers_needed); - - // This array holds the pointers to all parameter strings, either - // to the original string parameters or to the recently converted - // in the exec_params vector. - std::array param_ptrs = { - detail::exec_arg::to_str(&exec_params, - std::forward(params))...}; + return exec_prepared_with_result_format(stmt, false, + std::forward(params)...); + } - return exec_prepared_internal(stmt, sizeof...(params), - param_ptrs.data()); + /** + * Run the named prepared SQL statement and return the results in binary + * format. + * + * \param stmt The name of the prepared statement. + * \param params Any number of arguments (will be converted to strings + * if necessary). + * \throws exception if the command failed. + */ + template + pg_result_t exec_prepared_as_binary(char const *stmt, TArgs... params) const + { + return exec_prepared_with_result_format(stmt, true, + std::forward(params)...); } /** @@ -254,7 +254,46 @@ class pg_conn_t private: pg_result_t exec_prepared_internal(char const *stmt, int num_params, - char const *const *param_values) const; + char const *const *param_values, + int *param_lengths, int *param_formats, + int result_format) const; + + /** + * Run the named prepared SQL statement and return the results. + * + * \param stmt The name of the prepared statement. + * \param result_as_binary Ask for the resuls to be returned in binary + * format. + * \param params Any number of arguments (will be converted to strings + * if necessary). + * \throws exception if the command failed. + */ + template + pg_result_t exec_prepared_with_result_format(char const *stmt, + bool result_as_binary, + TArgs... params) const + { + // We have to convert all non-string parameters into strings and + // store them somewhere. We use the exec_params vector for this. + // It needs to be large enough to hold all parameters without resizing + // so that pointers into the strings in that vector remain valid + // after new parameters have been added. + constexpr auto const total_buffers_needed = + (0 + ... + detail::exec_arg::buffers_needed); + std::vector exec_params; + exec_params.reserve(total_buffers_needed); + + // This array holds the pointers to all parameter strings, either + // to the original string parameters or to the recently converted + // in the exec_params vector. + std::array param_ptrs = { + detail::exec_arg::to_str(&exec_params, + std::forward(params))...}; + + return exec_prepared_internal(stmt, sizeof...(params), + param_ptrs.data(), nullptr, nullptr, + result_as_binary ? 1 : 0); + } struct pg_conn_deleter_t { diff --git a/src/table.cpp b/src/table.cpp index 598214c76..c5af69d6a 100644 --- a/src/table.cpp +++ b/src/table.cpp @@ -451,6 +451,6 @@ void table_t::escape_type(std::string const &value, ColumnType flags) pg_result_t table_t::get_wkb(osmid_t id) { - return m_sql_conn->exec_prepared("get_wkb", id); + return m_sql_conn->exec_prepared_as_binary("get_wkb", id); }