/* See the copyright notice (COPYRIGHT) in this directory. */

/*
 * NAME
 *
 * Public:
 *        pg_open()       Open a connection to the database.
 *        pg_close()      Close a database connection.
 *        pg_dead()       Ping the connection.
 *
 * Private:
 *        pg_connect()
 *        pg_fill_dbConn()
 *        
 * DESCRIPTION
 *        This file contains functions for managing a postgres database 
 *        connection. Only one Postgres connection can be live at a given 
 *        moment.
 *
 * DIAGNOSTICS
 *        Functions which return pointers return NULL if an error occurs.
 *        Functions which return a non-negative int will return -1 if an error 
 *        occured.
 *
 * FILES
 *        pg_conn.c (this file)
 *
 * SEE ALSO
 *        libgendb.h
 *
 * AUTHOR
 *        Jean T. Anderson, SAIC Open Systems Division
 */

#ifndef        lint
static char SccsId[] = "%W% %G% Copyright (c) 1992-1993 Science Applications International Corporation";
#endif

#include "gdi_postgres.h"

extern dbConn null_conn;        /* declared in gdi_error.c */

extern char     *PQhost;        /* Globals declared in fe-pqexec.c */
extern char     *PQtty;
extern char     PQdatabase[];
extern int      PQportset;

Proto ( static dbStatus, pg_connect, (dbConn *, char *) );
Proto ( static void, pg_fill_dbConn, (dbConn *) );

/* ========================= pg_open() ===================================== */

/*
 * pg_open ()
 *
 * Allocates the vendor connection, opens a connection to a database, 
 * and adds two channels.
 *
 * Only one connection to Postgres is allowed at a time, but additional
 * channels can be opened. 
 *
 * Called by gdi_open, returns SUCCESS or FAILURE.
 *
 * Public
 * 
 * AUTHOR
 *        J. T. Anderson, SAIC Open Systems Division, jean@gso.saic.com
 *
 * MODS
 *    jta   7/4/93    Only sets up one channel; the likelihood more will
 *                    be used is doubtful.
 *    jta   8/6/93    Took out PGDATABASE check because you can also connect
 *                    based on USER. libpq handles the relevant checking.
 */

dbStatus
pg_open (conn, account, password, database, server, appname)
dbConn      *conn;
char        *account;        /* NULL for Postgres */
char        *password;       /* NULL for Postgres */
char        *database;       /* Optional (PGDATABASE) */
char        *server;         /* Optional (PGHOST) */
char        *appname;        /* NULL for Postgres */
{
        char    *routine = "pg_open";
        char    msg_buf [GDI_ERROR_SIZE + 1];

        int     chan;

        /* ============
         *  Initial QA
         * ============
         */

        if (conn->debug == GDI_DEBUG_VERBOSE)
               fprintf(stderr, "%16s: opening connection to Postgres\n",
                    routine);

        if(PQportset)
        {                /* If already connected, kick it back */
                sprintf(msg_buf, 
                        "%16s: already connected to a POSTGRES database--disconnect with gdi_close() and try again.", routine);
                (void) gdi_error_app (conn, GDI_NOCONNECT, msg_buf);
                return (GDI_FAILURE);
        }

         /* The FORTRAN xface or anybody using libpar could pass in a blank. */
        if( server != NULL )
             if( (strlen(server) > 0) && (server[0] != ' ') )
                 PQhost = server;

        /* =====================
         * Allocate vendor_conn 
         * =====================
         */
        if ((conn->vendor_conn = (void *) UCALLOC (dbConnPostgres, 1)) == NULL)
        {       (void) gdi_error_unix (conn, routine);
                return (GDI_FAILURE);
        }

        /* ====================
         *  Connect to database
         * ====================
         */
        if( pg_connect(conn, database) != GDI_SUCCESS )
                return(GDI_FAILURE);

        /* ===================================
         * Fill in dbConn and vendor_conn info 
         * ===================================
         */
        pg_fill_dbConn(conn);

        /* ====================
         *  Add a query channel
         * ====================
         */
        if (pg_open_channel (conn, &chan) != GDI_SUCCESS) 
        {       pg_close (conn);
                return (GDI_FAILURE);
        }

        return (GDI_SUCCESS);
}


/*
 * pg_close ()
 *
 * Close the database connection, clean up any temp tables, and deallocate 
 * the vendor_conn.
 *
 * Public
 */

dbStatus
pg_close (conn)
dbConn                *conn;
{
        char *routine = "pg_close";
        int i;

                /* clean up temp tables */

                /* Free channels, vendor conn, and dbConn */
        for (i = 0; i <  PG_NUM_CHANNELS (conn); i++)
                (void) pg_close_channel(conn, i);

        UFREE(PG_CHANNELS(conn));

        UFREE (conn->vendor_conn);

                /* Close database connection */
        PQfinish();

        if (conn->debug == GDI_DEBUG_VERBOSE)
               fprintf(stderr, "%16s: closed connection to Postgres\n",
                    routine);

        return (GDI_SUCCESS);
}


/*
 * pg_dead ()
 *
 * Determine if a connection is dead.  Return TRUE if dead or FALSE if live.
 *
 * Public
 */

dbStatus
pg_dead (conn)
dbConn        *conn;
{
        if(PQportset)
                return (FALSE);
        else
                return (TRUE);
}

/* ============================================
 *  pg_connect()
 *
 *  Actually connect and validate connection
 *
 *  Private
 * ============================================
 */
static
dbStatus
pg_connect(conn, pgdb)
dbConn *conn;
char *pgdb;
{

        PQsetdb(pgdb);

        /* PQportset doesn't get turned on until something happens.  So go
         * ahead and make sure the user-defined the GDI uses are in place.
         */

        if( (pg_gdi_funcs(conn)) == GDI_FAILURE)
                return(GDI_FAILURE);

        if(!PQportset)
                return(GDI_FAILURE);

        return(GDI_SUCCESS);
}

/* pg_fill_dbConn()
 * 
 * Fill in the dbConn with the bits of info we are carting around so far.
 *
 * Private
 */
static
void
pg_fill_dbConn(conn)
dbConn        *conn;
{
        (void) pg_strncpy(GDI_ACCOUNT(conn), "n/a for postgres", 
                GDI_ACCOUNT_SIZE, 16);

        (void) pg_strncpy(GDI_DATABASE(conn), PQdatabase,
                GDI_DBNAME_SIZE, strlen(PQdatabase));
        (void) pg_strncpy(GDI_NODE(conn), PQhost, 
                GDI_NODE_SIZE, strlen(PQhost));
        GDI_LANG(conn) = GDI_POSTQUEL;
        PG_TRAN(conn) = FALSE;

                /* Initialize Error Flags */
        (void) gdi_error_init (conn, FALSE, GDI_WARNING, 0, 0);
        return;
}
