/*
 * PostgreSQL Database Driver for Kamailio
 *
 * Portions Copyright (C) 2001-2003 FhG FOKUS
 * Copyright (C) 2003 August.Net Services, LLC
 * Portions Copyright (C) 2005-2008 iptelorg GmbH
 *
 * This file is part of Kamailio, a free SIP server.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 *
 * Kamailio is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version
 *
 * Kamailio is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/** \addtogroup postgres
 * @{
 */

/** \file
 * Implementation of functions related to PostgreSQL Oid identifiers.
 */


#include "pg_oid.h"
#include "../../core/dprint.h"
#include "../../core/ut.h"
#include <strings.h>
#include <stdlib.h>
#include <string.h>

/** An array of supported PostgreSQL field types. */
static char *pg_type_id_name[] = {
		"bool",
		"bytea",
		"char",
		"int8",
		"int2",
		"int4",
		"text",
		"float4",
		"float8",
		"inet",
		"bpchar",
		"varchar",
		"timestamp",
		"timestamptz",
		"bit",
		"varbit",
};


static int get_index(char *name)
{
	int i;

	for(i = 0; i < PG_ID_MAX; i++) {
		if(strcasecmp(name, pg_type_id_name[i]) == 0)
			return i;
	}
	return -1;
}


pg_type_t *pg_new_oid_table(PGresult *res)
{
	pg_type_t *table = NULL;
	int row, n = 0, end, idx, fields;
	str s;

	if(res == NULL || PQresultStatus(res) != PGRES_TUPLES_OK)
		goto error;

	n = PQntuples(res);
	if(n <= 0)
		goto error;
	fields = PQnfields(res);
	if(fields != 2)
		goto error;

	table = (pg_type_t *)malloc(sizeof(pg_type_t) * (n + 1));
	if(table == NULL)
		goto error;
	memset(table, '\0', sizeof(pg_type_t) * (n + 1));

	end = n - 1;
	for(row = 0; row < n; row++) {

		/* Get name */
		s.s = PQgetvalue(res, row, 0);
		if(s.s == NULL)
			goto error;

		/* Find index where the record is to be stored */
		idx = get_index(s.s);
		if(idx == -1)
			idx = end--;

		/* Store the name */
		table[idx].name = strdup(s.s);
		if(table[idx].name == NULL)
			goto error;

		/* Oid */
		s.s = PQgetvalue(res, row, 1);
		if(s.s == NULL)
			goto error;
		s.len = strlen(s.s);
		if(str2int(&s, &table[idx].oid) < 0)
			goto error;

		DBG("postgres: Type %s maps to Oid %d\n", table[idx].name,
				table[idx].oid);
	}
	return table;

error:
	ERR("postgres: Error while obtaining field/data type description from "
		"server\n");
	if(table) {
		for(idx = 0; idx < n; idx++) {
			if(table[idx].name)
				free(table[idx].name);
		}
		free(table);
	}
	return NULL;
}


void pg_destroy_oid_table(pg_type_t *table)
{
	int i;
	if(table) {
		for(i = 0; table[i].name; i++) {
			free(table[i].name);
		}
		free(table);
	}
}


int pg_name2oid(Oid *oid, pg_type_t *table, const char *name)
{
	int i;

	if(!oid || !table) {
		BUG("postgres: Invalid parameters to pg_name2oid\n");
		return -1;
	}

	if(name == NULL || name[0] == '\0')
		return 1;

	for(i = 0; table[i].name; i++) {
		if(strcasecmp(table[i].name, name) == 0) {
			*oid = table[i].oid;
			return 0;
		}
	}
	return 1;
}


int pg_oid2name(const char **name, pg_type_t *table, Oid oid)
{
	int i;

	if(!table || !name) {
		BUG("postgres: Invalid parameters to pg_oid2name\n");
		return -1;
	}

	for(i = 0; table[i].name; i++) {
		if(oid == table[i].oid) {
			*name = table[i].name;
			return 0;
		}
	}
	return 1;
}

/** @} */
