summaryrefslogblamecommitdiffstats
path: root/ts3db.c
blob: d056a5eb3279e3f9eeaa88e2cddafe10186bcb60 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                  

                     
                   
                      
 
                          


                 

                                        
                

                            


                                                  






                                                                          


                           




                        
                               



                            

                                            



                                      










                                   



                                                           
                  
 



















                                                                               




                                                    

                 



                                              
                                                                   






                                                

                                                       
                       
 


             









                                                  
                                                                   
 
                               




                                                








                                                                    
 



                                                                                  



                                                          





                                                                                        
















                                                                
 




                                                                              
                                                    



                                                                          
                                                       





                                                                                 

















                                                                      




                                                  
                         

                                         
                                                            


         
                    




                                                                            














                                                                      
                    

             
#include "ts3db.h"
#include <libpq-fe.h>
#include <stdbool.h>
#include <string.h>
#include <iniparser.h>

#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:sslcrt", 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;
}