/* * This file is a part of Winix * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2010-2022, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include "dbconn.h" #include "core/log.h" #include "core/error.h" namespace Winix { DbConn::DbConn() { pg_conn = 0; } DbConn::~DbConn() { Close(); } PGconn * DbConn::GetPgConn() { return pg_conn; } void DbConn::SetConnParam(const std::wstring & conn_string) { db_conn_string = conn_string; db_host.clear(); db_hostaddr.clear(); db_port.clear(); db_database.clear(); db_user.clear(); db_pass.clear(); } void DbConn::SetConnParam(const std::wstring & host, const std::wstring & hostaddr, const std::wstring & port, const std::wstring & database, const std::wstring & user, const std::wstring & pass) { db_conn_string.clear(); db_host = host; db_hostaddr = hostaddr; db_port = port; db_database = database; db_user = user; db_pass = pass; } void DbConn::Connect() { Close(); conn_info.Clear(); conn_info.SetExtented(false); if( !db_conn_string.empty() ) { conn_info << R(db_conn_string); } else { conn_info << R("dbname=") << db_database << R(" user=") << db_user << R(" password=") << db_pass; if( !db_host.empty() ) { conn_info << R(L" host=") << db_host; } if( !db_hostaddr.empty() ) { conn_info << R(L" hostaddr=") << db_hostaddr; } if( !db_port.empty() ) { conn_info << R(L" port=") << db_port; } } pg_conn = PQconnectdb(conn_info.CStr()); // warning! pg_conn can be not null but there cannnot be a connection established // use PQstatus(pg_conn) to check whether the connection works fine } void DbConn::LogNoConnection(size_t attempts) { log << log2 << "Db: connection to the database cannot be established"; log << ", (" << attempts << " attempt(s))" << logend; log << logsave; } void DbConn::LogConnectionSocket() { log << log2 << "Db: connection to the database works fine" << logend; log << log3 << "Db: connection socket: " << PQsocket(pg_conn) << logend; log << logsave; } bool DbConn::WaitForConnection(size_t attempts_max, size_t attempt_delay) { size_t attempts = 0; bool attempts_exceeded = false; if( attempt_delay == 0 ) attempt_delay = 1; if( attempt_delay > 120 ) attempt_delay = 120; if( !pg_conn || PQstatus(pg_conn) != CONNECTION_OK ) { log << log3 << "Db: waiting for the db to be ready...." << logend << logsave; while( !attempts_exceeded && !AssertConnection(false, false) ) { if( attempts_max != 0 ) { attempts += 1; attempts_exceeded = (attempts >= attempts_max); } if( !attempts_exceeded ) { sleep(attempt_delay); } } } if( attempts_exceeded ) { LogNoConnection(attempts); } else { LogConnectionSocket(); } return !attempts_exceeded; } void DbConn::Close() { if( pg_conn ) { PQfinish(pg_conn); pg_conn = 0; } } bool DbConn::AssertConnection(bool put_log, bool throw_if_no_connection) { bool was_connection = true; if( !pg_conn ) { was_connection = false; Connect(); } else if( PQstatus(pg_conn) != CONNECTION_OK ) { if( put_log ) log << log2 << "Db: connection to the database is lost, trying to recover" << logend; was_connection = false; PQreset(pg_conn); } if( pg_conn && PQstatus(pg_conn) == CONNECTION_OK ) { if( !was_connection ) { if( put_log ) LogConnectionSocket(); SetDbParameters(); } return true; } else { if( put_log ) log << log1 << "Db: connection to db server cannot be established" << logend; if( throw_if_no_connection ) throw Error(WINIX_ERR_DB_FATAL_ERROR_DURING_CONNECTING); return false; } } void DbConn::SetDbParameters() { if( PQsetClientEncoding(pg_conn, "UTF8") == -1 ) log << log1 << "Db: Can't set the proper client encoding" << logend; } } // namespace Winix