view database/postgresql/src/driver.cpp @ 29:99792c6c8b06

Server: add initial postgresql account management, #475
author David Demelier <markand@malikania.fr>
date Thu, 26 May 2016 07:32:05 +0200
parents
children a1e80d991968
line wrap: on
line source

/*
 * driver.cpp -- PostgreSQL database driver
 *
 * Copyright (c) 2013-2016 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 <string>
#include <unordered_map>

#include <malikania/dynlib.h>

#include "driver.h"

namespace pgsql {

PGconn *connection{nullptr};

std::shared_ptr<PGresult> exec(const std::string &sql)
{
	std::shared_ptr<PGresult> ptr(PQexec(connection, sql.c_str()), PQclear);

	if (PQresultStatus(ptr.get()) != PGRES_TUPLES_OK && PQresultStatus(ptr.get()) != PGRES_COMMAND_OK)
		throw std::runtime_error(PQresultErrorMessage(ptr.get()));

	return ptr;
}

std::string escape(const std::string &input)
{
	auto text = PQescapeLiteral(connection, input.c_str(), input.length());

	if (!text)
		throw std::runtime_error(PQerrorMessage(connection));

	std::string result(text);

	PQfreemem(text);

	return result;
}

} // !pgsql

namespace {

std::string parameters(const std::unordered_map<std::string, std::string> &params)
{
	std::ostringstream oss;
	std::unordered_map<std::string, std::string>::const_iterator it;

	// Host.
	if ((it = params.find("host")) == params.end())
		throw std::runtime_error("missing 'host' parameter");

	oss << "host = " << it->second << " ";

	// Database.
	if ((it = params.find("database")) == params.end())
		throw std::runtime_error("missing 'database' parameter");

	oss << "dbname = " << it->second << " ";

	// User.
	if ((it = params.find("user")) == params.end())
		throw std::runtime_error("missing 'user' parameter");

	oss << "user = " << it->second << " ";

	// Port (optional).
	if ((it = params.find("port")) != params.end())
		oss << "port = " << it->second << " ";

	// Password (optional).
	if ((it = params.find("password")) != params.end())
		oss << "password = " << it->second << " ";

	return oss.str();
}

} // !namespace

extern "C" {

DYNLIB_EXPORT void malikania_driver_load(const std::unordered_map<std::string, std::string> &params)
{
	pgsql::connection = PQconnectdb(parameters(params).c_str());

	if (!pgsql::connection)
		throw std::runtime_error(PQerrorMessage(pgsql::connection));
}

DYNLIB_EXPORT void malikania_driver_unload()
{
	if (pgsql::connection) {
		PQfinish(pgsql::connection);
		pgsql::connection = nullptr;
	}
}

} // !C