Skip to content

Commit

Permalink
Support PostgreSQL (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
huanghantao committed Mar 6, 2023
1 parent 954d350 commit 40cfc42
Show file tree
Hide file tree
Showing 10 changed files with 416 additions and 1 deletion.
11 changes: 11 additions & 0 deletions .github/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: '3'

services:
postgres:
container_name: postgres
image: postgres:latest
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- "5432:5432"
11 changes: 10 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -198,27 +198,36 @@ jobs:
if [ "${{runner.os}}" = "Linux" ]
then
sudo apt-get update
sudo apt-get install -yyq libgtest-dev libcurl4-openssl-dev
sudo apt-get install -yyq libgtest-dev libcurl4-openssl-dev libpq-dev postgresql-server-dev-all
else
brew install googletest ||
brew install googletest ||
brew install googletest
brew install pkg-config
brew install openssl@1.1
brew install curl
brew install libpq
fi
- name: Checkout libcat sources
uses: actions/checkout@v2
with:
path: libcat

- name: Start service containers
shell: bash
if: runner.os == 'Linux'
working-directory: libcat
run: |
docker compose -f ${{github.workspace}}/libcat/.github/docker-compose.yml up -d
- name: Build libcat and Run tests
shell: bash
working-directory: libcat
run: |
${{ runner.os == 'macOS' && 'export PKG_CONFIG_PATH="/usr/local/opt/openssl@1.1/lib/pkgconfig:$PKG_CONFIG_PATH"' || '' }}
${{ runner.os == 'macOS' && 'export PKG_CONFIG_PATH="/usr/local/opt/curl/lib/pkgconfig:$PKG_CONFIG_PATH"' || '' }}
${{ runner.os == 'Linux' && 'export TEST_CAT_POSTGRESQL="true"' || '' }}
echo "::group::Create build dir"
mkdir -p build && cd build || exit 1
echo "::endgroup::"
Expand Down
31 changes: 31 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,34 @@ else()
message(STATUS "cURL is not enabled")
endif()

# pq dep
find_package(PostgreSQL QUIET)
if(NOT PostgreSQL_FOUND AND PkgConfig_FOUND)
pkg_check_modules(PostgreSQL libpq QUIET)
if(PostgreSQL_FOUND)
set(PostgreSQL_LIBRARIES ${PostgreSQL_LINK_LIBRARIES})
endif()
endif()

cmake_dependent_option(LIBCAT_ENABLE_POSTGRESQL
"Enable PostgreSQL if found"
ON PostgreSQL_FOUND
OFF)
if (LIBCAT_ENABLE_POSTGRESQL)
if (NOT PostgreSQL_FOUND)
message(FATAL_ERROR "Require PostgreSQL but not found")
endif()
message(STATUS "Enable PostgreSQL")
list(APPEND cat_defines CAT_HAVE_PQ=1)

list(APPEND cat_includes ${PostgreSQL_INCLUDE_DIRS})
list(APPEND cat_libraries ${PostgreSQL_LIBRARIES})
list(APPEND cat_sources src/cat_pq.c)
else()
find_package(PostgreSQL REQUIRED) # throw warning
message(STATUS "PostgreSQL is not enabled")
endif()

set(cat_target_objects "")
if (LIBCAT_USE_BOOST_CONTEXT)
list(APPEND cat_target_objects $<TARGET_OBJECTS:cat_context>)
Expand Down Expand Up @@ -912,6 +940,9 @@ if (LIBCAT_BUILD_TESTS)
if (LIBCAT_ENABLE_CURL)
list(APPEND cat_test_sources tests/test_cat_curl.cc)
endif()
if (LIBCAT_ENABLE_POSTGRESQL)
list(APPEND cat_test_sources tests/test_cat_pq.cc)
endif()
add_executable(cat_tests ${cat_test_sources})
if(MSVC)
set_property(TARGET cat_tests PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
Expand Down
9 changes: 9 additions & 0 deletions include/cat_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,12 @@ static cat_always_inline cat_bool_t cat_os_is_windows(void)
return cat_true;
#endif
}

static cat_always_inline cat_bool_t cat_os_is_linux(void)
{
#ifndef CAT_OS_LINUX
return cat_false;
#else
return cat_true;
#endif
}
50 changes: 50 additions & 0 deletions include/cat_pq.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
+--------------------------------------------------------------------------+
| libcat |
+--------------------------------------------------------------------------+
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| http://www.apache.org/licenses/LICENSE-2.0 |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. See accompanying LICENSE file. |
+--------------------------------------------------------------------------+
| Author: Codinghuang <codinghuang@qq.com> |
+--------------------------------------------------------------------------+
*/

#ifndef CAT_PQ_H
#define CAT_PQ_H
#ifdef __cplusplus
extern "C" {
#endif

#include "cat.h"

#ifdef CAT_HAVE_PQ
#define CAT_PQ 1

#include <libpq-fe.h>
#include <libpq/libpq-fs.h>
// #include <libpq-int.h>

CAT_API cat_bool_t cat_pq_runtime_init(void);
CAT_API cat_bool_t cat_pq_runtime_close(void);

CAT_API PGconn *cat_pq_connectdb(const char *conninfo);
CAT_API PGresult *cat_pq_prepare(PGconn *conn, const char *stmt_name, const char *query, int n_params, const Oid *param_types);
CAT_API PGresult *cat_pq_exec_prepared(PGconn *conn, const char *stmt_name, int n_params,
const char *const *param_values, const int *param_lengths, const int *param_formats, int result_format);
CAT_API PGresult *cat_pq_exec(PGconn *conn, const char *query);
CAT_API PGresult *cat_pq_exec_params(PGconn *conn, const char *command, int n_params,
const Oid *param_types, const char *const *param_values, const int *param_lengths, const int *param_formats, int result_format);

#endif /* CAT_HAVE_PQ */

#ifdef __cplusplus
}
#endif
#endif /* CAT_PQ_H */
1 change: 1 addition & 0 deletions run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ set -e
-DLIBCAT_USE_THREAD_KEY="${LIBCAT_USE_THREAD_KEY-OFF}" \
-DLIBCAT_ENABLE_OPENSSL="${LIBCAT_ENABLE_OPENSSL-ON}" \
-DLIBCAT_ENABLE_CURL="${LIBCAT_ENABLE_CURL-ON}" \
-DLIBCAT_ENABLE_PQ="${LIBCAT_ENABLE_PQ-ON}" \
..

# build tests
Expand Down
179 changes: 179 additions & 0 deletions src/cat_pq.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/*
+--------------------------------------------------------------------------+
| libcat |
+--------------------------------------------------------------------------+
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| http://www.apache.org/licenses/LICENSE-2.0 |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. See accompanying LICENSE file. |
+--------------------------------------------------------------------------+
| Author: Codinghuang <codinghuang@qq.com> |
+--------------------------------------------------------------------------+
*/

#include "cat_pq.h"

#ifdef CAT_PQ

#include "cat_poll.h"

CAT_API cat_bool_t cat_pq_runtime_init(void)
{
return cat_true;
}

CAT_API cat_bool_t cat_pq_runtime_close(void)
{
return cat_true;
}

static int cat_pq_flush(PGconn *conn)
{
int flush_ret = -1;

do {
cat_ret_t poll_ret = cat_poll_one(PQsocket(conn), POLLOUT, NULL, -1);
if (unlikely(poll_ret == CAT_RET_ERROR)) {
return -1;
}
CAT_LOG_DEBUG(PQ, "PQflush(conn=%p)", conn);
flush_ret = PQflush(conn);
} while (flush_ret == 1);

return flush_ret;
}

static PGresult *cat_pq_get_result(PGconn *conn)
{
PGresult *result, *last_result = NULL;
cat_ret_t poll_ret = cat_poll_one(PQsocket(conn), POLLIN, NULL, -1);
if (unlikely(poll_ret == CAT_RET_ERROR)) {
return NULL;
}

CAT_LOG_DEBUG(PQ, "PQgetResult(conn=%p)", conn);
while ((result = PQgetResult(conn))) {
PQclear(last_result);
last_result = result;
}

return last_result;
}

static cat_bool_t cat_pq_poll_connection(PGconn *conn)
{
int r;

while ((r = PQconnectPoll(conn)) && r != PGRES_POLLING_OK) {
cat_pollfd_events_t events = POLLNONE;

switch(r) {
case PGRES_POLLING_READING:
events |= POLLIN;
break;
case PGRES_POLLING_WRITING:
events |= POLLOUT;
break;
case PGRES_POLLING_FAILED:
return cat_false;
default:
return cat_false;
}

cat_ret_t ret = cat_poll_one(PQsocket(conn), events, NULL, -1);
if (unlikely(ret == CAT_RET_ERROR)) {
return cat_false;
}
}

return cat_false;
}

CAT_API PGconn *cat_pq_connectdb(const char *conninfo)
{
int fd;
PGconn *conn = PQconnectStart(conninfo);
if(conn == NULL) {
return NULL;
}

fd = PQsocket(conn);
if (unlikely(fd < 0)) {
return conn;
}

PQsetnonblocking(conn, 1);

cat_pq_poll_connection(conn);

return conn;
}

CAT_API PGresult *cat_pq_prepare(PGconn *conn, const char *stmt_name, const char *query, int n_params, const Oid *param_types)
{
CAT_LOG_DEBUG(PQ, "PQsendPrepare(conn=%p, stmt_name='%s')", conn, stmt_name);
int ret = PQsendPrepare(conn, stmt_name, query, n_params, param_types);
if (ret == 0) {
return NULL;
}

if (cat_pq_flush(conn) == -1) {
return NULL;
}

return cat_pq_get_result(conn);
}

CAT_API PGresult *cat_pq_exec_prepared(PGconn *conn, const char *stmt_name, int n_params,
const char *const *param_values, const int *param_lengths, const int *param_formats, int result_format)
{
CAT_LOG_DEBUG(PQ, "PQsendQueryPrepared(conn=%p, stmt_name='%s')", conn, stmt_name);
int ret = PQsendQueryPrepared(conn, stmt_name, n_params, param_values, param_lengths, param_formats, result_format);
if (ret == 0) {
return NULL;
}

if (cat_pq_flush(conn) == -1) {
return NULL;
}

return cat_pq_get_result(conn);
}

CAT_API PGresult *cat_pq_exec(PGconn *conn, const char *query)
{
CAT_LOG_DEBUG(PQ, "PQsendQuery(conn=%p, query='%s')", conn, query);
int ret = PQsendQuery(conn, query);
if (ret == 0) {
return NULL;
}

if (cat_pq_flush(conn) == -1) {
return NULL;
}

return cat_pq_get_result(conn);
}

CAT_API PGresult *cat_pq_exec_params(PGconn *conn, const char *command, int n_params,
const Oid *param_types, const char *const *param_values, const int *param_lengths, const int *param_formats, int result_format)
{
CAT_LOG_DEBUG(PQ, "PQsendQueryParams(conn=%p, command='%s')", conn, command);
int ret = PQsendQueryParams(conn, command, n_params, param_types, param_values, param_lengths, param_formats, result_format);
if (ret == 0) {
return NULL;
}

if (cat_pq_flush(conn) == -1) {
return NULL;
}

return cat_pq_get_result(conn);
}

#endif /* CAT_PQ */
6 changes: 6 additions & 0 deletions tests/test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ class BootstrapEnvironment : public testing::Environment
ASSERT_TRUE(cat_runtime_init_all());
#ifdef CAT_CURL
ASSERT_TRUE(cat_curl_runtime_init());
#endif
#ifdef CAT_PQ
ASSERT_TRUE(cat_pq_runtime_init());
#endif
cat_set_error_log(stderr);

Expand Down Expand Up @@ -363,6 +366,9 @@ class BootstrapEnvironment : public testing::Environment
ASSERT_EQ(cat_coroutine_get_count() , 1);

ASSERT_TRUE(cat_runtime_shutdown_all());
#ifdef CAT_PQ
ASSERT_TRUE(cat_pq_runtime_close());
#endif
#ifdef CAT_CURL
ASSERT_TRUE(cat_curl_runtime_close());
#endif
Expand Down
5 changes: 5 additions & 0 deletions tests/test.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
/* ext, not enabled by default */
#include "cat_curl.h"

/* ext, not enabled by default */
#include "cat_pq.h"

/* GTEST_SKIP and GTEST_SKIP_ shim */
#ifndef GTEST_SKIP
# define GTEST_SKIP() {/* do nothing */}
Expand Down Expand Up @@ -81,6 +84,8 @@
#endif
#define TEST_SERVER_BACKLOG 8192

#define TEST_PQ_CONNINFO "host=127.0.0.1 dbname=postgres user='postgres' password='postgres' connect_timeout=30"

#define TEST_REMOTE_HTTP_SERVER ::testing::CONFIG_REMOTE_HTTP_SERVER_HOST.c_str(), ::testing::CONFIG_REMOTE_HTTP_SERVER_HOST.length(), ::testing::CONFIG_REMOTE_HTTP_SERVER_PORT
#define TEST_REMOTE_HTTP_SERVER_HOST ::testing::CONFIG_REMOTE_HTTP_SERVER_HOST.c_str()
#define TEST_REMOTE_HTTP_SERVER_PORT ::testing::CONFIG_REMOTE_HTTP_SERVER_PORT
Expand Down

0 comments on commit 40cfc42

Please sign in to comment.