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