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