最近学习了一下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;
}