#include "ts3db.h"
#include <libpq-fe.h>
#include <stdbool.h>
#include <string.h>
#define MAX_CONNECTIONS 99
typedef struct {
PGconn *conn;
PGresult *result;
} pg_connection;
static log_callback log = 0;
static pg_connection connections[MAX_CONNECTIONS];
static unsigned int connection_count = 0;
static const char *keywords[] = { "host", "hostaddr", "port", "dbname",
"user", "password", "sslmode", "sslcert",
"sslkey", "sslrootcert", "sslcrl",
"application_name", 0};
typedef struct {
char *host;
char *hostaddr;
char *port;
char *dbname;
char *user;
char *password;
char *sslmode;
char *sslcert;
char *sslkey;
char *sslrootcert;
char *sslcrl;
char *application_name;
} pg_settings;
static pg_settings settings;
char *ts3dbplugin_version()
{
return "0.1";
}
char *ts3dbplugin_name()
{
return "PostgreSQL plugin";
}
int ts3dbplugin_disconnect()
{
log("disconnect", LOG_DEVELOP);
ts3dbplugin_shutdown();
return 0;
}
void ts3dbplugin_shutdown()
{
log("shutdown", LOG_DEVELOP);
unsigned int i;
for (i = 0; i < connection_count; i++) {
PQclear(connections[i].result);
PQfinish(connections[i].conn);
}
connection_count = 0;
}
int ts3dbplugin_init(log_callback logging, char *parameter)
{
log = logging;
settings.host = "localhost";
settings.hostaddr = "";
settings.port = "";
settings.dbname = "ts3";
settings.user = "ts3";
settings.password = "";
settings.sslmode = NULL;
settings.sslcert = NULL;
settings.sslkey = NULL;
settings.sslrootcert = NULL;
settings.sslcrl = NULL;
settings.application_name = "teamspeak3";
return 0;
}
int ts3dbplugin_connect(unsigned int *connection_nr)
{
PGconn *conn;
if (connection_count >= MAX_CONNECTIONS) {
return 0;
}
conn = PQconnectdbParams(keywords, (const char **)&settings, true);
if (PQstatus(conn) != CONNECTION_OK) {
log(PQerrorMessage(conn), LOG_CRITICAL);
return 1280;
}
*connection_nr = connection_count;
connections[connection_count].conn = conn;
connections[connection_count].result = NULL;
connection_count++;
return 0;
}
PGconn *get_connection(unsigned int connection_nr)
{
if (connection_nr >= connection_count) {
log("Connection not found.", LOG_ERROR);
return NULL;
}
return connections[connection_nr].conn;
}
PGresult *get_last_result(unsigned int connection_nr)
{
if (connection_nr >= connection_count) {
log("Connection not found.", LOG_ERROR);
return NULL;
}
return connections[connection_nr].result;
}
void save_last_result(unsigned int connection_nr, PGresult *result)
{
if (connection_nr >= connection_count) {
log("Connection not found.", LOG_ERROR);
return;
}
if (connections[connection_nr].result != NULL) {
PQclear(connections[connection_nr].result);
}
connections[connection_nr].result = result;
}
char *ts3dbplugin_getlasterror(unsigned int connection_nr)
{
log("getlasterror", LOG_DEVELOP);
const PGconn *conn = get_connection(connection_nr);
return PQerrorMessage(conn);
}
unsigned int ts3dbplugin_tableexists(unsigned int connection_nr, const char* table_name)
{
log("tableexists", LOG_DEVELOP);
log(table_name, LOG_DEVELOP);
PGconn *conn = get_connection(connection_nr);
const char* const params[] = { table_name };
PGresult *result;
int tables;
result = PQexecParams(conn, "select 1 from pg_tables where \
schemaname='public' and \
tablename = $1 limit 1;",
1, NULL, params, NULL, NULL, 0);
tables = PQntuples(result);
PQclear(result);
if (tables == 0) {
/* table not exists */
return 0;
}
return 1;
}
unsigned long long ts3dbplugin_getmodifiedrowcount(unsigned int connection_nr)
{
log("getmodifiedrowcount", LOG_DEVELOP);
PGresult *result = get_last_result(connection_nr);
const char *count = PQcmdTuples(result);
unsigned long long number;
sscanf(count, "%llu", &number);
return number;
}
unsigned long long ts3dbplugin_getlastinsertid(unsigned int connection_nr)
{
log("getlastinsertid", LOG_DEVELOP);
const PGresult *result = get_last_result(connection_nr);
if (PQnfields(result) == 1) {
if (strcmp(PQfname(result, 0), "last_inserted_id") == 0) {
const char *count = PQgetvalue(result, 0, 0);
unsigned long long number;
sscanf(count, "%llu", &number);
return number;
}
}
return 0;
}
unsigned int ts3dbplugin_open(unsigned int connection_nr, const char* query,
field_callback new_field, value_callback new_value,
row_callback new_row, void *context)
{
log(query, LOG_DEBUG);
ExecStatusType status;
int col_count, row_count, i, j;
PGconn *conn = get_connection(connection_nr);
PGresult *result = PQexec(conn, query);
save_last_result(connection_nr, result);
status = PQresultStatus(result);
if (status == PGRES_BAD_RESPONSE || status == PGRES_FATAL_ERROR) {
log(PQresultErrorMessage(result), LOG_ERROR);
return 1280;
}
if (status == PGRES_NONFATAL_ERROR) {
log(PQresultErrorMessage(result), LOG_WARNING);
}
col_count = PQnfields(result);
for (i = 0; i < col_count; i++) {
log(PQfname(result, i), LOG_DEBUG);
new_field(i, PQfname(result, i), context);
}
row_count = PQntuples(result);
for (i = 0; i < row_count; i++) {
log("new row", LOG_DEBUG);
new_row(context);
log("new row done.", LOG_DEBUG);
for (j = 0; j < col_count; j++) {
log(PQgetvalue(result, i, j), LOG_DEBUG);
new_value(j, PQgetvalue(result, i, j), context);
}
}
return 0;
}
unsigned int ts3dbplugin_exec(unsigned int connection_nr, const char* query)
{
log(query, LOG_DEVELOP);
ExecStatusType status;
PGconn *conn = get_connection(connection_nr);
PGresult *result = PQexec(conn, query);
save_last_result(connection_nr, result);
status = PQresultStatus(result);
if (status == PGRES_BAD_RESPONSE || status == PGRES_FATAL_ERROR) {
log(PQresultErrorMessage(result), LOG_ERROR);
return 1280;
}
if (status == PGRES_NONFATAL_ERROR) {
log(PQresultErrorMessage(result), LOG_WARNING);
}
return 0;
}