/* 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_fill_dbConn()
 *     
 * DESCRIPTION
 *     This file contains functions for managing a postgres database 
 *     connection. Only one Postgres connection can be live at a time.
 *
 * DIAGNOSTICS
 *     pg_conn functions return GDI_SUCCESS or GDI_FAILURE.
 *
 * FILES
 *     pg_conn.c (this file)
 *
 * SEE ALSO
 *     libgendb.h
 *
 * AUTHOR
 *     Jean T. Anderson, SAIC Open Systems Division
 */

#ifndef     lint
static char SccsId[] = "@(#)pg_conn.c	16.4 8/7/93 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 void, pg_fill_dbConn, (dbConn *) );

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

/*
 * pg_open ()
 *
 * Allocates the vendor connection, opens a connection to a database, and
 * adds one query channel. The GDI default is 2, but jta doesn't think more
 * than one is going to get used. The calling application can always add more.
 *
 * Only one connection to Postgres is allowed at a time.
 *
 * Called by gdi_open, returns SUCCESS or FAILURE.
 *
 * Public
 * 
 * AUTHOR
 *     J. T. Anderson, SAIC Open Systems Division, jean@gso.saic.com
 */

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     *pgdb; 
     char     msg_buf [GDI_ERROR_SIZE + 1];

     int     chan;

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

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

     /* FORTRAN, or anybody using libpar, might pass in a blank. */
     if ( (database[0] == '\0') || (database[0] == ' ') )
     {
          /* Do it like the monitor does ..... */
          if( !(pgdb = getenv("PGDATABASE")) && !(pgdb = getenv("USER")) )
          {
               sprintf(msg_buf, "%s: No database name", routine);
                      (void) gdi_error_app (conn, GDI_BADDATA, msg_buf);
               return(GDI_FAILURE);
          }

          if (conn->debug == GDI_DEBUG_VERBOSE)
               fprintf(stderr,
                    "%16s: setting database to '%s' from environment.\n", 
                    routine, pgdb);
     }
     else
          pgdb=database;

     /* If already connected, kick it back. */
     if(PQportset)
     {          
          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);
     }

     /* FORTRAN, or anybody using libpar, might 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
      * ====================
      */

     PQsetdb(pgdb);

     /* PQportset isn't set until something happens. So it's a good time
      * to make sure the GDI user-defined functions are in place.
      */

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

     if(!PQportset)
          return(GDI_FAILURE);

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


     /* ==================
      *  Add one 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;

     /* Futuree note: 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_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;
{
     char *p;

     if ((p = getenv("USER")) != NULL)
          (void) strcpy(GDI_ACCOUNT(conn), p);

     (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;
}
