diff --git a/README.md b/README.md index c22cb8d..27daec7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -# npgsql_wrapper (C++) -PgSQL C++ Wrapper for web_jsx (FCGI/CGI Application)
+# Multi Connection Pool PgSQL C++ Wrapper for web_jsx (FCGI/CGI Application)
#Include header file ```c++ #if !defined(_npgsql_h) diff --git a/src/connection_state.h b/src/connection_state.h index 265a418..4ff4600 100644 --- a/src/connection_state.h +++ b/src/connection_state.h @@ -4,15 +4,14 @@ * Copyrights licensed under the New BSD License. * See the accompanying LICENSE file for terms. */ +#if defined(_MSC_VER) #pragma once -#if !defined(_npgsql_global_h) -#include "npgsql_global.h" -#endif//!_global_h +#endif//!_MSC_VER #if !defined(_connection_state_h) -#define _connection_state_h -#pragma warning (disable : 4231) +# define _connection_state_h +//#pragma warning (disable : 4231) typedef enum { OPEN = 1, CLOSED = 0 } connection_state; -#endif//!_parameter_direction_h \ No newline at end of file +#endif//!_connection_state_h \ No newline at end of file diff --git a/src/npgsql.cpp b/src/npgsql.cpp index 7e76cbc..f2d1c22 100644 Binary files a/src/npgsql.cpp and b/src/npgsql.cpp differ diff --git a/src/npgsql.h b/src/npgsql.h index 957ad08..5a30bdc 100644 --- a/src/npgsql.h +++ b/src/npgsql.h @@ -1,71 +1,71 @@ ////8:44 AM 11/19/2018 Start +#if defined(_MSC_VER) #pragma once +#endif//!_MSC_VER #if !defined(_npgsql_h) #pragma warning (disable : 4231) -#define _npgsql_h -#if !defined(_npgsql_global_h) -#include "npgsql_global.h" -#endif//!_global_h -//5:27 PM 11/19/2018 -#if !defined(_pg_sql_h) -#include "pg_sql.h" -#endif//!_global_h -#if !defined(_npgsql_db_type_h) -#include "npgsql_db_type.h" -#endif//!_npgsql_db_type_h -#if !defined(_parameter_direction_h) -#include "npgsql_params.h" -#endif//!_parameter_direction_h -#if !defined(_npgsql_param_type_h) -#include "npgsql_param_type.h" -#endif//!_npgsql_param_type_h -#if !defined(_npgsql_result_h) -#include "npgsql_result.h" -#endif//!_npgsql_result_h -#if !defined(_connection_state_h) -#include "connection_state.h" -#endif//!_connection_state_h -#ifndef _REGEX_ -#include -#endif// !_REGEX_ +# define _npgsql_h +# include "npgsql_global.h" +# include "pg_sql.h" +# include "npgsql_db_type.h" +# include "npgsql_params.h" +# include "npgsql_param_type.h" +# include "npgsql_result.h" +# include "connection_state.h" +# include + +#if !defined(_free_obj) +# define _free_obj(obj)\ +while(obj){\ + obj->clear();delete obj;obj = NULL;\ +} +#endif//!_free_obj class NPGSQL_API npgsql { public: connection_state conn_state; private: + //pg_connection_pool _active_conn; //!TODO pg_sql* _pgsql; - const char* _conn; + std::string* _conn; char* _internal_error; void panic(const char* error); int check_con_status(); +protected: + int _is_disposed; + void create_instance(); public: - npgsql(const char* lib_path); - npgsql(); + explicit npgsql(const char* lib_path); + explicit npgsql(); + npgsql(const npgsql&) = delete; + npgsql& operator=(const npgsql&) = delete; ~npgsql(); void quote_literal(std::string&str) { str = "'" + str + "'"; return; - }; - virtual const char * get_last_error(); - virtual int connect(const char* conn); - virtual int execute_scalar(const char *query, char *result); - virtual int execute_scalar(const char *sp, std::list&sql_param, std::map& result); - virtual int execute_io(const char *sp, const char *login_id, const char *form_data, std::map& result); + } + const char * get_last_error(); + int connect(const char* conn); + int connect(); + int execute_scalar(const char *query, char *result); + int execute_scalar(const char *sp, std::list&sql_param, std::map& result); + int execute_io(const char *sp, const char *login_id, const char *form_data, std::map& result); // Execute the statement - virtual int execute_non_query(const char *query); - virtual const char* execute_query(const char * query, int&rec); + int execute_non_query(const char *query); + const char* execute_query(const char * query, int&rec); template int execute_scalar(const char *query, _func func); template int execute_scalar(const char *query, std::list&sql_param, _func func); template int execute_scalar_l(const char *query, std::list&sql_param, _func func); - virtual int close(); + int close(); + void release(); }; #pragma warning (default : 4231) template inline int npgsql::execute_scalar(const char * query, _func func) { return _pgsql->execute_scalar(query, func); -}; +} template inline int npgsql::execute_scalar( const char* query, std::list& sql_param, _func func ) { @@ -85,7 +85,7 @@ inline int npgsql::execute_scalar( const char* query, std::list& param_stmt->append( param->parameter_name ); param_stmt->append( "=" ); param_stmt->append( val->c_str() ); - free( val ); + _free_obj( val ); param_stmt->append( "::" ); param_stmt->append( get_db_type( param->db_type ) ); continue; @@ -95,19 +95,19 @@ inline int npgsql::execute_scalar( const char* query, std::list& param_stmt->append( param->parameter_name ); param_stmt->append( "=" ); param_stmt->append( val->c_str() ); - free( val ); + _free_obj( val ); param_stmt->append( "::" ); param_stmt->append( get_db_type( param->db_type ) ); } int ret = 0; if ( param_count <= 0 ) { - free( param_stmt ); + _free_obj(param_stmt); ret = _pgsql->execute_scalar( query, func ); } else { std::string* stmt = new std::string( query ); - stmt->append( param_stmt->c_str() ); free( param_stmt ); + stmt->append( param_stmt->c_str() ); ret = _pgsql->execute_scalar( stmt->c_str(), func ); - free( stmt ); + _free_obj(stmt); _free_obj(param_stmt); } return ret; } @@ -136,15 +136,11 @@ inline int npgsql::execute_scalar_l( const char* query, std::listc_str() ); - //std::cout << val->c_str() << "
"; - //std::cout << copy << "
"; - free( str ); free( re ); free( val ); + _free_obj(str); delete re; _free_obj(val); } } - //std::cout << _query->c_str() << "
"; int ret = _pgsql->execute_scalar( _query->c_str(), func ); - //free(_query); - delete _query; + _free_obj(_query); return ret; } #endif // !npgsql_h \ No newline at end of file diff --git a/src/npgsql.rc b/src/npgsql.rc index 4d6b456..6a0b9ba 100644 Binary files a/src/npgsql.rc and b/src/npgsql.rc differ diff --git a/src/npgsql_config.h b/src/npgsql_config.h new file mode 100644 index 0000000..7817e7c --- /dev/null +++ b/src/npgsql_config.h @@ -0,0 +1,25 @@ +/** +* Copyright (c) 2018, SOW (https://www.safeonline.world). (https://github.com/RKTUXYN) All rights reserved. +* @author {SOW} +* Copyrights licensed under the New BSD License. +* See the accompanying LICENSE file for terms. +*/ +//11:42 AM 2/19/2020 +#if defined(_MSC_VER) +#pragma once +#endif//!_MSC_VER +#if !defined(_npgsql_config_h) +# define _npgsql_config_h +#if defined(NPGSQL_EXPORTS) +# define NPGSQL_API __declspec(dllexport) +#else +# define NPGSQL_API __declspec(dllimport) +#endif//!NPGSQL_EXPORTS +#if !defined(_free_obj) +# define _free_obj(obj)\ +while(obj){\ + obj->clear();delete obj;obj = NULL;\ +} +#endif//!_free_obj +# define SUCCESS 1 +#endif//!_npgsql_config_h \ No newline at end of file diff --git a/src/npgsql_connection.cpp b/src/npgsql_connection.cpp new file mode 100644 index 0000000..86d284f --- /dev/null +++ b/src/npgsql_connection.cpp @@ -0,0 +1,309 @@ +/** +* Copyright (c) 2018, SOW (https://www.safeonline.world). (https://github.com/RKTUXYN) All rights reserved. +* @author {SOW} +* Copyrights licensed under the New BSD License. +* See the accompanying LICENSE file for terms. +*/ +# include "npgsql_connection.h" +# include "npgsql_global.h" +# include +# include +#if !defined(FALSE) +# define FALSE 0 +#endif//!FALSE + +#if !defined(TRUE) +# define TRUE 1 +#endif//!FALSE +/*Delete execution result*/ +void clear_response(PGconn* conn) { + PGresult* res; + while ((res = PQgetResult(conn))) { + PQclear(res); + } +} +npgsql_connection::npgsql_connection() { + _active_pools = NULL; + _internal_error = NULL; + _errc = FALSE; _conn_info = NULL; + _conn_state = CLOSED; +} +void npgsql_connection::clear_conn_info() { + if (_conn_info != NULL) { + _free_obj(_conn_info->server); + _free_obj(_conn_info->database); + _free_obj(_conn_info->user); + _free_obj(_conn_info->pwd); + _free_obj(_conn_info->port); + delete _conn_info; + _conn_info = NULL; + } +} +npgsql_connection::~npgsql_connection(){ + clear_conn_info(); + this->exit_all(); +} + +int npgsql_connection::connect(pg_connection_info* conn){ + if (_conn_state == OPEN) { + close_all_connection(); this->clear_conn_info(); + } + this->_conn_info = conn; + if (validate_cinfo( ) < 0) { + return _errc; + } + pg_connection_pool* cpool = create_connection_pool();/** open one connection*/ + if (cpool->conn_state != OPEN) { + return -1; + } + if (_errc < 0)return _errc; + free_connection_pool(cpool); + return _errc; +} + +int npgsql_connection::connect(const char* conn){ + if (this->parse_connection_string(conn) < 0) { + return _errc; + } + return this->connect(); +} + +int npgsql_connection::connect(){ + if (this->_conn_info == NULL) { + throw new std::exception("Connection info required..."); + } + if (validate_cinfo() < 0) { + return _errc; + } + close_all_connection(); + pg_connection_pool* cpool = create_connection_pool();/** open one connection*/ + if (cpool->conn_state != OPEN) { + return -1; + } + if (_errc < 0)return _errc; + free_connection_pool(cpool); + return _errc; +} + +pg_connection_pool* npgsql_connection::create_connection_pool() { + pg_connection_pool* cpool = NULL; + if (_active_pools != NULL) { + for (cpool = _active_pools; cpool; cpool = cpool->next) { + if (cpool->busy < 0 || !cpool->busy) break; + } + if (cpool && cpool->busy) { + cpool = NULL; + } + } + if (cpool == NULL || cpool->busy < 0 || cpool->conn_state == CLOSED) { + if (cpool == NULL) { + cpool = new pg_connection_pool; + } + cpool->conn = PQsetdbLogin( + /*const char *pghost*/_conn_info->server->c_str(), + /*const char *pgport*/_conn_info->port->c_str(), + /*const char *pgoptions*/NULL, + /*const char *pgtty*/NULL, + /*const char *dbName*/_conn_info->database->c_str(), + /*const char *login*/_conn_info->user->c_str(), + /*const char *pwd*/_conn_info->pwd->c_str() + ); + if (PQstatus(cpool->conn) != CONNECTION_OK) { + cpool->error_code = -2; + panic(PQerrorMessage(cpool->conn)); + cpool->error_msg = get_last_error(); + cpool->conn_state = CLOSED; + } + else { + cpool->conn_state = OPEN; + } + if (cpool->conn_state == OPEN) { + cpool->error_code = 0; + cpool->error_msg = NULL; + cpool->busy = -1; + } + else { + cpool->busy = 1; + } + cpool->next = _active_pools; + _active_pools = cpool; + _conn_state = OPEN; + return cpool; + } + else { + cpool->busy++; + } + return cpool; +} + +void npgsql_connection::free_connection_pool(pg_connection_pool* cpool){ + cpool->busy = 0; + cpool->error_code = 0; + cpool->error_msg = NULL; +} + +void npgsql_connection::exit_all(){ + if (_internal_error != NULL) { + delete[]_internal_error; _internal_error = NULL; + } + close_all_connection(); clear_conn_info(); +} +void npgsql_connection::exit_nicely(pg_connection_pool* cpool) { + if (cpool == NULL || cpool->conn == NULL)return; + clear_response(cpool->conn); + PQfinish(cpool->conn); cpool->conn = NULL; + cpool->busy = -1; + cpool->conn_state = CLOSED; + cpool->error_code = 0; + cpool->error_msg = NULL; +} + +void npgsql_connection::close_all_connection(){ + if (_conn_state == CLOSED)return; + if (_active_pools == NULL)return; + pg_connection_pool* cpool; + for (cpool = _active_pools; cpool; cpool = cpool->next) { + if (cpool->busy < 0)continue; + clear_response(cpool->conn); + PQfinish(cpool->conn); + } + while (_active_pools) { + cpool = _active_pools; + _active_pools = _active_pools->next; + if (cpool->busy) { + //fprintf(stderr,"destroying Database object before Connect object(s)\n"); + } + cpool->conn = NULL; + cpool->busy = -1; + cpool->error_msg = NULL; + delete cpool; + } + _conn_state = CLOSED; + if (_active_pools != NULL) + delete _active_pools; + _active_pools = NULL; +} + +const char* npgsql_connection::get_last_error(){ + if (_errc >= 0) return "No Error Found!!!"; + return const_cast(_internal_error); +} + +connection_state npgsql_connection::conn_state(){ + return _conn_state; +} +//constexpr const char* +#define _conn_user_error "No user defined (e.g. postgress) in given connection string as `UserId`!!!" +#define _conn_pwd_error "No password defined (e.g. 123456) in given connection string as `Password`!!!" +#define _conn_db_error "No database defined (e.g. sow) in given connection string as `Database`!!!" +#define _conn_server_error "No server defined (e.g. localhost) in given connection string as `Password`!!!" +#define _conn_port_error "No port defined (e.g. 5432) in given connection string as `Port`!!!" + +int npgsql_connection::parse_connection_string(const char* conn){ + if (conn == NULL || strlen(conn) == 0) { + panic("No connection string found!!!"); + return -1; + } + std::string* query = new std::string(conn); + std::regex pattern("([\\w+%]+)=([^;]*)"); + std::map conn_obj; + auto words_begin = std::sregex_iterator(query->begin(), query->end(), pattern); + auto words_end = std::sregex_iterator(); + for (std::sregex_iterator i = words_begin; i != words_end; i++) { + std::string key = (*i)[1].str(); + std::string value = (*i)[2].str(); + if (conn_obj.find(key) != conn_obj.end()) { + key = "Duplicate key found in connection string ==> `" + key + "`!!!"; + panic(key.c_str()); + _free_obj(query); + goto _ERROR; + } + conn_obj[key] = value; + } + _free_obj(query); + if (_conn_info == NULL) { + _conn_info = new pg_connection_info(); + } + _conn_info->user = new std::string(conn_obj["UserId"]); + if (_conn_info->user->empty()) { + panic(_conn_user_error); + goto _ERROR; + } + _conn_info->pwd = new std::string(conn_obj["Password"]); + if (_conn_info->pwd->empty()) { + panic(_conn_pwd_error); + goto _ERROR; + } + _conn_info->database = new std::string(conn_obj["Database"]); + if (_conn_info->database->empty()) { + panic(_conn_db_error); + goto _ERROR; + } + _conn_info->server = new std::string(conn_obj["Server"]); + if (_conn_info->server->empty()) { + panic(_conn_server_error); + goto _ERROR; + } + _conn_info->port = new std::string(conn_obj["Port"]); + if (_conn_info->port->empty()) { + panic(_conn_port_error); + goto _ERROR; + } + goto _END; +_ERROR: + conn_obj.clear(); + return _errc; +_END: + conn_obj.clear(); + return 1; +} + +int npgsql_connection::validate_cinfo(){ + if (_conn_info == NULL) { + panic("No connection info found!!!"); + return _errc; + } + if (_conn_info->user == NULL || _conn_info->user->empty()) { + panic(_conn_user_error); + return _errc; + } + if (_conn_info->pwd->empty()) { + panic(_conn_pwd_error); + return _errc; + } + if (_conn_info->database->empty()) { + panic(_conn_db_error); + return _errc; + } + if (_conn_info->server->empty()) { + panic(_conn_server_error); + return _errc; + } + if (_conn_info->port->empty()) { + panic(_conn_port_error); + return _errc; + } + return 1; +} + +void npgsql_connection::panic(const char* error){ + if (_internal_error != NULL) { + delete[]_internal_error; _internal_error = NULL; + } + size_t len = strlen(error); + _internal_error = new char[len + sizeof(char)]; + strcpy_s(_internal_error, len, error); + _internal_error[len] = '\000'; + _errc = -1; +} + +void npgsql_connection::panic(char* erro_msg){ + if (_internal_error != NULL) { + delete[]_internal_error; _internal_error = NULL; + } + size_t len = strlen(erro_msg); + _internal_error = new char[len + sizeof(char)]; + strcpy_s(_internal_error, len, erro_msg); + _internal_error[len] = '\000'; + _errc = -1; +} diff --git a/src/npgsql_connection.h b/src/npgsql_connection.h new file mode 100644 index 0000000..0a6b868 --- /dev/null +++ b/src/npgsql_connection.h @@ -0,0 +1,62 @@ +/** +* Copyright (c) 2018, SOW (https://www.safeonline.world). (https://github.com/RKTUXYN) All rights reserved. +* @author {SOW} +* Copyrights licensed under the New BSD License. +* See the accompanying LICENSE file for terms. +*/ +#if defined(_MSC_VER) +#pragma once +#endif//!_MSC_VER +//5:32 PM 12/17/2019 +#if !defined(_npgsql_connection_h) +#pragma warning (disable : 4231) +#pragma warning(disable : 4996) +# define _npgsql_connection_h +# include +# include "connection_state.h" +# include +# include "npgsql_config.h" +typedef struct pg_conn_pool { + struct pg_conn_pool* next; /* pointer to next member*/ + PGconn* conn; /* PgSQL connection handle*/ + connection_state conn_state; + int busy; /* connection busy flag*/ + int error_code; + const char* error_msg; +}pg_connection_pool; +typedef struct { + std::string* user; + std::string* pwd; + std::string* database; + std::string* server; + std::string* port; +}pg_connection_info; +class NPGSQL_API npgsql_connection { +public: + explicit npgsql_connection(); + npgsql_connection(const npgsql_connection&) = delete; + npgsql_connection& operator=(const npgsql_connection&) = delete; + ~npgsql_connection(); + int connect(pg_connection_info* conn); + int connect(const char* conn); + int connect(); + pg_connection_pool* create_connection_pool(); + void free_connection_pool(pg_connection_pool* cpool); + void exit_all(); + void close_all_connection(); + const char* get_last_error(); + connection_state conn_state(); + void exit_nicely(pg_connection_pool* cpool); +protected: + int parse_connection_string(const char* conn); + int validate_cinfo(); + void clear_conn_info(); + connection_state _conn_state; + pg_connection_info* _conn_info; + pg_connection_pool* _active_pools; + int _errc; + char* _internal_error; + void panic(const char* error); + void panic(char* erro_msg); +}; +#endif//!_npgsql_connection_h \ No newline at end of file diff --git a/src/npgsql_db_type.h b/src/npgsql_db_type.h index d080827..e7a4f6b 100644 --- a/src/npgsql_db_type.h +++ b/src/npgsql_db_type.h @@ -1,11 +1,9 @@ //5:27 PM 11/19/2018 +#if defined(_MSC_VER) #pragma once -#if !defined(_npgsql_global_h) -#include "npgsql_global.h" -#endif//!_global_h +#endif//!_MSC_VER #if !defined(_npgsql_db_type_h) -#define _npgsql_db_type_h -#pragma warning (disable : 4231) +# define _npgsql_db_type_h typedef enum { COMMON = -1, NULL_=-2, @@ -402,7 +400,9 @@ static const char* get_db_type(npgsql_db_type db_type) { case npgsql_db_type::Jsonb:return "jsonb"; case npgsql_db_type::Varchar:return "varchar"; case npgsql_db_type::Boolean:return "boolean"; + case npgsql_db_type::Integer:return "integer"; + //case npgsql_db_type::Array: return "integer"; default:return "unknown"; } -}; +} #endif//!_npgsql_db_type_h \ No newline at end of file diff --git a/src/npgsql_global.h b/src/npgsql_global.h index 189f73e..f72d545 100644 --- a/src/npgsql_global.h +++ b/src/npgsql_global.h @@ -5,39 +5,19 @@ * Copyrights licensed under the New BSD License. * See the accompanying LICENSE file for terms. */ +#if defined(_MSC_VER) #pragma once +#endif//!_MSC_VER #if !defined(_npgsql_global_h) -#define _npgsql_global_h -#define SUCCESS 1 -#if !defined(_IOSTREAM_) -#include -#endif//!_IOSTREAM_ -#if !defined(_INC_STDIO) -#include /* defines FILENAME_MAX */ -#endif//!_INC_STDIO -#ifndef _LIST_ -#include -#endif // !_LIST_ -#ifndef _MAP_ -#include -#endif // !_MAP_ -#ifndef _INC_STDLIB -#include -#endif // !_INC_STDLIB -#ifndef _REGEX_ -#include -#endif// !_REGEX_ -#include -#if !defined(_VECTOR_) -#include -#endif//!_VECTOR_ -#if !defined(NPGSQL_EXPORTS) -#define NPGSQL_EXPORTS -#endif//!NPGSQL_EXPORTS -#ifdef NPGSQL_EXPORTS -#define NPGSQL_API __declspec(dllexport) -#else -#define NPGSQL_API __declspec(dllimport) -#endif//!NPGSQL_EXPORTS +# define _npgsql_global_h +# include +# include +# include +# include +# include +# include +# include +# include +# include "npgsql_config.h" #endif//!_npgsql_global_h diff --git a/src/npgsql_param_type.h b/src/npgsql_param_type.h index 2b8ea58..3483c31 100644 --- a/src/npgsql_param_type.h +++ b/src/npgsql_param_type.h @@ -1,12 +1,10 @@ +#if defined(_MSC_VER) #pragma once -#if !defined(_npgsql_global_h) -#include "npgsql_global.h" -#endif//!_global_h -#if !defined(_npgsql_db_type_h) -#include "npgsql_db_type.h" -#endif//!_npgsql_db_type_h +#endif//!_MSC_VER #if !defined(_npgsql_param_type_h) -#define _npgsql_param_type_h +# define _npgsql_param_type_h +# include "npgsql_global.h" +# include "npgsql_db_type.h" #pragma warning (disable : 4231) class NPGSQL_API npgsql_param_type { public: @@ -17,4 +15,4 @@ class NPGSQL_API npgsql_param_type { }; ~npgsql_param_type() {}; }; -#endif//!_global_h \ No newline at end of file +#endif//!_npgsql_param_type_h \ No newline at end of file diff --git a/src/npgsql_params.cpp b/src/npgsql_params.cpp index a249588..d78b373 100644 --- a/src/npgsql_params.cpp +++ b/src/npgsql_params.cpp @@ -4,18 +4,30 @@ * Copyrights licensed under the New BSD License. * See the accompanying LICENSE file for terms. */ -#include "npgsql_params.h" -npgsql_params::npgsql_params(const char * name, npgsql_db_type dtype, parameter_direction pd) { +# include "npgsql_params.h" +npgsql_params::npgsql_params( + const char * name, + npgsql_db_type dtype, + parameter_direction pd +) { this->parameter_name = name; this->db_type = dtype; this->direction = pd; this->value = NULL; -}; +} -npgsql_params::npgsql_params(const char * name, npgsql_db_type dtype, parameter_direction pd, const char * data) { +npgsql_params::npgsql_params( + const char * name, + npgsql_db_type dtype, + parameter_direction pd, + const char * data +) { this->parameter_name = name; this->db_type = dtype; this->direction = pd; this->value = data; -}; -npgsql_params::~npgsql_params() {}; +} +npgsql_params::~npgsql_params() { + this->parameter_name = NULL; + this->value = NULL; +} diff --git a/src/npgsql_params.h b/src/npgsql_params.h index 36716ee..e0df815 100644 --- a/src/npgsql_params.h +++ b/src/npgsql_params.h @@ -1,20 +1,15 @@ //5:27 PM 11/19/2018 +#if defined(_MSC_VER) #pragma once -#if !defined(_npgsql_global_h) -#include "npgsql_global.h" -#endif//!_global_h -#if !defined(_parameter_direction_h) -#define _npgsql_params_h -#if !defined(_parameter_direction_h) -#include "parameter_direction.h" -#endif//!_parameter_direction_h -#if !defined(_npgsql_db_type_h) -#include "npgsql_db_type.h" -#endif//!_npgsql_db_type_h +#endif//!_MSC_VER +#if !defined(_npgsql_params_h) +# define _npgsql_params_h +# include "npgsql_global.h" +# include "parameter_direction.h" +# include "npgsql_db_type.h" #pragma warning (disable : 4231) class NPGSQL_API npgsql_params { public: - //npgsql_params(const char* name, npgsql_db_type dtype, parameter_direction pd, void* data); npgsql_params(const char * name, npgsql_db_type dtype, parameter_direction pd, const char * data); npgsql_params(const char* name, npgsql_db_type dtype, parameter_direction pd); ~npgsql_params(); diff --git a/src/npgsql_pool.cpp b/src/npgsql_pool.cpp new file mode 100644 index 0000000..649c534 --- /dev/null +++ b/src/npgsql_pool.cpp @@ -0,0 +1,116 @@ +/** +* Copyright (c) 2018, SOW (https://www.safeonline.world). (https://github.com/RKTUXYN) All rights reserved. +* @author {SOW} +* Copyrights licensed under the New BSD License. +* See the accompanying LICENSE file for terms. +*/ +# include "npgsql_pool.h" +# include "npgsql_query.h" +npgsql_pool::npgsql_pool(){ + _errc = 0; _conn = new npgsql_connection(); + _internal_error = new char; + _conn_info = NULL; +} + +npgsql_pool::~npgsql_pool(){ + if (_conn == NULL)return; + if (_internal_error != NULL) { + free(_internal_error); _internal_error = NULL; + } + _conn->exit_all(); + delete _conn; _conn = NULL; + _conn_info = NULL; +} + +connection_state npgsql_pool::connect(const char* conn){ + if (this->_conn != NULL) { + this->_conn->exit_all(); + delete this->_conn; this->_conn = NULL; + } + int rec = this->_conn->connect(conn); + if (rec < 0) { + this->panic(this->_conn->get_last_error(), -1); + return CLOSED; + } + return OPEN; +} + +connection_state npgsql_pool::connect(pg_connection_info* conn){ + if (this->_conn != NULL) { + this->_conn->exit_all(); + delete this->_conn; this->_conn = NULL; + } + int rec = this->_conn->connect(conn); + if (rec < 0) { + this->panic(this->_conn->get_last_error(), -1); + return CLOSED; + } + return OPEN; +} + +int npgsql_pool::execute_scalar_x(const char* query, std::list& out_param_array, std::map& out_param_map){ + if (state() == CLOSED) { + this->panic("No active connectio found...", -1); + return _errc; + } + pg_connection_pool* cpool = this->_conn->create_connection_pool(); + if (cpool->error_code < 0) { + this->panic(cpool->error_msg, cpool->error_code); + this->_conn->exit_nicely(cpool); + return -1; + } + npgsql_query* pg_query = new npgsql_query(cpool); + int rec = pg_query->execute_scalar_x(query, out_param_array, out_param_map); + if (rec < 0) { + this->panic(pg_query->get_last_error(), -1); + } + pg_query->free_connection(); + delete pg_query; + return rec; +} + +int npgsql_pool::execute_non_query(const char* query){ + if (state() == CLOSED) { + this->panic("No active connectio found...", -1); + return _errc; + } + pg_connection_pool* cpool = this->_conn->create_connection_pool(); + if (cpool->error_code < 0) { + this->panic(cpool->error_msg, cpool->error_code); + this->_conn->exit_nicely(cpool); + return -1; + } + npgsql_query* pg_query = new npgsql_query(cpool); + int rec = pg_query->execute_non_query(query); + if (rec < 0) { + this->panic(pg_query->get_last_error(), -1); + } + pg_query->free_connection(); + delete pg_query; + return rec; +} + +const char* npgsql_pool::get_last_error(){ + if (_errc >= 0) return "No Error Found!!!"; + return const_cast(_internal_error); +} + +connection_state npgsql_pool::state(){ + return _conn == NULL ? CLOSED : _conn->conn_state(); +} + +void npgsql_pool::exit_all(){ + if (state() == CLOSED)return; + _conn->exit_all(); +} + +void npgsql_pool::close_all_connection(){ + if (state() == CLOSED)return; + _conn->close_all_connection(); +} +void npgsql_pool::panic(const char* error, int code = -1){ + free(_internal_error); + _internal_error = new char[strlen(error) + 1]; + strcpy(_internal_error, error); + _errc = code; +} diff --git a/src/npgsql_pool.h b/src/npgsql_pool.h new file mode 100644 index 0000000..8f69685 --- /dev/null +++ b/src/npgsql_pool.h @@ -0,0 +1,40 @@ +/** +* Copyright (c) 2018, SOW (https://www.safeonline.world). (https://github.com/RKTUXYN) All rights reserved. +* @author {SOW} +* Copyrights licensed under the New BSD License. +* See the accompanying LICENSE file for terms. +*/ +#if defined(_MSC_VER) +#pragma once +#endif//!_MSC_VER +//5:32 PM 12/17/2019 +#if !defined(_npgsql_pool_h) +#pragma warning (disable : 4231) +#pragma warning(disable : 4996) +# define _npgsql_pool_h +# include "npgsql_connection.h" +# include +# include +# include +class NPGSQL_API npgsql_pool { +public: + explicit npgsql_pool(); + npgsql_pool(const npgsql_pool&) = delete; + npgsql_pool& operator=(const npgsql_pool&) = delete; + ~npgsql_pool(); + connection_state connect(const char* conn); + connection_state connect(pg_connection_info* conn_info); + int execute_scalar_x(const char* query, std::list< std::string>& out_param_array, std::map& out_param_map); + int execute_non_query(const char* query); + const char* get_last_error(); + connection_state state(); + void exit_all(); + void close_all_connection(); +private: + const pg_connection_info* _conn_info; + npgsql_connection* _conn; + int _errc; + char* _internal_error; + void panic(const char* error, int code); +}; +#endif//!_npgsql_pool_h diff --git a/src/npgsql_query.cpp b/src/npgsql_query.cpp new file mode 100644 index 0000000..a46d8a2 --- /dev/null +++ b/src/npgsql_query.cpp @@ -0,0 +1,294 @@ +/** +* Copyright (c) 2018, SOW (https://www.safeonline.world). (https://github.com/RKTUXYN) All rights reserved. +* @author {SOW} +* Copyrights licensed under the New BSD License. +* See the accompanying LICENSE file for terms. +*/ +# include "npgsql_query.h" + +npgsql_query::npgsql_query(pg_connection_pool* cpool){ + _cpool = cpool; + _internal_error = NULL; + _errc = 0; +} + +npgsql_query::~npgsql_query() { + free_connection(); + if (_internal_error != NULL) { + delete[]_internal_error; + } +} +/*Delete execution result*/ +void npgsql_query::clear_response() { + PGresult* res; + while ((res = PQgetResult(_cpool->conn))) { + PQclear(res); + } +} +void npgsql_query::free_connection(){ + if ( _cpool ) { + _cpool->busy = 0; + _cpool->error_code = 0; + _cpool->error_msg = NULL; + _cpool = NULL; + } +} +const char* npgsql_query::execute_query(const char* query, int& rec){ + if (_cpool->conn_state == connection_state::CLOSED) { + panic("Connection state not opend!!!"); + return NULL; + } + if (_cpool->conn == NULL) { + panic("No Connection instance found !!!"); + return NULL; + } + if (((query != NULL) && (query[0] == '\0')) || query == NULL) { + panic("SQL Statement required!!!"); + return NULL; + } + //https://timmurphy.org/2009/11/19/pqexecparams-example-postgresql-query-execution-with-parameters/ + // Execute the statement + PGresult* res = PQexec(_cpool->conn, query); + const char* result = NULL; + ExecStatusType exs_type = PQresultStatus(res); + if (exs_type == PGRES_FATAL_ERROR) goto _ERROR; + if (exs_type == PGRES_NONFATAL_ERROR) goto _ERROR; + // Get the value of the first column of the first row + if (exs_type == PGRES_TUPLES_OK) { + char* resp = PQgetvalue(res, 0, 0); + result = const_cast(resp); + } + rec = 0; + goto _END; + +_ERROR: + panic( ); + goto _END; +_END: + /*Delete execution result*/ + //PQclear(res); + clear_response(); + return result; +} +void npgsql_query::exit_nicely() { + if ( _cpool ) { + PQfinish(_cpool->conn); + _cpool->conn = NULL; + _cpool->busy = -1; + _cpool->conn_state = connection_state::CLOSED; + _cpool->error_code = 0; + _cpool->error_msg = NULL; + } +} +int npgsql_query::execute_scalar_x(const char* query, std::list& out_param_array, std::map& out_param_map){ + if (_cpool->conn_state == connection_state::CLOSED) { + panic("Connection state not opend!!!"); + return -1; + } + if (_cpool->conn == NULL) { + panic("No Connection instance found !!!"); + return -1; + } + if (((query != NULL) && (query[0] == '\0')) || query == NULL) { + panic("SQL Statement required!!!"); + return -1; + } + bool exists = false; + try { + // Execute the statement + PGresult* res = PQexec(_cpool->conn, query); + //free_connection(); + ExecStatusType exs_type = PQresultStatus(res); + if (exs_type == PGRES_FATAL_ERROR) goto _ERROR; + if (exs_type == PGRES_NONFATAL_ERROR) goto _ERROR; + // Get the value of the first column of the first row + if (exs_type == PGRES_TUPLES_OK) { + int field_map = 0; + std::string prop; + size_t len = 0; + for (auto s = out_param_array.begin(); s != out_param_array.end(); ++s) { + prop = *s; + char* resp = PQgetvalue(res, 0, field_map); + len = strlen(resp); + char* copy_resp = new char[len + 1]; + strcpy(copy_resp, resp); + out_param_map[prop.c_str()] = copy_resp; + field_map++; + } + exists = true; + goto _END; + } + if (exs_type == PGRES_COMMAND_OK) { + exists = true; goto _END; + } + panic("Invalid response defined!!!!"); + goto _END; + _ERROR: + panic( ); goto _END; + _END: + /*Delete execution result*/ + //PQclear(res); + clear_response(); + } + catch (std::exception& e) { + panic(e.what()); + } + return (exists == true) ? 0 : -1; +} + +int npgsql_query::execute_non_query(const char* query) { + if (_cpool->conn_state == connection_state::CLOSED) { + panic("Connection state not opend!!!"); + return -1; + } + if (_cpool->conn == NULL) { + panic("No Connection instance found !!!"); + return -1; + } + if (((query != NULL) && (query[0] == '\0')) || query == NULL) { + panic("SQL Statement required!!!"); + return _errc; + } + // Execute the query + PGresult* result = PQexec(_cpool->conn, query); + //free_connection(); + bool error = false; + int rc = PQresultStatus(result); + // Error raised + if (rc != PGRES_COMMAND_OK) { + panic( ); + error = true; + } + /*Delete execution result*/ + clear_response(); + //PQclear(result); + return (error == true) ? -1 : 0; +} +int npgsql_query::execute_scalar(const char* sp, std::list& sql_param, std::map& result){ + if (_cpool->conn_state == connection_state::CLOSED) { + panic("Connection state not opend!!!"); + return -1; + } + std::string* out_param = new std::string(""); + std::string* in_param = new std::string(""); + int in_param_count = 0; + int out_param_count = 0; + std::list* out_param_array = new std::list(); + for (auto s = sql_param.begin(); s != sql_param.end(); ++s) { + npgsql_params* param = *s; + if (param->direction == parameter_direction::Input || param->direction == parameter_direction::InputOutput) { + std::string val = param->value; + //quote_literal(val); + if (in_param_count == 0) { + in_param_count++; + in_param->append("( "); + in_param->append(val); + in_param->append("::"); + in_param->append(get_db_type(param->db_type)); + } + else { + in_param_count++; + in_param->append(", "); + in_param->append(val); + in_param->append("::"); + in_param->append(get_db_type(param->db_type)); + } + if (param->direction != parameter_direction::InputOutput) + continue; + } + if (param->direction == parameter_direction::Output || param->direction == parameter_direction::InputOutput) { + result[param->parameter_name] = NULL; + out_param_array->push_back(param->parameter_name); + if (out_param_count == 0) { + out_param->append("f."); + out_param->append(param->parameter_name); + out_param_count++; + continue; + } + out_param->append(", f."); + out_param->append(param->parameter_name); + out_param_count++; + continue; + } + } + std::string* query = new std::string("select "); + if (out_param_count <= 0) { + query->append("f.* from "); + } + else { + query->append(out_param->c_str()); + query->append(" from "); + } + if (in_param_count <= 0) { + query->append(sp); + query->append("("); + } + else { + query->append(sp); + query->append(in_param->c_str()); + } + query->append(") as f "); + int ret = this->execute_scalar_x(query->c_str(), *out_param_array, result); + out_param->clear(); delete out_param; + in_param->clear(); delete in_param; + query->clear(); out_param_array->clear(); + delete query; delete out_param_array; + return ret; +} +int npgsql_query::execute_io(const char* sp, const char* ctx, const char* form_data, std::map& result){ + if (_cpool->conn_state == connection_state::CLOSED) { + panic("Connection state not opend!!!"); + return -1; + } + std::string* query = new std::string("select "); + query->append("f.* from "); + query->append(sp); + query->append("("); + std::string* val = new std::string(ctx); + quote_literal(*val); + query->append(val->c_str()); + val->clear(); delete val; + query->append("::"); + query->append(get_db_type(npgsql_db_type::Jsonb)); + query->append(","); + val = new std::string(form_data); + quote_literal(*val); + query->append(val->c_str()); + val->clear(); delete val; + query->append("::"); + query->append(get_db_type(npgsql_db_type::Jsonb)); + query->append(") as f "); + + std::list* out_param_array = new std::list(); + out_param_array->push_back("_ret_data_table"); + out_param_array->push_back("_ret_val"); + out_param_array->push_back("_ret_msg"); + int ret = this->execute_scalar_x(query->c_str(), *out_param_array, result); + out_param_array->clear(); delete out_param_array; + query->clear(); delete query; + return ret; +} + +const char* npgsql_query::get_last_error(){ + if (_errc >= 0) return "No Error Found!!!"; + return const_cast(_internal_error); +} + +void npgsql_query::panic(const char* error) { + if (_internal_error != NULL) + delete[]_internal_error; + _internal_error = new char[strlen(error) + 1]; + strcpy(_internal_error, error); + _errc = -1; +} + +void npgsql_query::panic() { + if (_internal_error != NULL) + delete[]_internal_error; + //if (_cpool == NULL)return; + //if (_cpool->conn == NULL)return; + char* erro_msg = PQerrorMessage(_cpool->conn); + _internal_error = new char[strlen(erro_msg) + 1]; + strcpy(_internal_error, const_cast(erro_msg)); + _errc = -1; +} \ No newline at end of file diff --git a/src/npgsql_query.h b/src/npgsql_query.h new file mode 100644 index 0000000..b44b065 --- /dev/null +++ b/src/npgsql_query.h @@ -0,0 +1,187 @@ +/** +* Copyright (c) 2018, SOW (https://www.safeonline.world). (https://github.com/RKTUXYN) All rights reserved. +* @author {SOW} +* Copyrights licensed under the New BSD License. +* See the accompanying LICENSE file for terms. +*/ +#if defined(_MSC_VER) +#pragma once +#endif//!_MSC_VER +//5:32 PM 12/17/2019 +#if !defined(_npgsql_query_h) +#pragma warning (disable : 4231) +#pragma warning(disable : 4996)//Disable strcpy warning +# define _npgsql_query_h +# include "npgsql_connection.h" +# include "npgsql_db_type.h" +# include "npgsql_params.h" +# include "npgsql_param_type.h" +# include "npgsql_result.h" +class NPGSQL_API npgsql_query { +public: + explicit npgsql_query(pg_connection_pool* cpool); + npgsql_query(const npgsql_query&) = delete; + npgsql_query& operator=(const npgsql_query&) = delete; + ~npgsql_query(); + void free_connection(); + const char* execute_query(const char* query, int& rec); + int execute_scalar_x(const char* query, std::list< std::string>& out_param_array, std::map& out_param_map); + int execute_non_query(const char* query); + int execute_scalar(const char* sp, std::list& sql_param, std::map& result); + int execute_io(const char* sp, const char* ctx, const char* form_data, std::map& result); + template + int execute_scalar_l(const char* query, std::list& sql_param, _func func); + template + int execute_scalar(const char* query, _func func); + template + int execute_scalar(const char* query, std::list& sql_param, _func func); + void quote_literal(std::string& str) { + str = "'" + str + "'"; + return; + } + const char* get_last_error(); + void exit_nicely(); +private: + pg_connection_pool* _cpool; + int _errc; + char* _internal_error; + void clear_response(); + void panic(const char* error); + void panic(); +}; + +template +int npgsql_query::execute_scalar_l(const char* query, std::list& sql_param, _func func) { + if (_cpool->conn_state == connection_state::CLOSED) { + panic("Connection state not opend!!!"); + return -1; + } + std::string* _query = new std::string(query); + if (!sql_param.empty()) { + int count = 0; + for (auto itr = sql_param.begin(); itr != sql_param.end(); ++itr) { + count++; + std::string* str = new std::string("\\$"); + str->append(std::to_string(count)); + std::regex* re = new std::regex(*str); + npgsql_param_type* key = *itr; + std::string* val; + if (key->db_type == npgsql_db_type::NULL_) { + val = new std::string("null"); + } + else { + val = new std::string(key->value); + if (key->db_type != npgsql_db_type::COMMON) { + val->append("::"); val->append(get_db_type(key->db_type)); + } + else { + quote_literal(*val); + } + } + std::string& copy = *_query; + copy = std::regex_replace(copy, *re, val->c_str()); + str->clear(); val->clear(); + delete str; delete re; delete val; + } + } + + int ret = this->execute_scalar(_query->c_str(), func); + //free(_query); + delete _query; + return ret; +} +template +int npgsql_query::execute_scalar(const char* query, _func func) { + if (_cpool->conn_state == connection_state::CLOSED) { + panic("Connection state not opend!!!"); + return -1; + } + bool exists = false; + PGresult* res = PQexec(_cpool->conn, query ); + ExecStatusType exs_type = PQresultStatus(res); + if (exs_type == PGRES_FATAL_ERROR) goto _ERROR; + if (exs_type == PGRES_NONFATAL_ERROR) goto _ERROR; + if (exs_type == PGRES_TUPLES_OK) { + exists = true; + int nFields = PQnfields(res); + size_t len = 0; + for (int i = 0; i < PQntuples(res); i++) { + std::vector* rows = new std::vector(); + for (int j = 0; j < nFields; j++) { + char* c = PQgetvalue(res, i, j); + len = strlen(c); + char* copy = new char[len + 1]; + //strcpy_s(copy, len, c); + strcpy(copy, c); + rows->push_back(copy); + //free(c); + } + func(i, *rows); + delete rows; + } + goto _END; + } + + if (exs_type == PGRES_COMMAND_OK) { + exists = true; goto _END; + } + panic("Invalid response defined!!!!"); + exists = false; + goto _END; +_ERROR: + panic( ); + goto _END; +_END: + /*Delete execution result*/ + PQclear(res); + return (exists == true) ? 0 : -1; +} +template +int npgsql_query::execute_scalar(const char* query, std::list& sql_param, _func func) { + if (_cpool->conn_state == connection_state::CLOSED) { + panic("Connection state not opend!!!"); + return -1; + } + std::string* param_stmt = new std::string(""); + int param_count = 0; + for (auto s = sql_param.begin(); s != sql_param.end(); ++s) { + npgsql_params* param = *s; + if (param->direction != parameter_direction::Input) { + throw new std::exception("You should pass input param"); + } + std::string* val = new std::string(param->value); + quote_literal(*val); + if (param_count == 0) { + param_count++; + param_stmt->append(" where "); + param_stmt->append(param->parameter_name); + param_stmt->append("="); + param_stmt->append(val->c_str()); + free(val); + param_stmt->append("::"); + param_stmt->append(get_db_type(param->db_type)); + continue; + } + param_count++; + param_stmt->append(", "); + param_stmt->append(param->parameter_name); + param_stmt->append("="); + param_stmt->append(val->c_str()); + free(val); + param_stmt->append("::"); + param_stmt->append(get_db_type(param->db_type)); + } + int ret = 0; + if (param_count <= 0) { + delete param_stmt; + ret = this->execute_scalar(query, func); + } + else { + std::string* stmt = new std::string(query); + stmt->append(param_stmt->c_str()); + ret = this->execute_scalar(stmt->c_str(), func); + delete stmt; delete param_stmt; + } + return ret; +} +#endif//!_npgsql_query_h \ No newline at end of file diff --git a/src/npgsql_result.h b/src/npgsql_result.h index b284b3c..0d900cb 100644 --- a/src/npgsql_result.h +++ b/src/npgsql_result.h @@ -4,13 +4,11 @@ * Copyrights licensed under the New BSD License. * See the accompanying LICENSE file for terms. */ +#if defined(_MSC_VER) #pragma once -#if !defined(_npgsql_global_h) -#include "npgsql_global.h" -#endif//!_global_h +#endif//!_MSC_VER #if !defined(_npgsql_result_h) -#define _npgsql_result_h -#pragma warning (disable : 4231) +# define _npgsql_result_h typedef struct { int ret_val; const char* ret_msg; diff --git a/src/npgsql_tools.cpp b/src/npgsql_tools.cpp index 111d9cd..d9bca4d 100644 --- a/src/npgsql_tools.cpp +++ b/src/npgsql_tools.cpp @@ -5,27 +5,21 @@ * See the accompanying LICENSE file for terms. */ //2:30 AM 11/22/2018 -#include "npgsql_tools.h" +# include "npgsql_tools.h" void json_array_stringify_s(std::vector& json_array_obj, std::string & json_str) { std::stringstream*ss = new std::stringstream(); std::stringstream& copy = *ss; copy << "["; - for (size_t i = 0; i < json_array_obj.size(); ++i) { + for (size_t i = 0, l = json_array_obj.size(); i < l; ++i) { if (i != 0) copy << ","; copy << "\"" << json_array_obj[i] << "\""; } copy << "]"; json_str = ss->str(); - free(ss); + delete ss; return; -}; -void json_parse(const char * json_str, std::list>& json_obj) { -#if defined(_WIN64) - // -#endif//!_WIN64 - std::regex pattern("([\\w+%]+):([^,]*)"); -}; +} void json_array_stringify(std::list>& json_obj, std::string& json_str) { json_str = "["; for (auto s = json_obj.begin(); s != json_obj.end(); ++s) { @@ -48,7 +42,7 @@ void json_array_stringify(std::list>& json_ob } json_str += "]"; return; -}; +} void json_array_stringify_char(std::list>& json_obj, std::string & json_str) { json_str = "["; for (auto s = json_obj.begin(); s != json_obj.end(); ++s) { @@ -71,7 +65,7 @@ void json_array_stringify_char(std::list>& json_obj } json_str += "]"; return; -}; +} void json_array_stringify_cchar(std::list>& json_obj, std::string & json_str) { json_str = "["; for (auto s = json_obj.begin(); s != json_obj.end(); ++s) { @@ -96,7 +90,7 @@ void json_array_stringify_cchar(std::list>& j } json_str += "]"; return; -}; +} void json_obj_stringify(std::map& json_obj, std::string & json_str) { json_str += "{"; bool is_first = true; @@ -114,7 +108,7 @@ void json_obj_stringify(std::map& json_obj, std::strin } json_str += "}"; return; -}; +} void json_obj_stringify_char(std::map& json_obj, std::string & json_str) { json_str += "{"; bool is_first = true; @@ -132,7 +126,7 @@ void json_obj_stringify_char(std::map& json_obj, std::string } json_str += "}"; return; -}; +} void json_obj_stringify_cchar(std::map& json_obj, std::string & json_str) { json_str += "{"; bool is_first = true; @@ -154,4 +148,4 @@ void json_obj_stringify_cchar(std::map& json_obj, std: json_str += "}"; //std::cout << json_str << ""; return; -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/npgsql_tools.h b/src/npgsql_tools.h index 4bf0f19..dedd0ef 100644 --- a/src/npgsql_tools.h +++ b/src/npgsql_tools.h @@ -5,16 +5,15 @@ * See the accompanying LICENSE file for terms. */ //2:30 AM 11/22/2018 +#if defined(_MSC_VER) #pragma once -#if !defined(_npgsql_global_h) -#include "npgsql_global.h" -#endif//!_global_h +#endif//!_MSC_VER #if !defined(_npgsql_tools_h) -#include -#define _npgsql_tools_h +# define _npgsql_tools_h +# include "npgsql_global.h" +# include #pragma warning (disable : 4231) NPGSQL_API void json_array_stringify_s(std::vector& json_array_obj, std::string& json_str); -NPGSQL_API void json_parse(const char* json_str, std::list>&json_obj); NPGSQL_API void json_array_stringify(std::list>& json_obj, std::string&json_str); NPGSQL_API void json_array_stringify_char(std::list>& json_obj, std::string&json_str); NPGSQL_API void json_array_stringify_cchar(std::list>& json_obj, std::string&json_str); diff --git a/src/os_support.cpp b/src/os_support.cpp index 134c058..824e4c6 100644 --- a/src/os_support.cpp +++ b/src/os_support.cpp @@ -4,52 +4,52 @@ * Copyrights licensed under the New BSD License. * See the accompanying LICENSE file for terms. */ -#include "os_support.h" -#if !(defined(_WIN32)||defined(_WIN64)) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) +# include "os_support.h" +#if !(defined(_WIN32)||defined(_WIN64)) HMODULE os_support::load_library(LPCWSTR * name) { return HMODULE(); -}; +} void* os_support::load_library(const char *name) { return dlopen(name, RTLD_NOW); -}; +} void os_support::get_module_file_name(void* module, char *out_path, int len) { -}; +} void* os_support::get_proc_address(void* module, const char *name) { return dlsym(module, name); -}; +} #else HMODULE os_support::load_library(LPCWSTR name) { //return ::LoadLibrary(name); return LoadLibraryEx(name, NULL, 0x00000008); -}; +} void* os_support::get_proc_address(HMODULE module, const char *name) { return ::GetProcAddress(module, name); -}; +} void os_support::get_module_file_name(HMODULE module, char *out_path, int len) { ::GetModuleFileName(module, (LPWSTR)out_path, (DWORD)len); -}; -#endif +} +#endif//!_WIN32||_WIN64 char* os_support::load_library_error() { -#if !(defined(_WIN32)||defined(_WIN64)) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) +#if !(defined(_WIN32)||defined(_WIN64)) return dlerror(); #else return NULL; -#endif -}; +#endif//!_WIN32||_WIN64 +} // Sleep the specified number of seconds void os_support::sleep (unsigned int sec) { -#if !(defined(_WIN32)||defined(_WIN64)) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) +#if !(defined(_WIN32)||defined(_WIN64)) sleep(sec); #else ::Sleep(sec * 1000); -#endif -}; +#endif//!_WIN32||_WIN64 +} // Get error message of the last system error void os_support::get_last_error_text(const char *prefix, char *output, int len) { if (output == NULL || len <= 0) return; - char error[1024]; -#if !(defined(_WIN32)||defined(_WIN64)) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) + char error[2048]; +#if !(defined(_WIN32)||defined(_WIN64)) return; #else DWORD rc = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), @@ -62,17 +62,19 @@ void os_support::get_last_error_text(const char *prefix, char *output, int len) // On Windows OS error messages terminated with 0D 0A 00, remove new lines if (rc > 2 && error[rc - 2] == '\r') error[rc - 2] = '\x0'; - - if (prefix != NULL) { - output = new char[strlen(prefix) + 1]; - strcpy_s(output, sizeof output, prefix); - } - else + // + if (strlen(prefix) != 0) { *output = '\x0'; + } + else { + size_t plen = strlen(prefix); + output = new char[plen]; + strcpy_s(output, plen * sizeof(char), prefix); + } strcat_s(output, sizeof output, error); -#endif -}; +#endif//!_WIN32||_WIN64 +} // Get current time in milliseconds size_t os_support::get_tick_count() { - return ::GetTickCount(); -}; \ No newline at end of file + return (size_t)::GetTickCount64(); +} \ No newline at end of file diff --git a/src/os_support.h b/src/os_support.h index 9cb41aa..2c26202 100644 --- a/src/os_support.h +++ b/src/os_support.h @@ -4,15 +4,16 @@ * Copyrights licensed under the New BSD License. * See the accompanying LICENSE file for terms. */ +#if defined(_MSC_VER) +#pragma once +#endif//!_MSC_VER #if !defined(_os_support_h) -#define _os_support_h -#ifndef _WINDOWS_ -#include -#endif//!_WINDOWS_ -#ifndef _IOSTREAM_ -#include -#endif//!_IOSTREAM_ -#include +# define _os_support_h +#if defined(WIN32) || defined(_WIN64) +# include +#endif//!WIN32 +# include +# include class os_support { public: #if defined(WIN32) || defined(_WIN64) diff --git a/src/parameter_direction.h b/src/parameter_direction.h index 7e5300c..375b88b 100644 --- a/src/parameter_direction.h +++ b/src/parameter_direction.h @@ -1,11 +1,9 @@ //5:27 PM 11/19/2018 +#if defined(_MSC_VER) #pragma once -#if !defined(_npgsql_global_h) -#include "npgsql_global.h" -#endif//!_global_h +#endif//!_MSC_VER #if !defined(_parameter_direction_h) -#define _parameter_direction_h -#pragma warning (disable : 4231) +# define _parameter_direction_h typedef enum { // // Summary: diff --git a/src/pg_sql.cpp b/src/pg_sql.cpp index 27720da..f4cf0c7 100644 --- a/src/pg_sql.cpp +++ b/src/pg_sql.cpp @@ -4,17 +4,30 @@ * Copyrights licensed under the New BSD License. * See the accompanying LICENSE file for terms. */ -#include "pg_sql.h" +# include "pg_sql.h" pg_sql::pg_sql() { _pq_error_text = new char; _n_error_text = new char; + _connected = false; + _conn = NULL; _n_error = 0; _pq_error = 0; + _is_disposed = 0; }; pg_sql::~pg_sql() { + if (_is_disposed != 0 )return; + //if (_conn == NULL)return; + _is_disposed = 1; if (_connected) { exit_nicely(); } //_pg_result = NULL; - _conn = NULL; + _conn = NULL; delete _pq_error_text; delete _n_error_text; -}; + _pq_error_text = NULL; _n_error_text = NULL; +} +void pg_sql::clear_response() { + PGresult* res; + while ((res = PQgetResult(_conn))) { + PQclear(res); + } +} int pg_sql::parse_connection_string(const char * conn, std::string & user, std::string & pwd, std::string & server, std::string & port, std::string & db) { if (((conn != NULL) && (conn[0] == '\0')) || conn == NULL) { panic("No connection string found!!!"); @@ -32,12 +45,12 @@ int pg_sql::parse_connection_string(const char * conn, std::string & user, std:: if (conn_obj.find(key) != conn_obj.end()) { key = "Duplicate key found in connection string ==> `" + key + "`!!!"; panic(key.c_str()); - free(query); + query->clear(); delete query; goto _ERROR; } conn_obj[key] = value; }; - free(query); + query->clear(); delete query; user = conn_obj["UserId"]; if (user.empty()) { panic("No user defined (e.g. postgress) in given connection string as `UserId`!!!"); @@ -65,9 +78,10 @@ int pg_sql::parse_connection_string(const char * conn, std::string & user, std:: } goto _END; _ERROR: + conn_obj.clear(); return _n_error; _END: - conn_obj.clear(); + //conn_obj.clear(); return 1; }; int pg_sql::connect(const char *conn) { @@ -107,7 +121,8 @@ int pg_sql::connect(const char *conn) { goto _END; _END: - free(user); free(pwd); free(server); free(port); free(db); + user->clear(); pwd->clear(); server->clear(); port->clear(); db->clear(); + delete user; delete pwd; delete server; delete port; delete db; return ret; //set_error(std::to_string(ret).c_str()); //return -1; @@ -115,8 +130,10 @@ int pg_sql::connect(const char *conn) { void pg_sql::exit_nicely() { if (!_connected)return; if (_conn != NULL) { + clear_response(); /*close the connection to the database and cleanup*/ - PQfinish (_conn); + PQfinish(_conn); _conn = NULL; + _connected = false; } return; } @@ -142,13 +159,13 @@ const char* pg_sql::execute_cmd(const char *command, int&ret) { } panic("pg_sql::execute_cmd not implemented yet!!!"); return '\0'; - /*PGresult *PQexecParams(PGconn *conn, - const char *command, - int nParams, - const Oid *paramTypes, - const char *const * paramValues, - const int *paramLengths, - const int *paramFormats, + /*PGresult *PQexecParams(PGconn *conn, + const char *command, + int nParams, + const Oid *paramTypes, + const char *const * paramValues, + const int *paramLengths, + const int *paramFormats, int resultFormat)*/ command = "INSERT INTO person(name) values($1) returning person_id"; int nParams = 0; @@ -156,19 +173,19 @@ const char* pg_sql::execute_cmd(const char *command, int&ret) { const char *values[1] = { name }; int lengths[1] = { (int)strlen(name) }; int binary[1] = { 1 }; - PGresult *res = PQexecParams( - /*PGconn *conn*/_conn,//Active connection - /*const char *command*/command,//SQL Statement - /*int nParams*/nParams,//number of parameters - /*const Oid *paramTypes*/NULL,//let the backend deduce param type - /*const char *const * paramValues*/values,//values to substitute $1 and $2 - /*const int *paramLengths*/lengths,//the lengths, in bytes, of each of the parameter values - /*const int *paramFormats*/binary,//whether the values are binary or not + PGresult *res = PQexecParams( + /*PGconn *conn*/_conn,//Active connection + /*const char *command*/command,//SQL Statement + /*int nParams*/nParams,//number of parameters + /*const Oid *paramTypes*/NULL,//let the backend deduce param type + /*const char *const * paramValues*/values,//values to substitute $1 and $2 + /*const int *paramLengths*/lengths,//the lengths, in bytes, of each of the parameter values + /*const int *paramFormats*/binary,//whether the values are binary or not /*int resultFormat*/0//we want the result in text format ); //std::vector chars; //const char* char_arr = chars.data(); - const char* result = '\0'; + const char* result = NULL; ExecStatusType exs_type = PQresultStatus(res); if (exs_type == PGRES_FATAL_ERROR) goto _ERROR; if (exs_type == PGRES_NONFATAL_ERROR) goto _ERROR; @@ -189,12 +206,12 @@ const char* pg_sql::execute_cmd(const char *command, int&ret) { const char* pg_sql::execute_query(const char *query, int&ret) { if (((query != NULL) && (query[0] == '\0')) || query == NULL) { panic("SQL Statement required!!!"); - return '\0'; + return NULL; } //https://timmurphy.org/2009/11/19/pqexecparams-example-postgresql-query-execution-with-parameters/ // Execute the statement PGresult *res = PQexec(_conn, query); - const char* result = '\0'; + const char* result = NULL; ExecStatusType exs_type = PQresultStatus(res); if (exs_type == PGRES_FATAL_ERROR) goto _ERROR; if (exs_type == PGRES_NONFATAL_ERROR) goto _ERROR; @@ -241,7 +258,7 @@ int pg_sql::execute_scalar_x(const char *query, std::list< std::string>&out_para char* copy_resp = new char[len + 1]; //strcpy_s(copy_resp, len, resp); strcpy(copy_resp, resp); - out_param_map[prop] = copy_resp; + out_param_map[prop.c_str()] = copy_resp; field_map++; //free(resp); } diff --git a/src/pg_sql.h b/src/pg_sql.h index c3f2354..7314759 100644 --- a/src/pg_sql.h +++ b/src/pg_sql.h @@ -5,48 +5,41 @@ * See the accompanying LICENSE file for terms. */ //2:16 AM 11/19/2018 -//#pragma warning(suppress : 4996) +#if defined(_MSC_VER) #pragma once +#endif//!_MSC_VER #if !defined(_pg_sql_h) #pragma warning(disable : 4996) -#define _pg_sql_h -#if !defined(_npgsql_global_h) -#include "npgsql_global.h" -#endif//!_global_h -#if !defined(_os_support_h) -#include "os_support.h" -#endif -#if !defined(LIBPQ_FE_H) -#include -#endif//!LIBPQ_FE_H -#if !defined(POSTGRES_EXT_H) -#include -#endif//!POSTGRES_EXT_H +# define _pg_sql_h +# include "npgsql_global.h" +# include "os_support.h" +# include +# include //libpq.lib //libeay32.dll, libiconv-2.dll, libintl-8.dll, libpq.dll, ssleay32.dll, zlib1.dll class pg_sql { private: bool _connected; PGconn* _conn; - //PGresult* _pg_result; - int _cursor_rows_fetched; - size_t _copy_cols_count; int _n_error; char* _n_error_text; int _pq_error; char* _pq_error_text; + int _is_disposed; public: - pg_sql(); + explicit pg_sql(); + pg_sql(const pg_sql&) = delete; + pg_sql& operator=(const pg_sql&) = delete; ~pg_sql(); - virtual const int is_api_error(); - virtual const char * get_last_error(); + const int is_api_error(); + const char * get_last_error(); // Connect to the database - virtual int connect(const char *conn); + int connect(const char *conn); // Close database connection - virtual void exit_nicely(); - virtual int get_row_count(const char *object, char *value); - virtual const char* execute_cmd(const char *command, int&ret); - virtual const char* execute_query(const char *query, int&ret); + void exit_nicely(); + int get_row_count(const char *object, char *value); + const char* execute_cmd(const char *command, int&ret); + const char* execute_query(const char *query, int&ret); template int execute_scalar(const char *query, _func fn) { if (((query != NULL) && (query[0] == '\0')) || query == NULL) { @@ -74,7 +67,7 @@ class pg_sql { //free(c); } fn(i, *rows); - free(rows); + delete rows; } goto _END; } @@ -93,10 +86,11 @@ class pg_sql { PQclear(res); return (exists == true) ? 0 : -1; }; - virtual int execute_scalar_x(const char *query, std::list&out_param_array, std::map&out_param_map); - virtual int execute_non_query(const char *query); + int execute_scalar_x(const char *query, std::list&out_param_array, std::map&out_param_map); + int execute_non_query(const char *query); private: - virtual int parse_connection_string(const char *conn, std::string& user, std::string& pwd, std::string& server, std::string& port, std::string& db); + int parse_connection_string(const char *conn, std::string& user, std::string& pwd, std::string& server, std::string& port, std::string& db); + void clear_response(); virtual void panic(const char* std_error_msg); virtual void panic(); }; diff --git a/src/pgsql_lib.cpp b/src/pgsql_lib.cpp index 7d5962d..e2a1121 100644 --- a/src/pgsql_lib.cpp +++ b/src/pgsql_lib.cpp @@ -4,7 +4,7 @@ * Copyrights licensed under the New BSD License. * See the accompanying LICENSE file for terms. */ -#include "pgsql_lib.h" +# include "pgsql_lib.h" LPWSTR s2ws(const char* s) { /*wchar_t wtext[FILENAME_MAX]; mbstowcs(wtext, s, strlen(s) + 1);//Plus null @@ -15,8 +15,9 @@ LPWSTR s2ws(const char* s) { LPWSTR& ptr = buf; //delete[] buf; return ptr; -}; +} pg_sql_lib::pg_sql_lib() { + _connected = false; _pg_result = NULL; _conn = NULL; _pgsql_proc_iddl = NULL; _pgsql_module = NULL; _PQclear = NULL; _PQerrorMessage = NULL; _PQexec = NULL; _PQfmod = NULL; _PQfname = NULL; _PQfsize = NULL; _PQftype = NULL; _PQgetisnull = NULL; @@ -26,9 +27,14 @@ pg_sql_lib::pg_sql_lib() { _PQconnectdb = NULL; _PQfinish = NULL; _pq_error_text = new char; _n_error_text = new char; + _n_error = 0; _pq_error = 0; + _copy_cols_count = 0; _cursor_rows_fetched = 0; }; pg_sql_lib::~pg_sql_lib() { if (_connected) { exit_nicely(); } + if (_pgsql_module != NULL) { + FreeLibrary(_pgsql_module); + } _pg_result = NULL; _conn = NULL; _pgsql_proc_iddl = NULL; _pgsql_module = NULL; _PQclear = NULL; _PQerrorMessage = NULL; _PQexec = NULL; _PQfmod = NULL; _PQfname = NULL; _PQfsize = NULL; _PQftype = NULL; _PQgetisnull = NULL; @@ -106,7 +112,7 @@ void pg_sql_lib::parse_connection_string(const char * conn, std::string & user, std::string value = (*i)[2].str(); conn_obj[key] = value; }; - free(query); + delete query; user = conn_obj["UserId"]; pwd = conn_obj["Password"]; db = conn_obj["Database"]; @@ -136,7 +142,8 @@ int pg_sql_lib::connect(const char *conn) { (db->empty() ? NULL : db->c_str()), (user->empty() ? NULL : user->c_str()), (pwd->empty() ? NULL : pwd->c_str())); - free(user); free(pwd); free(server); free(port); free(db); + user->clear(); pwd->clear(); server->clear(); port->clear(); db->clear(); + delete user; delete pwd; delete server; delete port; delete db; if (_PQstatus(_conn) != CONNECTION_OK) { set_error(); return -1; @@ -171,8 +178,10 @@ int pg_sql_lib::execute_scalar(const char *query, char *value) { value = _PQgetvalue(res, 0, 0); exists = true; } - else + else { + value = NULL; set_error(); + } _PQclear(res); return (exists == true) ? 0 : -1; }; diff --git a/src/pgsql_lib.h b/src/pgsql_lib.h index 40bfe93..74bcf9f 100644 --- a/src/pgsql_lib.h +++ b/src/pgsql_lib.h @@ -6,28 +6,23 @@ */ //2:16 AM 11/19/2018 //#pragma warning(suppress : 4996) +#if defined(_MSC_VER) #pragma once +#endif//!_MSC_VER #if !defined(_pgsql_lib_h) #pragma warning(disable : 4996) -#define _pgsql_lib_h -#if !defined(_npgsql_global_h) -#include "npgsql_global.h" -#endif//!_global_h -#if !defined(_os_support_h) -#include "os_support.h" -#endif -#if !defined(LIBPQ_FE_H) -#include -#endif//!LIBPQ_FE_H -#if !defined(POSTGRES_EXT_H) -#include -#endif//!POSTGRES_EXT_H +# define _pgsql_lib_h +# include "npgsql_global.h" +# include "os_support.h" +# include +# include #if !(defined(_WIN32)||defined(_WIN64)) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) -#define LIBPQ_C_DLL "libpq.so.5" +# define LIBPQ_C_DLL "libpq.so.5" #else -#define LIBPQ_C_DLL "libpq.dll" -#endif -#define LIBPQ_DLL_LOAD_ERROR "Error loading PostgreSQL " LIBPQ_C_DLL ": " +# define LIBPQ_C_DLL "libpq.dll" +#endif//!_WIN32 + +# define LIBPQ_DLL_LOAD_ERROR "Error loading PostgreSQL " LIBPQ_C_DLL ": " // libpq C library functions typedef void (*PQclearPQFunc)(PGresult *res); typedef char* (*PQerrorMessagePQFunc)(const PGconn *conn);