#include "ts3db.h" #include #include #include #include #define MAX_CONNECTIONS 99 typedef struct { PGconn *conn; unsigned long long modified_rows; unsigned long long last_inserted_id; } pg_connection; static log_callback log = 0; static pg_connection connections[MAX_CONNECTIONS]; static unsigned int connection_count = 0; static dictionary *config = NULL; static const char *config_keywords[13] = { "host", "hostaddr", "port", "dbname", "user", "password", "sslmode", "sslcert", "sslkey", "sslrootcert", "sslcrl", "application_name", NULL}; static const char *config_values[13] = { NULL }; char *ts3dbplugin_version() { return "0.1"; } char *ts3dbplugin_name() { return "PostgreSQL plugin"; } int ts3dbplugin_disconnect() { unsigned int i; for (i = 0; i < connection_count; i++) { PQfinish(connections[i].conn); } connection_count = 0; return 0; } void ts3dbplugin_shutdown() { ts3dbplugin_disconnect(); if (config != NULL) { iniparser_freedict(config); config = NULL; } } int ts3dbplugin_init(log_callback logging, char *parameter) { log = logging; if (parameter != NULL && strlen(parameter) > 0) { config = iniparser_load(parameter); } else { config = iniparser_load("ts3db_postgres.ini"); } config_values[0] = iniparser_getstring(config, "config:host", "localhost"); config_values[1] = iniparser_getstring(config, "config:hostaddr", "");; config_values[2] = iniparser_getstring(config, "config:port", ""); config_values[3] = iniparser_getstring(config, "config:dbname", "ts3"); config_values[4] = iniparser_getstring(config, "config:user", "ts3"); config_values[5] = iniparser_getstring(config, "config:password", ""); config_values[6] = iniparser_getstring(config, "config:sslmode", NULL); config_values[7] = iniparser_getstring(config, "config:sslcert", NULL); config_values[8] = iniparser_getstring(config, "config:sslkey", NULL); config_values[9] = iniparser_getstring(config, "config:sslrootcert", NULL); config_values[10] = iniparser_getstring(config, "config:sslcrl", NULL); config_values[11] = "teamspeak3"; config_values[12] = NULL; return 0; } int ts3dbplugin_connect(unsigned int *connection_nr) { PGconn *conn; if (connection_count >= MAX_CONNECTIONS) { return 0; } conn = PQconnectdbParams(config_keywords, config_values, 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].modified_rows = 0; connections[connection_count].last_inserted_id = 0; 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; } void save_last_result(unsigned int connection_nr, PGresult *result) { const char *rows, *last_id; if (connection_nr >= connection_count) { log("Connection not found.", LOG_ERROR); return; } connections[connection_nr].modified_rows = 0; connections[connection_nr].last_inserted_id = 0; rows = PQcmdTuples(result); sscanf(rows, "%llu", &connections[connection_nr].modified_rows); if (PQnfields(result) == 1) { if (strcmp(PQfname(result, 0), "last_inserted_id") == 0) { last_id = PQgetvalue(result, 0, 0); log(last_id, LOG_ERROR); sscanf(last_id, "%llu", &connections[connection_nr].last_inserted_id); } } } char *ts3dbplugin_getlasterror(unsigned int connection_nr) { const PGconn *conn = get_connection(connection_nr); return PQerrorMessage(conn); } unsigned int ts3dbplugin_tableexists(unsigned int connection_nr, const char* table_name) { 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) { return connections[connection_nr].modified_rows; } unsigned long long ts3dbplugin_getlastinsertid(unsigned int connection_nr) { return connections[connection_nr].last_inserted_id; } 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) { 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++) { new_field(i, PQfname(result, i), context); } row_count = PQntuples(result); for (i = 0; i < row_count; i++) { new_row(context); for (j = 0; j < col_count; j++) { new_value(j, PQgetvalue(result, i, j), context); } } PQclear(result); return 0; } unsigned int ts3dbplugin_exec(unsigned int connection_nr, const char* query) { 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); } PQclear(result); return 0; }