]> granicus.if.org Git - postgresql/blob - src/interfaces/libpq/fe-connect.c
Whoops, redo Ultrix patch so the other ports still compile.
[postgresql] / src / interfaces / libpq / fe-connect.c
1 /*-------------------------------------------------------------------------
2  *
3  * fe-connect.c--
4  *    functions related to setting up a connection to the backend
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *    $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.21 1996/11/26 07:38:55 bryanh Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14
15 #include <stdlib.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <ctype.h>
22 #include <string.h>
23 #include <netdb.h>
24 #include <errno.h>
25 #include <signal.h>
26 #include <ctype.h>      /* for isspace() */
27
28 #include "postgres.h"
29 #include "libpq/pqcomm.h" /* for decls of MsgType, PacketBuf, StartupInfo */
30 #include "fe-auth.h"
31 #include "libpq-fe.h"
32
33 #ifdef NEED_STRDUP
34 #include "strdup.h"
35 #endif
36
37 #if defined(ultrix4) || defined(next)
38   /* ultrix is lame and doesn't have strdup in libc for some reason */
39  /* [TRH] So doesn't NEXTSTEP.  But whaddaya expect for a non-ANSI  
40 standard function? (My, my. Touchy today, are we?) */
41 char *
42 strdup(const char *string)
43 {
44     char *nstr;
45
46   if ((nstr = malloc(strlen(string)+1)) != NULL)
47       strcpy(nstr, string);
48     return nstr;
49 }
50 #endif
51
52 /* use a local version instead of the one found in pqpacket.c */
53 static ConnStatusType connectDB(PGconn *conn);
54
55 static int packetSend(Port *port, PacketBuf *buf, PacketLen len,
56                       bool nonBlocking);
57 static void startup2PacketBuf(StartupInfo* s, PacketBuf* res);
58 static void freePGconn(PGconn *conn);
59 static void closePGconn(PGconn *conn);
60 static int conninfo_parse(const char *conninfo, char *errorMessage);
61 static char *conninfo_getval(char *keyword);
62 static void conninfo_free(void);
63
64 #define NOTIFYLIST_INITIAL_SIZE 10
65 #define NOTIFYLIST_GROWBY 10
66
67
68 /* ----------
69  * Definition of the conninfo parameters and their fallback resources.
70  * If Environment-Var and Compiled-in are specified as NULL, no
71  * fallback is available. If after all no value can be determined
72  * for an option, an error is returned.
73  *
74  * The values for dbname and user are treated special in conninfo_parse.
75  * If the Compiled-in resource is specified as a NULL value, the
76  * user is determined by fe_getauthname() and for dbname the user
77  * name is copied.
78  *
79  * The Label and Disp-Char entries are provided for applications that
80  * want to use PQconndefaults() to create a generic database connection
81  * dialog. Disp-Char is defined as follows:
82  *     ""       Normal input field
83  * ----------
84  */
85 static PQconninfoOption PQconninfoOptions[] = {
86 /*    ----------------------------------------------------------------- */
87 /*    Option-name       Environment-Var Compiled-in     Current value   */
88 /*                      Label                           Disp-Char       */
89 /*    ----------------- --------------- --------------- --------------- */
90     { "user",           "PGUSER",       NULL,           NULL,
91                         "Database-User",                "", 20  },
92
93     { "dbname",         "PGDATABASE",   NULL,           NULL,
94                         "Database-Name",                "", 20  },
95
96     { "host",           "PGHOST",       DefaultHost,    NULL,
97                         "Database-Host",                "", 40  },
98
99     { "port",           "PGPORT",       DEF_PGPORT,     NULL,
100                         "Database-Port",                "", 6   },
101
102     { "tty",            "PGTTY",        DefaultTty,     NULL,
103                         "Backend-Debug-TTY",            "D", 40 },
104
105     { "options",        "PGOPTIONS",    DefaultOption,  NULL,
106                         "Backend-Debug-Options",        "D", 40 },
107 /*    ----------------- --------------- --------------- --------------- */
108     { NULL,             NULL,           NULL,           NULL,
109                         NULL,                           NULL, 0 }
110 };
111
112 /* ----------------
113  *      PQconnectdb
114  * 
115  * establishes a connectin to a postgres backend through the postmaster
116  * using connection information in a string.
117  *
118  * The conninfo string is a list of
119  *
120  *     option = value
121  *
122  * definitions. Value might be a single value containing no whitespaces
123  * or a single quoted string. If a single quote should appear everywhere
124  * in the value, it must be escaped with a backslash like \'
125  *
126  * Returns a PGconn* which is needed for all subsequent libpq calls
127  * if the status field of the connection returned is CONNECTION_BAD,
128  * then some fields may be null'ed out instead of having valid values 
129  * ----------------
130  */
131 PGconn*
132 PQconnectdb(const char *conninfo)
133 {
134     PGconn *conn;
135     PQconninfoOption *option;
136     char errorMessage[ERROR_MSG_LENGTH];
137
138     /* ----------
139      * Allocate memory for the conn structure
140      * ----------
141      */
142     conn = (PGconn*)malloc(sizeof(PGconn));
143     if (conn == NULL) {
144         fprintf(stderr,
145             "FATAL: PQsetdb() -- unable to allocate memory for a PGconn");
146         return (PGconn*)NULL;
147     }
148     memset((char *)conn, 0, sizeof(PGconn));
149
150     /* ----------
151      * Parse the conninfo string and get the fallback resources
152      * ----------
153      */
154     if(conninfo_parse(conninfo, errorMessage) < 0) {
155         conn->status = CONNECTION_BAD;
156         strcpy(conn->errorMessage, errorMessage);
157         conninfo_free();
158         return conn;
159     }
160
161     /* ----------
162      * Check that we have all connection parameters
163      * ----------
164      */
165     for(option = PQconninfoOptions; option->keyword != NULL; option++) {
166         if(option->val != NULL)  continue;      /* Value was in conninfo */
167
168         /* ----------
169          * No value was found for this option. Return an error.
170          * ----------
171          */
172         conn->status = CONNECTION_BAD;
173         sprintf(conn->errorMessage,
174            "ERROR: PQconnectdb(): Cannot determine a value for option '%s'.\n",
175            option->keyword);
176         strcat(conn->errorMessage,
177             "Option not specified in conninfo string");
178         if(option->environ) {
179             strcat(conn->errorMessage,
180                 ", environment variable ");
181             strcat(conn->errorMessage, option->environ);
182             strcat(conn->errorMessage, "\nnot set");
183         }
184         strcat(conn->errorMessage, " and no compiled in default value.\n");
185         conninfo_free();
186         return conn;
187     }
188
189     /* ----------
190      * Setup the conn structure
191      * ----------
192      */
193     conn->Pfout = NULL;
194     conn->Pfin = NULL;
195     conn->Pfdebug = NULL;
196     conn->port = NULL;
197     conn->notifyList = DLNewList();
198
199     conn->pghost    = strdup(conninfo_getval("host"));
200     conn->pgport    = strdup(conninfo_getval("port"));
201     conn->pgtty     = strdup(conninfo_getval("tty"));
202     conn->pgoptions = strdup(conninfo_getval("options"));
203     conn->pguser    = strdup(conninfo_getval("user"));
204     conn->dbName    = strdup(conninfo_getval("dbname"));
205
206     /* ----------
207      * Free the connection info - all is in conn now
208      * ----------
209      */
210     conninfo_free();
211
212     /* ----------
213      * Connect to the database
214      * ----------
215      */
216     conn->status = connectDB(conn);
217     if (conn->status == CONNECTION_OK) {
218       PGresult *res;
219       /* Send a blank query to make sure everything works; in particular, that
220          the database exists.
221          */ 
222       res = PQexec(conn," ");
223       if (res == NULL || res->resultStatus != PGRES_EMPTY_QUERY) {
224         /* PQexec has put error message in conn->errorMessage */
225         closePGconn(conn);
226       }
227       PQclear(res);
228     } 
229
230     return conn;
231 }
232
233 /* ----------------
234  *      PQconndefaults
235  * 
236  * Parse an empty string like PQconnectdb() would do and return the
237  * address of the connection options structure. Using this function
238  * an application might determine all possible options and their
239  * current default values.
240  * ----------------
241  */
242 PQconninfoOption*
243 PQconndefaults(void)
244 {
245     char errorMessage[ERROR_MSG_LENGTH];
246
247     conninfo_parse("", errorMessage);
248     return PQconninfoOptions;
249 }
250
251 /* ----------------
252  *      PQsetdb
253  * 
254  * establishes a connection to a postgres backend through the postmaster
255  * at the specified host and port.
256  *
257  * returns a PGconn* which is needed for all subsequent libpq calls
258  * if the status field of the connection returned is CONNECTION_BAD,
259  * then some fields may be null'ed out instead of having valid values 
260  *
261  *  Uses these environment variables:
262  *
263  *    PGHOST       identifies host to which to connect if <pghost> argument
264  *                 is NULL or a null string.
265  *
266  *    PGPORT       identifies TCP port to which to connect if <pgport> argument
267  *                 is NULL or a null string.
268  *
269  *    PGTTY        identifies tty to which to send messages if <pgtty> argument
270  *                 is NULL or a null string.
271  *
272  *    PGOPTIONS    identifies connection options if <pgoptions> argument is
273  *                 NULL or a null string.
274  *
275  *    PGUSER       Postgres username to associate with the connection.
276  *
277  *    PGDATABASE   name of database to which to connect if <pgdatabase> 
278  *                 argument is NULL or a null string
279  *
280  *    None of the above need be defined.  There are defaults for all of them.
281  *
282  * ----------------
283  */
284 PGconn* 
285 PQsetdb(const char *pghost, const char* pgport, const char* pgoptions, const char* pgtty, const char* dbName)
286 {
287   PGconn *conn;
288   char *tmp;
289   char errorMessage[ERROR_MSG_LENGTH];
290     /* An error message from some service we call. */
291   bool error;   
292     /* We encountered an error that prevents successful completion */
293
294   conn = (PGconn*)malloc(sizeof(PGconn));
295
296   if (conn == NULL) 
297     fprintf(stderr,
298             "FATAL: PQsetdb() -- unable to allocate memory for a PGconn");
299   else {
300     conn->Pfout = NULL;
301     conn->Pfin = NULL;
302     conn->Pfdebug = NULL;
303     conn->port = NULL;
304     conn->notifyList = DLNewList();
305     
306     if (!pghost || pghost[0] == '\0') {
307       if (!(tmp = getenv("PGHOST"))) {
308         tmp = DefaultHost;
309       }
310       conn->pghost = strdup(tmp);
311     } else
312       conn->pghost = strdup(pghost);
313     
314     if (!pgport || pgport[0] == '\0') {
315       if (!(tmp = getenv("PGPORT"))) {
316         tmp = DEF_PGPORT;
317       }
318       conn->pgport = strdup(tmp);
319     } else
320       conn->pgport = strdup(pgport);
321     
322     if (!pgtty || pgtty[0] == '\0') {
323       if (!(tmp = getenv("PGTTY"))) {
324         tmp = DefaultTty;
325       }
326       conn->pgtty = strdup(tmp);
327     } else
328       conn->pgtty = strdup(pgtty);
329     
330     if (!pgoptions || pgoptions[0] == '\0') {
331       if (!(tmp = getenv("PGOPTIONS"))) {
332         tmp = DefaultOption;
333       }
334       conn->pgoptions = strdup(tmp);
335     } else
336       conn->pgoptions = strdup(pgoptions);
337
338     if ((tmp = getenv("PGUSER"))) {
339       error = FALSE;
340       conn->pguser = strdup(tmp);
341     } else {
342       tmp = fe_getauthname(errorMessage);
343       if (tmp == 0) {
344         error = TRUE;
345         sprintf(conn->errorMessage,
346                 "FATAL: PQsetdb: Unable to determine a Postgres username!\n");
347       } else {
348         error = FALSE;
349         conn->pguser = tmp;
350       }
351     }
352
353     if (!error) {
354       if (((tmp = (char *)dbName) && (dbName[0] != '\0')) ||
355           ((tmp = getenv("PGDATABASE")))) {
356         conn->dbName = strdup(tmp);
357       } else conn->dbName = strdup(conn->pguser);
358     } else conn->dbName = NULL;
359
360     if (error) conn->status = CONNECTION_BAD;
361     else {
362       conn->status = connectDB(conn);  
363         /* Puts message in conn->errorMessage */
364       if (conn->status == CONNECTION_OK) {
365         PGresult *res;
366         /* Send a blank query to make sure everything works; 
367            in particular, that the database exists.
368            */
369         res = PQexec(conn," ");
370         if (res == NULL || res->resultStatus != PGRES_EMPTY_QUERY) {
371           /* PQexec has put error message in conn->errorMessage */
372           closePGconn(conn);
373         }
374         PQclear(res);
375       }
376     }
377   }        
378   return conn;
379 }
380
381     
382 /*
383  * connectDB -
384  * make a connection to the backend so it is ready to receive queries.  
385  * return CONNECTION_OK if successful, CONNECTION_BAD if not.
386  *
387  */
388 static ConnStatusType
389 connectDB(PGconn *conn)
390 {
391     struct hostent *hp;
392
393     StartupInfo startup;
394     PacketBuf   pacBuf;
395     int         status;
396     MsgType     msgtype;
397     int         laddrlen = sizeof(struct sockaddr);
398     Port        *port = conn->port;
399     int         portno;
400
401     /*
402     //
403     // Initialize the startup packet. 
404     //
405     // This data structure is used for the seq-packet protocol.  It
406     // describes the frontend-backend connection.
407     //
408     //
409     */
410     strncpy(startup.user,conn->pguser,sizeof(startup.user));
411     strncpy(startup.database,conn->dbName,sizeof(startup.database));
412     strncpy(startup.tty,conn->pgtty,sizeof(startup.tty));
413     if (conn->pgoptions) {
414         strncpy(startup.options,conn->pgoptions, sizeof(startup.options));
415     }
416     else
417         startup.options[0]='\0'; 
418     startup.execFile[0]='\0';  /* not used */
419
420     /*
421     //
422     // Open a connection to postmaster/backend.
423     //
424     */
425     port = (Port *) malloc(sizeof(Port));
426     memset((char *) port, 0, sizeof(Port));
427
428     if (!(hp = gethostbyname(conn->pghost)) || hp->h_addrtype != AF_INET) {
429         (void) sprintf(conn->errorMessage,
430                        "connectDB() --  unknown hostname: %s\n",
431                        conn->pghost);
432         goto connect_errReturn;
433     }
434     memset((char *) &port->raddr, 0, sizeof(port->raddr));
435     memmove((char *) &(port->raddr.sin_addr),
436             (char *) hp->h_addr, 
437             hp->h_length);
438     port->raddr.sin_family = AF_INET;
439     portno = atoi(conn->pgport);
440     port->raddr.sin_port = htons((unsigned short)(portno));
441     
442     /* connect to the server  */
443     if ((port->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
444         (void) sprintf(conn->errorMessage,
445                "connectDB() -- socket() failed: errno=%d\n%s\n",
446                errno, strerror(errno));
447         goto connect_errReturn; 
448     }
449     if (connect(port->sock, (struct sockaddr *)&port->raddr,
450                 sizeof(port->raddr)) < 0) {
451         (void) sprintf(conn->errorMessage,
452                        "connectDB() failed: Is the postmaster running at '%s' on port '%s'?\n",
453                        conn->pghost,conn->pgport);
454         goto connect_errReturn; 
455     }
456     
457
458     /* fill in the client address */
459     if (getsockname(port->sock, (struct sockaddr *) &port->laddr,
460                     &laddrlen) < 0) {
461         (void) sprintf(conn->errorMessage,
462                "connectDB() -- getsockname() failed: errno=%d\n%s\n",
463                errno, strerror(errno));
464         goto connect_errReturn; 
465     }
466     
467     /* by this point, connection has been opened */
468     msgtype = fe_getauthsvc(conn->errorMessage);
469
470 /*    pacBuf = startup2PacketBuf(&startup);*/
471     startup2PacketBuf(&startup, &pacBuf);
472     pacBuf.msgtype = (MsgType) htonl(msgtype);
473     status = packetSend(port, &pacBuf, sizeof(PacketBuf), BLOCKING);
474     
475     if (status == STATUS_ERROR)
476         {
477         sprintf(conn->errorMessage,
478                "connectDB() --  couldn't send complete packet: errno=%d\n%s\n", errno,strerror(errno));
479         goto connect_errReturn;
480         }
481
482     /* authenticate as required*/
483     if (fe_sendauth(msgtype, port, conn->pghost, 
484                     conn->errorMessage) != STATUS_OK) {
485       (void) sprintf(conn->errorMessage,
486              "connectDB() --  authentication failed with %s\n",
487                conn->pghost);
488       goto connect_errReturn;   
489     }
490     
491     /* set up the socket file descriptors */
492     conn->Pfout = fdopen(port->sock, "w");
493     conn->Pfin = fdopen(dup(port->sock), "r");
494     if (!conn->Pfout || !conn->Pfin) {
495         (void) sprintf(conn->errorMessage,
496                "connectDB() -- fdopen() failed: errno=%d\n%s\n",
497                errno, strerror(errno));
498       goto connect_errReturn;   
499     }
500     
501     conn->port = port;
502
503     return CONNECTION_OK;
504
505 connect_errReturn:
506     return CONNECTION_BAD;
507
508 }
509
510 /*
511  * freePGconn
512  *   - free the PGconn data structure 
513  *
514  */
515 static void 
516 freePGconn(PGconn *conn)
517 {
518   if (conn->pghost) free(conn->pghost);
519   if (conn->pgtty) free(conn->pgtty);
520   if (conn->pgoptions) free(conn->pgoptions);
521   if (conn->pgport) free(conn->pgport);
522   if (conn->dbName) free(conn->dbName);
523   if (conn->pguser) free(conn->pguser);
524   if (conn->notifyList) DLFreeList(conn->notifyList);
525   free(conn);
526 }
527
528 /*
529    closePGconn
530      - properly close a connection to the backend
531 */
532 static void
533 closePGconn(PGconn *conn)
534 {
535     struct sigaction ignore_action;
536       /* This is used as a constant, but not declared as such because the
537          sigaction structure is defined differently on different systems */
538     struct sigaction oldaction;
539
540     /* If connection is already gone, that's cool.  No reason for kernel
541        to kill us when we try to write to it.  So ignore SIGPIPE signals.
542        */
543     ignore_action.sa_handler = SIG_IGN;
544     sigemptyset(&ignore_action.sa_mask);
545     ignore_action.sa_flags = 0;
546     sigaction(SIGPIPE, (struct sigaction *) &ignore_action, &oldaction);
547
548     fputs("X\0", conn->Pfout);
549     fflush(conn->Pfout);
550     sigaction(SIGPIPE, &oldaction, NULL);
551     if (conn->Pfout) fclose(conn->Pfout);
552     if (conn->Pfin)  fclose(conn->Pfin);
553     if (conn->Pfdebug) fclose(conn->Pfdebug);
554     conn->status = CONNECTION_BAD;  /* Well, not really _bad_ - just absent */
555 }
556
557 /*
558    PQfinish:
559       properly close a connection to the backend
560       also frees the PGconn data structure so it shouldn't be re-used 
561       after this
562 */
563 void
564 PQfinish(PGconn *conn)
565 {
566   if (!conn) {
567     fprintf(stderr,"PQfinish() -- pointer to PGconn is null");
568   } else {
569     if (conn->status == CONNECTION_OK)
570       closePGconn(conn);
571     freePGconn(conn);
572   }
573 }
574
575 /* PQreset :
576    resets the connection to the backend
577    closes the existing connection and makes a new one 
578 */
579 void
580 PQreset(PGconn *conn)
581 {
582   if (!conn) {
583     fprintf(stderr,"PQreset() -- pointer to PGconn is null");
584   } else {
585     closePGconn(conn);
586     conn->status = connectDB(conn);
587   }
588 }
589
590 /*
591  * PacketSend()
592  *
593  this is just like PacketSend(), defined in backend/libpq/pqpacket.c
594  but we define it here to avoid linking in all of libpq.a
595
596  * packetSend -- send a single-packet message.
597  *
598  * RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise.
599  * SIDE_EFFECTS: may block.
600  * NOTES: Non-blocking writes would significantly complicate 
601  *      buffer management.  For now, we're not going to do it.
602  *
603 */
604 static int
605 packetSend(Port *port,
606            PacketBuf *buf,
607            PacketLen len,
608            bool nonBlocking)
609 {
610     PacketLen   totalLen;
611     int         addrLen = sizeof(struct sockaddr_in);
612     
613     totalLen = len;
614     
615     len = sendto(port->sock, (Addr) buf, totalLen, /* flags */ 0,
616                  (struct sockaddr *)&(port->raddr), addrLen);
617     
618     if (len < totalLen) {
619         return(STATUS_ERROR);
620     }
621     
622     return(STATUS_OK);
623 }
624
625 /*
626  * startup2PacketBuf()
627  *
628  * this is just like StartupInfo2Packet(), defined in backend/libpq/pqpacket.c
629  * but we repeat it here so we don't have to link in libpq.a
630  * 
631  * converts a StartupInfo structure to a PacketBuf
632  */
633 static void
634 startup2PacketBuf(StartupInfo* s, PacketBuf* res)
635 {
636   char* tmp;
637
638 /*  res = (PacketBuf*)malloc(sizeof(PacketBuf)); */
639   res->len = htonl(sizeof(PacketBuf));
640   /* use \n to delimit the strings */
641   res->data[0] = '\0';
642
643   tmp= res->data;
644
645   strncpy(tmp, s->database, sizeof(s->database));
646   tmp += sizeof(s->database);
647   strncpy(tmp, s->user, sizeof(s->user));
648   tmp += sizeof(s->user);
649   strncpy(tmp, s->options, sizeof(s->options));
650   tmp += sizeof(s->options);
651   strncpy(tmp, s->execFile, sizeof(s->execFile));
652   tmp += sizeof(s->execFile);
653   strncpy(tmp, s->tty, sizeof(s->execFile));
654 }
655
656 /* ----------------
657  * Conninfo parser routine
658  * ----------------
659  */
660 static int conninfo_parse(const char *conninfo, char *errorMessage)
661 {
662     char *pname;
663     char *pval;
664     char *buf;
665     char *tmp;
666     char *cp;
667     char *cp2;
668     PQconninfoOption *option;
669     char errortmp[ERROR_MSG_LENGTH];
670
671     conninfo_free();
672
673     if((buf = strdup(conninfo)) == NULL) {
674         strcpy(errorMessage, 
675                 "FATAL: cannot allocate memory for copy of conninfo string\n");
676         return -1;
677     }
678     cp = buf;
679
680     while(*cp) {
681         /* Skip blanks before the parameter name */
682         if(isspace(*cp)) {
683             cp++;
684             continue;
685         }
686
687         /* Get the parameter name */
688         pname = cp;
689         while(*cp) {
690             if(*cp == '=') {
691                 break;
692             }
693             if(isspace(*cp)) {
694                 *cp++ = '\0';
695                 while(*cp) {
696                     if(!isspace(*cp)) {
697                         break;
698                     }
699                     cp++;
700                 }
701                 break;
702             }
703             cp++;
704         }
705
706         /* Check that there is a following '=' */
707         if(*cp != '=') {
708             sprintf(errorMessage,
709                 "ERROR: PQconnectdb() - Missing '=' after '%s' in conninfo\n",
710                 pname);
711             free(buf);
712             return -1;
713         }
714         *cp++ = '\0';
715
716         /* Skip blanks after the '=' */
717         while(*cp) {
718             if(!isspace(*cp)) {
719                 break;
720             }
721             cp++;
722         }
723
724         pval = cp;
725
726         if(*cp != '\'') {
727             cp2 = pval;
728             while(*cp) {
729                 if(isspace(*cp)) {
730                     *cp++ = '\0';
731                     break;
732                 }
733                 if(*cp == '\\') {
734                     cp++;
735                     if(*cp != '\0') {
736                         *cp2++ = *cp++;
737                     }
738                 } else {
739                     *cp2++ = *cp++;
740                 }
741             }
742             *cp2  = '\0';
743         } else {
744             cp2 = pval;
745             cp++;
746             for(;;) {
747                 if(*cp == '\0') {
748                     sprintf(errorMessage,
749                       "ERROR: PQconnectdb() - unterminated quoted string in conninfo\n");
750                     free(buf);
751                     return -1;
752                 }
753                 if(*cp == '\\') {
754                     cp++;
755                     if(*cp != '\0') {
756                         *cp2++ = *cp++;
757                     }
758                     continue;
759                 }
760                 if(*cp == '\'') {
761                     *cp2 = '\0';
762                     cp++;
763                     break;
764                 }
765                 *cp2++ = *cp++;
766             }
767         }
768
769         /* ----------
770          * Now we have the name and the value. Search
771          * for the param record.
772          * ----------
773          */
774         for(option = PQconninfoOptions; option->keyword != NULL; option++) {
775             if(!strcmp(option->keyword, pname)) {
776                 break;
777             }
778         }
779         if(option->keyword == NULL) {
780             sprintf(errorMessage,
781                 "ERROR: PQconnectdb() - unknown option '%s'\n",
782                 pname);
783             free(buf);
784             return -1;
785         }
786
787         /* ----------
788          * Store the value
789          * ----------
790          */
791         option->val = strdup(pval);
792     }
793
794     free(buf);
795
796     /* ----------
797      * Get the fallback resources for parameters not specified
798      * in the conninfo string.
799      * ----------
800      */
801     for(option = PQconninfoOptions; option->keyword != NULL; option++) {
802         if(option->val != NULL)  continue;      /* Value was in conninfo */
803
804         /* ----------
805          * Try to get the environment variable fallback
806          * ----------
807          */
808         if(option->environ != NULL) {
809             if((tmp = getenv(option->environ)) != NULL) {
810                 option->val = strdup(tmp);
811                 continue;
812             }
813         }
814
815         /* ----------
816          * No environment variable specified or this one isn't set -
817          * try compiled in
818          * ----------
819          */
820         if(option->compiled != NULL) {
821             option->val = strdup(option->compiled);
822             continue;
823         }
824
825         /* ----------
826          * Special handling for user
827          * ----------
828          */
829         if(!strcmp(option->keyword, "user")) {
830             tmp = fe_getauthname(errortmp);
831             if (tmp) {
832                 option->val = strdup(tmp);
833             }
834         }
835
836         /* ----------
837          * Special handling for dbname
838          * ----------
839          */
840         if(!strcmp(option->keyword, "dbname")) {
841             tmp = conninfo_getval("user");
842             if (tmp) {
843                 option->val = strdup(tmp);
844             }
845         }
846     }
847
848     return 0;
849 }
850
851
852 static char*
853 conninfo_getval(char *keyword)
854 {
855     PQconninfoOption *option;
856
857     for(option = PQconninfoOptions; option->keyword != NULL; option++) {
858         if (!strcmp(option->keyword, keyword)) {
859             return option->val;
860         }
861     }
862
863     return NULL;
864 }
865
866
867 static void
868 conninfo_free()
869 {
870     PQconninfoOption *option;
871
872     for(option = PQconninfoOptions; option->keyword != NULL; option++) {
873         if(option->val != NULL) {
874             free(option->val);
875             option->val = NULL;
876         }
877     }
878 }
879
880 /* =========== accessor functions for PGconn ========= */
881 char* 
882 PQdb(PGconn* conn)
883 {
884   if (!conn) {
885     fprintf(stderr,"PQdb() -- pointer to PGconn is null");
886     return (char *)NULL;
887   }
888   return conn->dbName;
889 }
890
891 char* 
892 PQuser(PGconn* conn)
893 {
894   if (!conn) {
895     fprintf(stderr,"PQuser() -- pointer to PGconn is null");
896     return (char *)NULL;
897   }
898   return conn->pguser;
899 }
900
901 char* 
902 PQhost(PGconn* conn)
903 {
904   if (!conn) {
905     fprintf(stderr,"PQhost() -- pointer to PGconn is null");
906     return (char *)NULL;
907   }
908
909   return conn->pghost;
910 }
911
912 char* 
913 PQoptions(PGconn* conn)
914 {
915   if (!conn) {
916     fprintf(stderr,"PQoptions() -- pointer to PGconn is null");
917     return (char *)NULL;
918   }
919   return conn->pgoptions;
920 }
921
922 char* 
923 PQtty(PGconn* conn)
924 {
925   if (!conn) {
926     fprintf(stderr,"PQtty() -- pointer to PGconn is null");
927     return (char *)NULL;
928   }
929   return conn->pgtty;
930 }
931
932 char*
933 PQport(PGconn* conn)
934 {
935   if (!conn) {
936     fprintf(stderr,"PQport() -- pointer to PGconn is null");
937     return (char *)NULL;
938   }
939   return conn->pgport;
940 }
941
942 ConnStatusType
943 PQstatus(PGconn* conn)
944 {
945   if (!conn) {
946     fprintf(stderr,"PQstatus() -- pointer to PGconn is null");
947     return CONNECTION_BAD;
948   }
949   return conn->status;
950 }
951
952 char* 
953 PQerrorMessage(PGconn* conn)
954 {
955   if (!conn) {
956     fprintf(stderr,"PQerrorMessage() -- pointer to PGconn is null");
957     return (char *)NULL;
958   }
959   return conn->errorMessage;
960 }
961
962 void
963 PQtrace(PGconn *conn, FILE* debug_port)
964 {
965   if (conn == NULL ||
966       conn->status == CONNECTION_BAD) {
967     return;
968   }
969   PQuntrace(conn);
970   conn->Pfdebug = debug_port;
971 }
972
973 void 
974 PQuntrace(PGconn *conn)
975 {
976   if (conn == NULL ||
977       conn->status == CONNECTION_BAD) {
978     return;
979   }
980   if (conn->Pfdebug) {
981     fflush(conn->Pfdebug);
982     fclose(conn->Pfdebug);
983     conn->Pfdebug = NULL;
984   }
985 }