]> granicus.if.org Git - postgresql/blob - src/interfaces/libpq/fe-connect.c
As proposed,
[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.18 1996/11/11 12:16:54 scrappy 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 #if defined(ultrix4) || defined(next)
34   /* ultrix is lame and doesn't have strdup in libc for some reason */
35  /* [TRH] So doesn't NEXTSTEP.  But whaddaya expect for a non-ANSI  
36 standard function? (My, my. Touchy today, are we?) */
37 static
38 char *
39 strdup(const char *string)
40 {
41     char *nstr;
42
43   if ((nstr = malloc(strlen(string)+1)) != NULL)
44       strcpy(nstr, string);
45     return nstr;
46 }
47 #endif
48
49 /* use a local version instead of the one found in pqpacket.c */
50 static ConnStatusType connectDB(PGconn *conn);
51
52 static int packetSend(Port *port, PacketBuf *buf, PacketLen len,
53                       bool nonBlocking);
54 static void startup2PacketBuf(StartupInfo* s, PacketBuf* res);
55 static void freePGconn(PGconn *conn);
56 static void closePGconn(PGconn *conn);
57 static int conninfo_parse(const char *conninfo, char *errorMessage);
58 static char *conninfo_getval(char *keyword);
59 static void conninfo_free(void);
60
61 #define NOTIFYLIST_INITIAL_SIZE 10
62 #define NOTIFYLIST_GROWBY 10
63
64
65 /* ----------
66  * Definition of the conninfo parametes and their fallback resources.
67  * If Environment-Var and Compiled-in are specified as NULL, no
68  * fallback is available. If after all no value can be determined
69  * for an option, an error is returned.
70  *
71  * The values for dbname and user are treated special in conninfo_parse.
72  * If the Compiled-in resource is specified as a NULL value, the
73  * user is determined by fe_getauthname() and for dbname the user
74  * name is copied.
75  *
76  * The Label and Disp-Char entries are provided for applications that
77  * want to use PQconndefaults() to create a generic database connection
78  * dialog. Disp-Char is defined as follows:
79  *     ""       Normal input field
80  * ----------
81  */
82 static PQconninfoOption PQconninfoOptions[] = {
83 /*    ----------------------------------------------------------------- */
84 /*    Option-name       Environment-Var Compiled-in     Current value   */
85 /*                      Label                           Disp-Char       */
86 /*    ----------------- --------------- --------------- --------------- */
87     { "user",           "PGUSER",       NULL,           NULL,
88                         "Database-User",                "", 20  },
89
90     { "dbname",         "PGDATABASE",   NULL,           NULL,
91                         "Database-Name",                "", 20  },
92
93     { "host",           "PGHOST",       DefaultHost,    NULL,
94                         "Database-Host",                "", 40  },
95
96     { "port",           "PGPORT",       POSTPORT,       NULL,
97                         "Database-Port",                "", 6   },
98
99     { "tty",            "PGTTY",        DefaultTty,     NULL,
100                         "Backend-Debug-TTY",            "D", 40 },
101
102     { "options",        "PGOPTIONS",    DefaultOption,  NULL,
103                         "Backend-Debug-Options",        "D", 40 },
104 /*    ----------------- --------------- --------------- --------------- */
105     { NULL,             NULL,           NULL,           NULL,
106                         NULL,                           NULL, 0 }
107 };
108
109 /* ----------------
110  *      PQconnectdb
111  * 
112  * establishes a connectin to a postgres backend through the postmaster
113  * using connection information in a string.
114  *
115  * The conninfo string is a list of
116  *
117  *     option = value
118  *
119  * definitions. Value might be a single value containing no whitespaces
120  * or a single quoted string. If a single quote should appear everywhere
121  * in the value, it must be escaped with a backslash like \'
122  *
123  * Returns a PGconn* which is needed for all subsequent libpq calls
124  * if the status field of the connection returned is CONNECTION_BAD,
125  * then some fields may be null'ed out instead of having valid values 
126  * ----------------
127  */
128 PGconn*
129 PQconnectdb(const char *conninfo)
130 {
131     PGconn *conn;
132     PQconninfoOption *option;
133     char errorMessage[ERROR_MSG_LENGTH];
134
135     /* ----------
136      * Allocate memory for the conn structure
137      * ----------
138      */
139     conn = (PGconn*)malloc(sizeof(PGconn));
140     if (conn == NULL) {
141         fprintf(stderr,
142             "FATAL: PQsetdb() -- unable to allocate memory for a PGconn");
143         return (PGconn*)NULL;
144     }
145     memset((char *)conn, 0, sizeof(PGconn));
146
147     /* ----------
148      * Parse the conninfo string and get the fallback resources
149      * ----------
150      */
151     if(conninfo_parse(conninfo, errorMessage) < 0) {
152         conn->status = CONNECTION_BAD;
153         strcpy(conn->errorMessage, errorMessage);
154         conninfo_free();
155         return conn;
156     }
157
158     /* ----------
159      * Check that we have all connection parameters
160      * ----------
161      */
162     for(option = PQconninfoOptions; option->keyword != NULL; option++) {
163         if(option->val != NULL)  continue;      /* Value was in conninfo */
164
165         /* ----------
166          * No value was found for this option. Return an error.
167          * ----------
168          */
169         conn->status = CONNECTION_BAD;
170         sprintf(conn->errorMessage,
171            "ERROR: PQconnectdb(): Cannot determine a value for option '%s'.\n",
172            option->keyword);
173         strcat(conn->errorMessage,
174             "Option not specified in conninfo string");
175         if(option->environ) {
176             strcat(conn->errorMessage,
177                 ", environment variable ");
178             strcat(conn->errorMessage, option->environ);
179             strcat(conn->errorMessage, "\nnot set");
180         }
181         strcat(conn->errorMessage, " and no compiled in default value.\n");
182         conninfo_free();
183         return conn;
184     }
185
186     /* ----------
187      * Setup the conn structure
188      * ----------
189      */
190     conn->Pfout = NULL;
191     conn->Pfin = NULL;
192     conn->Pfdebug = NULL;
193     conn->port = NULL;
194     conn->notifyList = DLNewList();
195     conn->lobjfuncs = NULL;
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     conn->lobjfuncs = NULL;
304     
305     if (!pghost || pghost[0] == '\0') {
306       if (!(tmp = getenv("PGHOST"))) {
307         tmp = DefaultHost;
308       }
309       conn->pghost = strdup(tmp);
310     } else
311       conn->pghost = strdup(pghost);
312     
313     if (!pgport || pgport[0] == '\0') {
314       if (!(tmp = getenv("PGPORT"))) {
315         tmp = POSTPORT;
316       }
317       conn->pgport = strdup(tmp);
318     } else
319       conn->pgport = strdup(pgport);
320     
321     if (!pgtty || pgtty[0] == '\0') {
322       if (!(tmp = getenv("PGTTY"))) {
323         tmp = DefaultTty;
324       }
325       conn->pgtty = strdup(tmp);
326     } else
327       conn->pgtty = strdup(pgtty);
328     
329     if (!pgoptions || pgoptions[0] == '\0') {
330       if (!(tmp = getenv("PGOPTIONS"))) {
331         tmp = DefaultOption;
332       }
333       conn->pgoptions = strdup(tmp);
334     } else
335       conn->pgoptions = strdup(pgoptions);
336
337     if ((tmp = getenv("PGUSER"))) {
338       error = FALSE;
339       conn->pguser = strdup(tmp);
340     } else {
341       tmp = fe_getauthname(errorMessage);
342       if (tmp == 0) {
343         error = TRUE;
344         sprintf(conn->errorMessage,
345                 "FATAL: PQsetdb: Unable to determine a Postgres username!\n");
346       } else {
347         error = FALSE;
348         conn->pguser = tmp;
349       }
350     }
351
352     if (!error) {
353       if (((tmp = (char *)dbName) && (dbName[0] != '\0')) ||
354           ((tmp = getenv("PGDATABASE")))) {
355         conn->dbName = strdup(tmp);
356       } else conn->dbName = strdup(conn->pguser);
357     } else conn->dbName = NULL;
358
359     if (error) conn->status = CONNECTION_BAD;
360     else {
361       conn->status = connectDB(conn);  
362         /* Puts message in conn->errorMessage */
363       if (conn->status == CONNECTION_OK) {
364         PGresult *res;
365         /* Send a blank query to make sure everything works; 
366            in particular, that the database exists.
367            */
368         res = PQexec(conn," ");
369         if (res == NULL || res->resultStatus != PGRES_EMPTY_QUERY) {
370           /* PQexec has put error message in conn->errorMessage */
371           closePGconn(conn);
372         }
373         PQclear(res);
374       }
375     }
376   }        
377   return conn;
378 }
379
380     
381 /*
382  * connectDB -
383  * make a connection to the backend so it is ready to receive queries.  
384  * return CONNECTION_OK if successful, CONNECTION_BAD if not.
385  *
386  */
387 static ConnStatusType
388 connectDB(PGconn *conn)
389 {
390     struct hostent *hp;
391
392     StartupInfo startup;
393     PacketBuf   pacBuf;
394     int         status;
395     MsgType     msgtype;
396     int         laddrlen = sizeof(struct sockaddr);
397     Port        *port = conn->port;
398     int         portno;
399
400     /*
401     //
402     // Initialize the startup packet. 
403     //
404     // This data structure is used for the seq-packet protocol.  It
405     // describes the frontend-backend connection.
406     //
407     //
408     */
409     strncpy(startup.user,conn->pguser,sizeof(startup.user));
410     strncpy(startup.database,conn->dbName,sizeof(startup.database));
411     strncpy(startup.tty,conn->pgtty,sizeof(startup.tty));
412     if (conn->pgoptions) {
413         strncpy(startup.options,conn->pgoptions, sizeof(startup.options));
414     }
415     else
416         startup.options[0]='\0'; 
417     startup.execFile[0]='\0';  /* not used */
418
419     /*
420     //
421     // Open a connection to postmaster/backend.
422     //
423     */
424     port = (Port *) malloc(sizeof(Port));
425     memset((char *) port, 0, sizeof(Port));
426
427     if (!(hp = gethostbyname(conn->pghost)) || hp->h_addrtype != AF_INET) {
428         (void) sprintf(conn->errorMessage,
429                        "connectDB() --  unknown hostname: %s\n",
430                        conn->pghost);
431         goto connect_errReturn;
432     }
433     memset((char *) &port->raddr, 0, sizeof(port->raddr));
434     memmove((char *) &(port->raddr.sin_addr),
435             (char *) hp->h_addr, 
436             hp->h_length);
437     port->raddr.sin_family = AF_INET;
438     portno = atoi(conn->pgport);
439     port->raddr.sin_port = htons((unsigned short)(portno));
440     
441     /* connect to the server  */
442     if ((port->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
443         (void) sprintf(conn->errorMessage,
444                "connectDB() -- socket() failed: errno=%d\n%s\n",
445                errno, strerror(errno));
446         goto connect_errReturn; 
447     }
448     if (connect(port->sock, (struct sockaddr *)&port->raddr,
449                 sizeof(port->raddr)) < 0) {
450         (void) sprintf(conn->errorMessage,
451                        "connectDB() failed: Is the postmaster running at '%s' on port '%s'?\n",
452                        conn->pghost,conn->pgport);
453         goto connect_errReturn; 
454     }
455     
456
457     /* fill in the client address */
458     if (getsockname(port->sock, (struct sockaddr *) &port->laddr,
459                     &laddrlen) < 0) {
460         (void) sprintf(conn->errorMessage,
461                "connectDB() -- getsockname() failed: errno=%d\n%s\n",
462                errno, strerror(errno));
463         goto connect_errReturn; 
464     }
465     
466     /* by this point, connection has been opened */
467     msgtype = fe_getauthsvc(conn->errorMessage);
468
469 /*    pacBuf = startup2PacketBuf(&startup);*/
470     startup2PacketBuf(&startup, &pacBuf);
471     pacBuf.msgtype = (MsgType) htonl(msgtype);
472     status = packetSend(port, &pacBuf, sizeof(PacketBuf), BLOCKING);
473     
474     if (status == STATUS_ERROR)
475         {
476         sprintf(conn->errorMessage,
477                "connectDB() --  couldn't send complete packet: errno=%d\n%s\n", errno,strerror(errno));
478         goto connect_errReturn;
479         }
480
481     /* authenticate as required*/
482     if (fe_sendauth(msgtype, port, conn->pghost, 
483                     conn->errorMessage) != STATUS_OK) {
484       (void) sprintf(conn->errorMessage,
485              "connectDB() --  authentication failed with %s\n",
486                conn->pghost);
487       goto connect_errReturn;   
488     }
489     
490     /* set up the socket file descriptors */
491     conn->Pfout = fdopen(port->sock, "w");
492     conn->Pfin = fdopen(dup(port->sock), "r");
493     if (!conn->Pfout || !conn->Pfin) {
494         (void) sprintf(conn->errorMessage,
495                "connectDB() -- fdopen() failed: errno=%d\n%s\n",
496                errno, strerror(errno));
497       goto connect_errReturn;   
498     }
499     
500     conn->port = port;
501
502     return CONNECTION_OK;
503
504 connect_errReturn:
505     return CONNECTION_BAD;
506
507 }
508
509 /*
510  * freePGconn
511  *   - free the PGconn data structure 
512  *
513  */
514 static void 
515 freePGconn(PGconn *conn)
516 {
517   if (conn->pghost) free(conn->pghost);
518   if (conn->pgtty) free(conn->pgtty);
519   if (conn->pgoptions) free(conn->pgoptions);
520   if (conn->pgport) free(conn->pgport);
521   if (conn->dbName) free(conn->dbName);
522   if (conn->pguser) free(conn->pguser);
523   if (conn->notifyList) DLFreeList(conn->notifyList);
524   if (conn->lobjfuncs) free(conn->lobjfuncs);
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 }