Mercurial > code
view C++/DriverPostgres.cpp @ 190:d263f85f43a4
Update escape string for PostgreSQL strings
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 27 Nov 2013 10:25:58 +0100 |
parents | cc1e5fe1ee2c |
children | 6c49e5e3ecc8 |
line wrap: on
line source
/* * DriverPostgres.cpp -- PostgreSQL driver * * Copyright (c) 2013, David Demelier <markand@malikania.fr> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <sstream> #include "DriverPostgres.h" /* -------------------------------------------------------- * Query PostgreSQL (protected methods) * -------------------------------------------------------- */ bool QueryPostgres::getBoolean(int row, const std::string &column) { int idx = PQfnumber(m_result.get(), column.c_str()); std::string code = PQgetvalue(m_result.get(), row, idx); return code[0] == 't'; } Date QueryPostgres::getDate(int row, const std::string &column) { int idx = PQfnumber(m_result.get(), column.c_str()); long timestamp = static_cast<long>(time(0)); try { std::ostringstream oss; std::string value, req; value = PQgetvalue(m_result.get(), row, idx); /* * Convert the date using the SQL function so that user does * not require any explicit conversion itself. */ oss << "Select EXTRACT(EPOCH FROM TIMESTAMP '"; oss << value; oss << "') AS RESULT"; req = oss.str(); Query::Ptr result = m_driver->query(req); timestamp = result->get<double>(0, "RESULT"); } catch (...) { } return Date(static_cast<time_t>(timestamp)); } double QueryPostgres::getDouble(int row, const std::string &column) { int idx = PQfnumber(m_result.get(), column.c_str()); return std::stod(PQgetvalue(m_result.get(), row, idx)); } int QueryPostgres::getInt(int row, const std::string &column) { int idx = PQfnumber(m_result.get(), column.c_str()); return std::stoi(PQgetvalue(m_result.get(), row, idx)); } std::string QueryPostgres::getString(int row, const std::string &column) { int idx = PQfnumber(m_result.get(), column.c_str()); return std::string(PQgetvalue(m_result.get(), row, idx)); } /* -------------------------------------------------------- * Query PostgreSQL (public methods) * -------------------------------------------------------- */ QueryPostgres::QueryPostgres(Driver::Ptr driver, PostgresResult result) { m_driver = driver; m_result = std::move(result); } QueryPostgres::~QueryPostgres() { } ColumnType QueryPostgres::type(const std::string &column) const { ColumnType type; int pqType, index; index = PQfnumber(m_result.get(), column.c_str()); pqType = PQftype(m_result.get(), index); switch (pqType) { case 16: type = ColumnType::Boolean; break; case 1082: case 1083: case 1114: type = ColumnType::Date; break; case 1700: case 700: case 701: type = ColumnType::Double; break; case 20: case 21: case 23: type = ColumnType::Integer; break; case 25: case 1042: case 1043: type = ColumnType::String; break; default: type = ColumnType::Invalid; } return type; } int QueryPostgres::countRows() { return PQntuples(m_result.get()); } int QueryPostgres::countColumns() { return PQnfields(m_result.get()); } bool QueryPostgres::isNull(int row, const std::string &column) { int idx = PQfnumber(m_result.get(), column.c_str()); return PQgetisnull(m_result.get(), row, idx) == 1; } void QueryPostgres::dump(void) { std::cout << "Dumping PostgreSQL result, "; std::cout << countRows() << " rows, "; std::cout << countColumns() << " columns" << std::endl; for (int r = 0; r < countRows(); ++r) { std::cout << "Dumping row " << r << std::endl; std::cout << "==============================" << std::endl; for (int c = 0; c < countColumns(); ++c) { std::cout << "\t" << PQfname(m_result.get(), c); std::cout << " = " << PQgetvalue(m_result.get(), r, c) << std::endl; } } } /* -------------------------------------------------------- * Request PostgreSQL * -------------------------------------------------------- */ RequestPostgres::RequestPostgres(std::shared_ptr<PGconn> conn, const std::string &command) : Request(command) { m_connection = conn; } std::string RequestPostgres::bindBoolean(bool value) { return (value) ? "'t'" : "'f'"; } std::string RequestPostgres::bindDate(Date value) { std::ostringstream oss; oss << "to_timestamp("; oss << value.getTimestamp(); oss << ")"; return oss.str(); } std::string RequestPostgres::bindDouble(double value) { return std::to_string(value); } std::string RequestPostgres::bindInt(int value) { return std::to_string(value); } std::string RequestPostgres::bindString(std::string value) { std::string result; char *tmp; tmp = PQescapeLiteral(m_connection.get(), value.c_str(), value.length()); if (tmp == nullptr) return ""; result = std::string(tmp); PQfreemem(tmp); return result; } /* -------------------------------------------------------- * Driver PostgreSQL * -------------------------------------------------------- */ DriverPostgres::DriverPostgres() { } DriverPostgres::~DriverPostgres() { } std::string DriverPostgres::convert(Params ¶ms) { std::ostringstream oss; oss << "host = " << params["host"] << " "; oss << "port = " << params["port"] << " "; oss << "user = " << params["user"] << " "; oss << "dbname = " << params["database"] << " "; oss << "password = " << params["password"]; return oss.str(); } bool DriverPostgres::connect(const Params ¶ms) { Params copy = params; PGconn *conn = PQconnectdb(convert(copy).c_str()); if (conn == nullptr) { m_error = strerror(ENOMEM); return false; } if (PQstatus(conn) == CONNECTION_BAD) { m_error = PQerrorMessage(conn); PQfinish(conn); return false; } m_connection = std::shared_ptr<PGconn>(conn, PGDeleter()); return true; } Request::Ptr DriverPostgres::prepare(const std::string &command) { return std::make_shared<RequestPostgres>(m_connection, command); } Query::Ptr DriverPostgres::query(const std::string &cmd) { PGresult *info; // If NULL, the libpq said no memory info = PQexec(m_connection.get(), cmd.c_str()); if (info == nullptr) throw Query::Error(strerror(ENOMEM)); // If an error occured int errorCode = PQresultStatus(info); if (errorCode != PGRES_COMMAND_OK && errorCode != PGRES_TUPLES_OK) { std::string error = PQresultErrorMessage(info); PQclear(info); throw Query::Error(error); } return std::unique_ptr<Query>(new QueryPostgres(shared_from_this(), QueryPostgres::PostgresResult(info))); } std::string DriverPostgres::description() const { std::ostringstream oss; oss << "Connected on PostgreSQL database: " << std::endl; oss << " host: " << PQhost(m_connection.get()) << std::endl; oss << " port: " << PQport(m_connection.get()) << std::endl; oss << " user: " << PQuser(m_connection.get()) << std::endl; oss << " database: " << PQdb(m_connection.get()) << std::endl; return oss.str(); } std::string DriverPostgres::version() const { std::ostringstream oss; oss << "PostgreSQL driver (version " << PQlibVersion() << ")"; return oss.str(); }