/* * This file is a part of morm * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2018-2021, 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. * */ // for sleep() #include #include "postgresqlconnector.h" #include "utf8/utf8.h" #include "postgresqlexpression.h" #include "convert/strtoint.h" namespace morm { PostgreSQLConnector::PostgreSQLConnector() { pg_conn = nullptr; } PostgreSQLConnector::~PostgreSQLConnector() { close(); } void PostgreSQLConnector::close() { if( pg_conn ) { PQfinish(pg_conn); pg_conn = nullptr; } } void PostgreSQLConnector::allocate_default_expression() { deallocate_expression(); db_expression = new PostgreSQLExpression(); expression_allocated = true; } QueryResult * PostgreSQLConnector::create_query_result() { return new PostgreSQLQueryResult(); } bool PostgreSQLConnector::do_query(const char * query_str, PostgreSQLQueryResult * psql_result) { if( pg_conn && psql_result ) { psql_result->clear(); if( log_queries && log ) { (*log) << pt::Log::log3 << "Morm: query: " << query_str << pt::Log::logend; } psql_result->psql_result = PQexec(pg_conn, query_str); if( !psql_result->psql_result ) { if( PQstatus(pg_conn) != CONNECTION_OK ) { assert_connection(); psql_result->psql_result = PQexec(pg_conn, query_str); } } if( psql_result->psql_result ) { psql_result->psql_status = PQresultStatus(psql_result->psql_result); psql_result->result_rows = static_cast(PQntuples(psql_result->psql_result)); psql_result->result_cols = static_cast(PQnfields(psql_result->psql_result)); } if( !psql_result->psql_result || psql_result->psql_status == PGRES_FATAL_ERROR ) { const char * err_msg = PQerrorMessage(pg_conn); if( err_msg ) { pt::UTF8ToWide(err_msg, psql_result->error_msg); } if( log ) { (*log) << pt::Log::log1 << "Morm: Problem with this query: \"" << query_str << '\"' << pt::Log::logend; if( err_msg ) (*log) << pt::Log::log1 << "Morm: " << err_msg << pt::Log::logend; } } else { psql_result->status = true; } } return (pg_conn && psql_result && psql_result->psql_result != nullptr && psql_result->status); } bool PostgreSQLConnector::query(const char * query_str, QueryResult & query_result) { PostgreSQLQueryResult * psql_result = dynamic_cast(&query_result); return do_query(query_str, psql_result); } const char * PostgreSQLConnector::query_last_sequence(const wchar_t * sequence_table_name) { allocate_default_expression_if_needed(); if( db_expression ) { PostgreSQLQueryResult psql_result; stream.clear(); stream << "select currval(E'"; db_expression->esc(sequence_table_name, stream); stream << "');"; if( query_select(stream, psql_result) ) { if( psql_result.result_rows == 1 ) { return psql_result.get_value_from_result(0, 0); } else { if( log ) { (*log) << pt::Log::log1 << "Morm: expected only one row in sequence result, has: " << psql_result.result_rows << pt::Log::logend; } } } else { if( pg_conn && log ) { (*log) << pt::Log::log1 << "Morm: error (currval) for table: " << sequence_table_name << ", " << PQerrorMessage(pg_conn) << pt::Log::logend; } } } return nullptr; } bool PostgreSQLConnector::query(const pt::TextStream & stream, QueryResult & query_result) { stream.to_string(query_str); return query(query_str.c_str(), query_result); } bool PostgreSQLConnector::query(const std::string & query_str, QueryResult & query_result) { return query(query_str.c_str(), query_result); } bool PostgreSQLConnector::query_select(const char * query_str, QueryResult & query_result) { PostgreSQLQueryResult * psql_result = dynamic_cast(&query_result); bool result = false; if( psql_result ) { result = (do_query(query_str, psql_result) && psql_result->psql_status == PGRES_TUPLES_OK); psql_result->status = result; } return result; } bool PostgreSQLConnector::query_update(const char * query_str, QueryResult & query_result) { PostgreSQLQueryResult * psql_result = dynamic_cast(&query_result); bool result = false; if( psql_result ) { result = (do_query(query_str, psql_result) && psql_result->psql_status == PGRES_COMMAND_OK); psql_result->status = result; } return result; } bool PostgreSQLConnector::query_insert(const char * query_str, QueryResult & query_result) { PostgreSQLQueryResult * psql_result = dynamic_cast(&query_result); bool result = false; if( psql_result ) { result = (do_query(query_str, psql_result) && psql_result->psql_status == PGRES_COMMAND_OK); psql_result->status = result; } return result; } bool PostgreSQLConnector::query_remove(const char * query_str, QueryResult & query_result) { PostgreSQLQueryResult * psql_result = dynamic_cast(&query_result); bool result = false; if( psql_result ) { result = (do_query(query_str, psql_result) && psql_result->psql_status == PGRES_COMMAND_OK); psql_result->status = result; } return result; } bool PostgreSQLConnector::query_select(const pt::TextStream & stream, QueryResult & query_result) { stream.to_string(query_str); return query_select(query_str.c_str(), query_result); } bool PostgreSQLConnector::query_update(const pt::TextStream & stream, QueryResult & query_result) { stream.to_string(query_str); return query_update(query_str.c_str(), query_result); } bool PostgreSQLConnector::query_insert(const pt::TextStream & stream, QueryResult & query_result) { stream.to_string(query_str); return query_insert(query_str.c_str(), query_result); } bool PostgreSQLConnector::query_remove(const pt::TextStream & stream, QueryResult & query_result) { stream.to_string(query_str); return query_remove(query_str.c_str(), query_result); } //void PostgreSQLConnector::CreateIdList(const std::vector & id_tab, std::wstring & list, bool add_parentheses) //{ //wchar_t buffer[50]; //size_t buffer_len = sizeof(buffer) / sizeof(wchar_t); // // list.clear(); // // if( add_parentheses ) // list += '('; // // for(size_t i=0 ; i