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