2021-12-02 简易封装一个postgresql C++接口

本文档展示了如何使用C++封装PostgreSQL的libpq库,并提供了连接数据库、设置查询路径、开始事务、声明游标、执行查询、关闭游标和提交事务等功能。同时,代码中应用了地址 sanitizer 和 trapv 编译选项以增强安全性,并使用了{fmt}

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近学习了一下SQL, 配置了一个postgres数据库, pg本身是有C和C++接口的, 为了熟悉这个库, 又封装了一下, 将libpg封在struct里方便调用, 同时利用析构来断开资源.

调试编译参数:

set_languages("c++17")

add_cxxflags("-fsanitize=address","-ftrapv")

add_ldflags("-lpq")

add_ldflags("-lfmt")

add_ldflags("-fsanitize=address")

编译环境: linux: Debian + gcc + Xmake.

依赖: {fmt} 库, libpg库, C++版本>=17.

默认查询域:public

//PostGres.h

#ifndef POSTGRESH
#define POSTGRESH

#include <postgresql/libpq-fe.h>
#include <fmt/core.h>
#include <string>
#include <string_view>

struct pgDb
{
    pgDb(const char *conninfos = "dbname = postgres") : conninfo(conninfos)
    {
        conn = PQconnectdb(conninfo);
        if (PQstatus(conn) != CONNECTION_OK)
        {
            fmt::print("Connection to database failed: {}\n",
                       PQerrorMessage(conn));
        }
        else
        {
            res = PQexec(conn,
                         "SELECT pg_catalog.set_config('search_path','',false)");
            if (PQresultStatus(res) != PGRES_TUPLES_OK)
            {
                fmt::print("SET faild: {}\n", PQerrorMessage(conn));
            }

            PQclear(res);

            res = PQexec(conn, "set search_path=public");

            fmt::print("{}\n", PQresStatus(PQresultStatus(res)));

            PQclear(res);
        }
    }

    pgDb(const pgDb &) = delete;

    pgDb(pgDb &&) = delete;

    ~pgDb()
    {
        PQfinish(conn);
    }

    void reset(const char *conninfos = "dbname = postgres")
    {
        PQfinish(conn);
        conninfo = conninfos;
        conn = PQconnectdb(conninfo);
        if (PQstatus(conn) != CONNECTION_OK)
        {
            fmt::print("Connection to database failed: {}\n",
                       PQerrorMessage(conn));
        }
        else
        {
            res = PQexec(conn,
                         "SELECT pg_catalog.set_config('search_path','',false)");
            if (PQresultStatus(res) != PGRES_TUPLES_OK)
            {
                fmt::print("SET faild: {}\n", PQerrorMessage(conn));
            }
            PQclear(res);
        }
            res = PQexec(conn, "set search_path=public");

            fmt::print("{}\n", PQresStatus(PQresultStatus(res)));

            PQclear(res);
    }

    void begin()
    {
        res = PQexec(conn, "BEGIN");
        if (PQresultStatus(res) != PGRES_COMMAND_OK)
        {
            fmt::print("BEGIN command failed: {}\n", PQerrorMessage(conn));
        }
        PQclear(res);
    }

    void declareCursor()
    {
        res = PQexec(conn, "DECLARE myportal CURSOR FOR select * from pg_database");
        if (PQresultStatus(res) != PGRES_COMMAND_OK)
        {
            fmt::print("DECLARE CURSOR failed: {}\n", PQerrorMessage(conn));
        }
        PQclear(res);
    }

    void closeCursor()
    {
        res = PQexec(conn, "CLOSE myportal");
        PQclear(res);
    }

    void fetchAll()
    {
        res = PQexec(conn, "FETCH ALL in myportal");
        if (PQresultStatus(res) != PGRES_TUPLES_OK)
        {
            fmt::print("DECLARE CURSOR failed: {}\n", PQerrorMessage(conn));
            PQclear(res);
        }
        int nFields = PQnfields(res);
        for (int i = 0; i != nFields; ++i)
        {
            fmt::print("{:<15}", PQfname(res, i));
        }
        fmt::print("\n\n");
        for (int i = 0; i != PQntuples(res); ++i)
        {
            for (int j = 0; j != nFields; ++j)
            {
                fmt::print("{:<15}", PQgetvalue(res, i, j));
            }
            fmt::print("\n");
        }
        PQclear(res);
    }

    void exec(const std::string &sql)
    {
        res = PQexec(conn, sql.c_str());

        if (PQresultStatus(res) == PGRES_TUPLES_OK)
        {
            int nFields = PQnfields(res);

            for (int i = 0; i != nFields; ++i)
            {
                fmt::print("{:<15}", PQfname(res, i));
            }

            fmt::print("\n\n");

            for (int i = 0; i != PQntuples(res); ++i)
            {
                for (int j = 0; j != nFields; ++j)
                {
                    fmt::print("{:<15}", PQgetvalue(res, i, j));
                }
                fmt::print("\n");
            }

            PQclear(res);

            return;
        }
        else if (PQresultStatus(res) == PGRES_COMMAND_OK)
        {
            fmt::print("PGRES_COMMAND_OK\n");

            PQclear(res);

            return;
        }
        else
        {
            fmt::print("{}\n", PQresStatus(PQresultStatus(res)));
            fmt::print("EXECOMMAND failed: {}\n", PQerrorMessage(conn));
            PQclear(res);
            return;
        }
    }

    void end()
    {
        res = PQexec(conn, "COMMIT");
        if (PQresultStatus(res) != PGRES_COMMAND_OK)
        {
            fmt::print("COMMIT command failed: {}\n", PQerrorMessage(conn));
        }        
        PQclear(res);
    }

    std::string_view getDbName()
    {
        return PQdb(conn);
    };

    std::string_view getUser()
    {
        return PQuser(conn);
    };

    std::string_view getPass()
    {
        return PQpass(conn);
    };

    std::string_view getHost()
    {
        return PQhost(conn);
    };

    std::string_view getHostAddr()
    {
        return PQhostaddr(conn);
    };

    std::string_view getPort()
    {
        return PQport(conn);
    };

    std::string_view getOptions()
    {
        return PQoptions(conn);
    };

private:
    const char *conninfo = nullptr;
    PGconn *conn = nullptr;
    PGresult *res = nullptr;
};

#endif

测试:

#include "PostGres.h"
#include <iostream>

int main(int argc, char *argv[])
{
    {
        std::string cmd;

        pgData pgd("host=127.0.0.1 dbname=postgres user=postgres password=test");

        fmt::print("{} {} {} \n", pgd.getHost(), pgd.getDbName(), pgd.getUser());

        while (std::getline(std::cin, cmd))
        {
            pgd.exec(cmd);
        }

        pgd.begin();
        pgd.declareCursor();
        pgd.fetchAll();
        pgd.closeCursor();
        pgd.end();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不停感叹的老林_<C 语言编程核心突破>

不打赏的人, 看完也学不会.

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值