]> granicus.if.org Git - postgresql/blob - src/interfaces/libpq/fe-connect.c
From: Phil Thompson <phil@river-bank.demon.co.uk>
[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.59 1998/01/26 01:42:28 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 <sys/un.h>
25 #include <netinet/in.h>
26 #include <netinet/tcp.h>
27 #include <errno.h>
28 #include <signal.h>
29 #include <ctype.h>                              /* for isspace() */
30
31 #include "postgres.h"
32 #include "fe-auth.h"
33 #include "fe-connect.h"
34 #include "libpq-fe.h"
35
36 #ifndef HAVE_STRDUP
37 #include "strdup.h"
38 #endif
39 #ifdef HAVE_CRYPT_H
40 #include <crypt.h>
41 #endif
42
43
44 /* use a local version instead of the one found in pqpacket.c */
45 static ConnStatusType connectDB(PGconn *conn);
46
47 static void freePGconn(PGconn *conn);
48 static void closePGconn(PGconn *conn);
49 static int      conninfo_parse(const char *conninfo, char *errorMessage);
50 static char *conninfo_getval(char *keyword);
51 static void conninfo_free(void);
52 void PQsetenv(PGconn *conn);
53
54 #define NOTIFYLIST_INITIAL_SIZE 10
55 #define NOTIFYLIST_GROWBY 10
56
57
58 /* ----------
59  * Definition of the conninfo parameters and their fallback resources.
60  * If Environment-Var and Compiled-in are specified as NULL, no
61  * fallback is available. If after all no value can be determined
62  * for an option, an error is returned.
63  *
64  * The values for dbname and user are treated special in conninfo_parse.
65  * If the Compiled-in resource is specified as a NULL value, the
66  * user is determined by fe_getauthname() and for dbname the user
67  * name is copied.
68  *
69  * The Label and Disp-Char entries are provided for applications that
70  * want to use PQconndefaults() to create a generic database connection
71  * dialog. Disp-Char is defined as follows:
72  *         ""           Normal input field
73  * ----------
74  */
75 static PQconninfoOption PQconninfoOptions[] = {
76 /* ----------------------------------------------------------------- */
77 /*        Option-name           Environment-Var Compiled-in             Current value   */
78 /*                                              Label                                                   Disp-Char               */
79 /* ----------------- --------------- --------------- --------------- */
80         /* "authtype" is ignored as it is no longer used. */
81         {"authtype", "PGAUTHTYPE", DefaultAuthtype, NULL,
82         "Database-Authtype", "", 20},
83
84         {"user", "PGUSER", NULL, NULL,
85         "Database-User", "", 20},
86
87         {"password", "PGPASSWORD", DefaultPassword, NULL,
88         "Database-Password", "", 20},
89
90         {"dbname", "PGDATABASE", NULL, NULL,
91         "Database-Name", "", 20},
92
93         {"host", "PGHOST", NULL, NULL,
94         "Database-Host", "", 40},
95
96         {"port", "PGPORT", DEF_PGPORT, 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 struct EnvironmentOptions
110 {
111         const char *envName,
112                            *pgName;
113 }                       EnvironmentOptions[] =
114
115 {
116         /* common user-interface settings */
117         {       "PGDATESTYLE",  "datestyle" },
118         {       "PGTZ",                 "timezone" },
119
120         /* internal performance-related settings */
121         {       "PGCOSTHEAP",   "cost_heap" },
122         {       "PGCOSTINDEX",  "cost_index" },
123         {       "PGRPLANS",             "r_plans" },
124         {       "PGGEQO",               "geqo" },
125         {       NULL }
126 };
127
128 /* ----------------
129  *              PQconnectdb
130  *
131  * establishes a connection to a postgres backend through the postmaster
132  * using connection information in a string.
133  *
134  * The conninfo string is a list of
135  *
136  *         option = value
137  *
138  * definitions. Value might be a single value containing no whitespaces
139  * or a single quoted string. If a single quote should appear everywhere
140  * in the value, it must be escaped with a backslash like \'
141  *
142  * Returns a PGconn* which is needed for all subsequent libpq calls
143  * if the status field of the connection returned is CONNECTION_BAD,
144  * then some fields may be null'ed out instead of having valid values
145  * ----------------
146  */
147 PGconn *
148 PQconnectdb(const char *conninfo)
149 {
150         PGconn     *conn;
151         char            errorMessage[ERROR_MSG_LENGTH];
152         char* tmp;
153         /* ----------
154          * Allocate memory for the conn structure
155          * ----------
156          */
157         conn = (PGconn *) malloc(sizeof(PGconn));
158         if (conn == NULL)
159         {
160                 fprintf(stderr,
161                    "FATAL: PQsetdb() -- unable to allocate memory for a PGconn");
162                 return (PGconn *) NULL;
163         }
164         MemSet((char *) conn, 0, sizeof(PGconn));
165
166         /* ----------
167          * Parse the conninfo string and get the fallback resources
168          * ----------
169          */
170         if (conninfo_parse(conninfo, errorMessage) < 0)
171         {
172                 conn->status = CONNECTION_BAD;
173                 strcpy(conn->errorMessage, errorMessage);
174                 conninfo_free();
175                 return conn;
176         }
177
178         /* ----------
179          * Setup the conn structure
180          * ----------
181          */
182         conn->lobjfuncs = (PGlobjfuncs *) NULL;
183         conn->Pfout = NULL;
184         conn->Pfin = NULL;
185         conn->Pfdebug = NULL;
186         conn->notifyList = DLNewList();
187
188         tmp = conninfo_getval("host");
189         conn->pghost = tmp ? strdup(tmp) : NULL;
190         tmp = conninfo_getval("port");
191         conn->pgport = tmp ? strdup(tmp) : NULL;
192         tmp = conninfo_getval("tty");
193         conn->pgtty  = tmp ? strdup(tmp) : NULL;
194         tmp = conninfo_getval("options");
195         conn->pgoptions = tmp ? strdup(tmp) : NULL;
196         tmp = conninfo_getval("user");
197         conn->pguser = tmp ? strdup(tmp) : NULL;
198         tmp = conninfo_getval("password");
199         conn->pgpass = tmp ? strdup(tmp) : NULL;
200         tmp = conninfo_getval("dbname");
201         conn->dbName = tmp ? strdup(tmp) : NULL;
202
203         /* ----------
204          * Free the connection info - all is in conn now
205          * ----------
206          */
207         conninfo_free();
208
209         /* ----------
210          * Connect to the database
211          * ----------
212          */
213         conn->status = connectDB(conn);
214         if (conn->status == CONNECTION_OK)
215         {
216                 PGresult   *res;
217
218                 /*
219                  * Send a blank query to make sure everything works; in
220                  * particular, that the database exists.
221                  */
222                 res = PQexec(conn, " ");
223                 if (res == NULL || res->resultStatus != PGRES_EMPTY_QUERY)
224                 {
225                         /* PQexec has put error message in conn->errorMessage */
226                         closePGconn(conn);
227                 }
228                 PQclear(res);
229         }
230
231         PQsetenv(conn);
232
233         return conn;
234 }
235
236 /* ----------------
237  *              PQconndefaults
238  *
239  * Parse an empty string like PQconnectdb() would do and return the
240  * address of the connection options structure. Using this function
241  * an application might determine all possible options and their
242  * current default values.
243  * ----------------
244  */
245 PQconninfoOption *
246 PQconndefaults(void)
247 {
248         char            errorMessage[ERROR_MSG_LENGTH];
249
250         conninfo_parse("", errorMessage);
251         return PQconninfoOptions;
252 }
253
254 /* ----------------
255  *              PQsetdbLogin
256  *
257  * establishes a connection to a postgres backend through the postmaster
258  * at the specified host and port.
259  *
260  * returns a PGconn* which is needed for all subsequent libpq calls
261  * if the status field of the connection returned is CONNECTION_BAD,
262  * then some fields may be null'ed out instead of having valid values
263  *
264  *      Uses these environment variables:
265  *
266  *        PGHOST           identifies host to which to connect if <pghost> argument
267  *                                 is NULL or a null string.
268  *
269  *        PGPORT           identifies TCP port to which to connect if <pgport> argument
270  *                                 is NULL or a null string.
271  *
272  *        PGTTY            identifies tty to which to send messages if <pgtty> argument
273  *                                 is NULL or a null string.
274  *
275  *        PGOPTIONS    identifies connection options if <pgoptions> argument is
276  *                                 NULL or a null string.
277  *
278  *        PGUSER           Postgres username to associate with the connection.
279  *
280  *        PGPASSWORD   The user's password.
281  *
282  *        PGDATABASE   name of database to which to connect if <pgdatabase>
283  *                                 argument is NULL or a null string
284  *
285  *        None of the above need be defined.  There are defaults for all of them.
286  *
287  * To support "delimited identifiers" for database names, only convert
288  * the database name to lower case if it is not surrounded by double quotes.
289  * Otherwise, strip the double quotes but leave the reset of the string intact.
290  * - thomas 1997-11-08
291  *
292  * ----------------
293  */
294 PGconn     *
295 PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, const char *pgtty, const char *dbName, const char *login, const char *pwd)
296 {
297         PGconn     *conn;
298         char       *tmp;
299         char            errorMessage[ERROR_MSG_LENGTH];
300
301         /* An error message from some service we call. */
302         bool            error;
303
304         /* We encountered an error that prevents successful completion */
305         int                     i;
306
307         conn = (PGconn *) malloc(sizeof(PGconn));
308
309         if (conn == NULL)
310                 fprintf(stderr,
311                    "FATAL: PQsetdb() -- unable to allocate memory for a PGconn");
312         else
313         {
314                 conn->lobjfuncs = (PGlobjfuncs *) NULL;
315                 conn->Pfout = NULL;
316                 conn->Pfin = NULL;
317                 conn->Pfdebug = NULL;
318                 conn->notifyList = DLNewList();
319
320                 if ((pghost == NULL) || pghost[0] == '\0')
321                 {
322                         conn->pghost = NULL;
323                         if ((tmp = getenv("PGHOST")) != NULL)
324                                 conn->pghost = strdup(tmp);
325                 }
326                 else
327                         conn->pghost = strdup(pghost);
328
329                 if ((pgport == NULL) || pgport[0] == '\0')
330                 {
331                         if ((tmp = getenv("PGPORT")) == NULL)
332                                 tmp = DEF_PGPORT;
333                         conn->pgport = strdup(tmp);
334                 }
335                 else
336                         conn->pgport = strdup(pgport);
337
338                 if ((pgtty == NULL) || pgtty[0] == '\0')
339                 {
340                         if ((tmp = getenv("PGTTY")) == NULL)
341                                 tmp = DefaultTty;
342                         conn->pgtty = strdup(tmp);
343                 }
344                 else
345                         conn->pgtty = strdup(pgtty);
346
347                 if ((pgoptions == NULL) || pgoptions[0] == '\0')
348                 {
349                         if ((tmp = getenv("PGOPTIONS")) == NULL)
350                                 tmp = DefaultOption;
351                         conn->pgoptions = strdup(tmp);
352                 }
353                 else
354                         conn->pgoptions = strdup(pgoptions);
355
356                 if (login)
357                 {
358                         error = FALSE;
359                         conn->pguser = strdup(login);
360                 }
361                 else if ((tmp = getenv("PGUSER")) != NULL)
362                 {
363                         error = FALSE;
364                         conn->pguser = strdup(tmp);
365                 }
366                 else
367                 {
368                         tmp = fe_getauthname(errorMessage);
369                         if (tmp == 0)
370                         {
371                                 error = TRUE;
372                                 sprintf(conn->errorMessage,
373                                                 "FATAL: PQsetdb: Unable to determine a Postgres username!\n");
374                         }
375                         else
376                         {
377                                 error = FALSE;
378                                 conn->pguser = tmp;
379                         }
380                 }
381
382                 if (pwd)
383                 {
384                         conn->pgpass = strdup(pwd);
385                 }
386                 else if ((tmp = getenv("PGPASSWORD")) != NULL)
387                 {
388                         conn->pgpass = strdup(tmp);
389                 }
390                 else
391                         conn->pgpass = strdup(DefaultPassword);
392
393                 if (!error)
394                 {
395                         if ((((tmp = (char *) dbName) != NULL) && (dbName[0] != '\0'))
396                                 || ((tmp = getenv("PGDATABASE"))))
397                                 conn->dbName = strdup(tmp);
398                         else
399                                 conn->dbName = strdup(conn->pguser);
400
401                         /*
402                          * if the database name is surrounded by double-quotes,
403                          *  then don't convert case
404                          */
405                         if (*conn->dbName == '"')
406                         {
407                                 strcpy(conn->dbName, conn->dbName + 1);
408                                 *(conn->dbName + strlen(conn->dbName) - 1) = '\0';
409                         }
410                         else
411                                 for (i = 0; conn->dbName[i]; i++)
412                                         if (isupper(conn->dbName[i]))
413                                                 conn->dbName[i] = tolower(conn->dbName[i]);
414                 }
415                 else
416                         conn->dbName = NULL;
417
418                 if (error)
419                         conn->status = CONNECTION_BAD;
420                 else
421                 {
422                         conn->status = connectDB(conn);
423                         /* Puts message in conn->errorMessage */
424                         if (conn->status == CONNECTION_OK)
425                         {
426                                 PGresult   *res;
427
428                                 /*
429                                  * Send a blank query to make sure everything works; in
430                                  * particular, that the database exists.
431                                  */
432                                 res = PQexec(conn, " ");
433                                 if (res == NULL || res->resultStatus != PGRES_EMPTY_QUERY)
434                                 {
435                                         /* PQexec has put error message in conn->errorMessage */
436                                         closePGconn(conn);
437                                 }
438                                 PQclear(res);
439                         }
440                         PQsetenv(conn);
441                 }
442         }
443         return conn;
444 }
445
446
447 /*
448  * connectDB -
449  * make a connection to the backend so it is ready to receive queries.
450  * return CONNECTION_OK if successful, CONNECTION_BAD if not.
451  *
452  */
453 static ConnStatusType
454 connectDB(PGconn *conn)
455 {
456         struct hostent *hp;
457
458         StartupPacket   sp;
459         AuthRequest     areq;
460         int                     laddrlen = sizeof(SockAddr);
461         int                     portno,
462                                 family,
463                                 len;
464
465         /*
466          * Initialize the startup packet.
467          */
468
469         MemSet((char *)&sp, 0, sizeof (StartupPacket));
470
471         sp.protoVersion = (ProtocolVersion)htonl(PG_PROTOCOL_LATEST);
472
473         strncpy(sp.user, conn->pguser, SM_USER);
474         strncpy(sp.database, conn->dbName, SM_DATABASE);
475         strncpy(sp.tty, conn->pgtty, SM_TTY);
476
477         if (conn->pgoptions)
478                 strncpy(sp.options, conn->pgoptions, SM_OPTIONS);
479
480         /*
481          * Open a connection to postmaster/backend.
482          */
483
484         if (conn->pghost != NULL)
485         {
486                 hp = gethostbyname(conn->pghost);
487                 if ((hp == NULL) || (hp->h_addrtype != AF_INET))
488                 {
489                         (void) sprintf(conn->errorMessage,
490                                                    "connectDB() --  unknown hostname: %s\n",
491                                                    conn->pghost);
492                         goto connect_errReturn;
493                 }
494         } else
495                 hp = NULL;
496
497 #if FALSE
498         MemSet((char *) &port->raddr, 0, sizeof(port->raddr));
499 #endif
500         portno = atoi(conn->pgport);
501         family = (conn->pghost != NULL) ? AF_INET : AF_UNIX;
502         conn->raddr.sa.sa_family = family;
503         if (family == AF_INET)
504         {
505                 memmove((char *) &(conn->raddr.in.sin_addr),
506                                 (char *) hp->h_addr,
507                                 hp->h_length);
508                 conn->raddr.in.sin_port = htons((unsigned short) (portno));
509                 len = sizeof(struct sockaddr_in);
510         }
511         else
512         {
513                 len = UNIXSOCK_PATH(conn->raddr.un, portno);
514         }
515         /* connect to the server  */
516         if ((conn->sock = socket(family, SOCK_STREAM, 0)) < 0)
517         {
518                 (void) sprintf(conn->errorMessage,
519                                            "connectDB() -- socket() failed: errno=%d\n%s\n",
520                                            errno, strerror(errno));
521                 goto connect_errReturn;
522         }
523         if (connect(conn->sock, &conn->raddr.sa, len) < 0)
524         {
525                 (void) sprintf(conn->errorMessage,
526                                            "connectDB() failed: Is the postmaster running and accepting%s connections at '%s' on port '%s'?\n",
527                                            conn->pghost ? " TCP/IP(with -i)" : "",
528                                            conn->pghost ? conn->pghost : "UNIX Socket",
529                                            conn->pgport);
530                 goto connect_errReturn;
531         }
532         if (family == AF_INET)
533         {
534                 struct protoent *pe;
535                 int                     on = 1;
536
537                 pe = getprotobyname("TCP");
538                 if (pe == NULL)
539                 {
540                         (void) sprintf(conn->errorMessage,
541                                                    "connectDB(): getprotobyname failed\n");
542                         goto connect_errReturn;
543                 }
544                 if (setsockopt(conn->sock, pe->p_proto, TCP_NODELAY,
545                                            &on, sizeof(on)) < 0)
546                 {
547                         (void) sprintf(conn->errorMessage,
548                                                    "connectDB(): setsockopt failed\n");
549                         goto connect_errReturn;
550                 }
551         }
552
553         /* fill in the client address */
554         if (getsockname(conn->sock, &conn->laddr.sa, &laddrlen) < 0)
555         {
556                 (void) sprintf(conn->errorMessage,
557                                    "connectDB() -- getsockname() failed: errno=%d\n%s\n",
558                                            errno, strerror(errno));
559                 goto connect_errReturn;
560         }
561
562         /* set up the socket file descriptors */
563         conn->Pfout = fdopen(conn->sock, "w");
564         conn->Pfin = fdopen(dup(conn->sock), "r");
565         if ((conn->Pfout == NULL) || (conn->Pfin == NULL))
566         {
567                 (void) sprintf(conn->errorMessage,
568                                            "connectDB() -- fdopen() failed: errno=%d\n%s\n",
569                                            errno, strerror(errno));
570                 goto connect_errReturn;
571         }
572
573         /* Send the startup packet. */
574
575         if (packetSend(conn, (char *)&sp, sizeof(StartupPacket)) != STATUS_OK)
576         {
577                 sprintf(conn->errorMessage,
578                                 "connectDB() --  couldn't send complete packet: errno=%d\n%s\n", errno, strerror(errno));
579                 goto connect_errReturn;
580         }
581
582         /*
583          * Get the response from the backend, either an error message or an
584          * authentication request.
585          */
586
587         do
588         {
589                 int beresp;
590
591                 if ((beresp = pqGetc(conn->Pfin, conn->Pfdebug)) == EOF)
592                 {
593                         (void)sprintf(conn->errorMessage,
594                                         "connectDB() -- error getting authentication request\n");
595
596                         goto connect_errReturn;
597                 }
598
599                 /* Handle errors. */
600
601                 if (beresp == 'E')
602                 {
603                         pqGets(conn->errorMessage, sizeof (conn->errorMessage),
604                                 conn->Pfin, conn->Pfdebug);
605
606                         goto connect_errReturn;
607                 }
608
609                 /* Check it was an authentication request. */
610
611                 if (beresp != 'R')
612                 {
613                         (void)sprintf(conn->errorMessage,
614                                         "connectDB() -- expected authentication request\n");
615
616                         goto connect_errReturn;
617                 }
618
619                 /* Get the type of request. */
620
621                 if (pqGetInt((int *)&areq, 4, conn->Pfin, conn->Pfdebug))
622                 {
623                         (void)sprintf(conn->errorMessage,
624                                         "connectDB() -- error getting authentication request type\n");
625
626                         goto connect_errReturn;
627                 }
628
629                 /* Get the password salt if there is one. */
630
631                 if (areq == AUTH_REQ_CRYPT &&
632                         pqGetnchar(conn->salt, sizeof (conn->salt),
633                                         conn->Pfin, conn->Pfdebug))
634                 {
635                         (void)sprintf(conn->errorMessage,
636                                         "connectDB() -- error getting password salt\n");
637
638                         goto connect_errReturn;
639                 }
640
641
642                 /* Respond to the request. */
643
644                 if (fe_sendauth(areq, conn, conn->pghost, conn->pgpass,
645                                         conn->errorMessage) != STATUS_OK)
646                         goto connect_errReturn;
647         }
648         while (areq != AUTH_REQ_OK);
649
650         /* free the password so it's not hanging out in memory forever */
651         if (conn->pgpass != NULL)
652         {
653                 free(conn->pgpass);
654         }
655
656         return CONNECTION_OK;
657
658 connect_errReturn:
659         return CONNECTION_BAD;
660
661 }
662
663 void
664 PQsetenv(PGconn *conn)
665 {
666         struct EnvironmentOptions *eo;
667         char setQuery[80];              /* mjl: size okay? XXX */
668
669         for (eo = EnvironmentOptions; eo->envName; eo++)
670         {
671                 const char *val;
672
673                 if ((val = getenv(eo->envName)))
674                 {
675                         PGresult   *res;
676
677                         if (strcasecmp(val, "default") == 0)
678                                 sprintf(setQuery, "SET %s = %.60s", eo->pgName, val);
679                         else
680                                 sprintf(setQuery, "SET %s = '%.60s'", eo->pgName, val);
681 #ifdef CONNECTDEBUG
682 printf("Use environment variable %s to send %s\n", eo->envName, setQuery);
683 #endif
684                         res = PQexec(conn, setQuery);
685                         PQclear(res);   /* Don't care? */
686                 }
687         }
688 } /* PQsetenv() */
689
690 /*
691  * freePGconn
692  *       - free the PGconn data structure
693  *
694  */
695 static void
696 freePGconn(PGconn *conn)
697 {
698         if (!conn)
699                 return;
700         if (conn->pghost)
701                 free(conn->pghost);
702         if (conn->pgtty)
703                 free(conn->pgtty);
704         if (conn->pgoptions)
705                 free(conn->pgoptions);
706         if (conn->pgport)
707                 free(conn->pgport);
708         if (conn->dbName)
709                 free(conn->dbName);
710         if (conn->pguser)
711                 free(conn->pguser);
712         if (conn->notifyList)
713                 DLFreeList(conn->notifyList);
714         free(conn);
715 }
716
717 /*
718    closePGconn
719          - properly close a connection to the backend
720 */
721 static void
722 closePGconn(PGconn *conn)
723 {
724 /* GH: What to do for !USE_POSIX_SIGNALS ? */
725 #if defined(USE_POSIX_SIGNALS)
726         struct sigaction ignore_action;
727
728         /*
729          * This is used as a constant, but not declared as such because the
730          * sigaction structure is defined differently on different systems
731          */
732         struct sigaction oldaction;
733
734         /*
735          * If connection is already gone, that's cool.  No reason for kernel
736          * to kill us when we try to write to it.  So ignore SIGPIPE signals.
737          */
738         ignore_action.sa_handler = SIG_IGN;
739         sigemptyset(&ignore_action.sa_mask);
740         ignore_action.sa_flags = 0;
741         sigaction(SIGPIPE, (struct sigaction *) & ignore_action, &oldaction);
742
743         fputs("X\0", conn->Pfout);
744         fflush(conn->Pfout);
745         sigaction(SIGPIPE, &oldaction, NULL);
746 #else
747                                 signal(SIGPIPE, SIG_IGN);
748         fputs("X\0", conn->Pfout);
749         fflush(conn->Pfout);
750         signal(SIGPIPE, SIG_DFL);
751 #endif
752         if (conn->Pfout)
753                 fclose(conn->Pfout);
754         if (conn->Pfin)
755                 fclose(conn->Pfin);
756         if (conn->Pfdebug)
757                 fclose(conn->Pfdebug);
758         conn->status = CONNECTION_BAD;          /* Well, not really _bad_ - just
759                                                                                  * absent */
760 }
761
762 /*
763    PQfinish:
764           properly close a connection to the backend
765           also frees the PGconn data structure so it shouldn't be re-used
766           after this
767 */
768 void
769 PQfinish(PGconn *conn)
770 {
771         if (!conn)
772         {
773                 fprintf(stderr, "PQfinish() -- pointer to PGconn is null\n");
774         }
775         else
776         {
777                 if (conn->status == CONNECTION_OK)
778                         closePGconn(conn);
779                 freePGconn(conn);
780         }
781 }
782
783 /* PQreset :
784    resets the connection to the backend
785    closes the existing connection and makes a new one
786 */
787 void
788 PQreset(PGconn *conn)
789 {
790         if (!conn)
791         {
792                 fprintf(stderr, "PQreset() -- pointer to PGconn is null\n");
793         }
794         else
795         {
796                 closePGconn(conn);
797                 conn->status = connectDB(conn);
798         }
799 }
800
801 /*
802  * PacketSend()
803  *
804  this is just like PacketSend(), defined in backend/libpq/pqpacket.c
805  but we define it here to avoid linking in all of libpq.a
806
807  * packetSend -- send a single-packet message.
808  *
809  * RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise.
810  * SIDE_EFFECTS: may block.
811 */
812 int
813 packetSend(PGconn *conn,
814                    char *buf,
815                    size_t len)
816 {
817         /* Send the total packet size. */
818
819         if (pqPutInt(4 + len, 4, conn->Pfout, conn->Pfdebug))
820                 return STATUS_ERROR;
821
822         /* Send the packet itself. */
823
824         if (pqPutnchar(buf, len, conn->Pfout, conn->Pfdebug))
825                 return STATUS_ERROR;
826
827         pqFlush(conn->Pfout, conn->Pfdebug);
828
829         return STATUS_OK;
830 }
831
832
833 /* ----------------
834  * Conninfo parser routine
835  * ----------------
836  */
837 static int
838 conninfo_parse(const char *conninfo, char *errorMessage)
839 {
840         char       *pname;
841         char       *pval;
842         char       *buf;
843         char       *tmp;
844         char       *cp;
845         char       *cp2;
846         PQconninfoOption *option;
847         char            errortmp[ERROR_MSG_LENGTH];
848
849         conninfo_free();
850
851         if ((buf = strdup(conninfo)) == NULL)
852         {
853                 strcpy(errorMessage,
854                   "FATAL: cannot allocate memory for copy of conninfo string\n");
855                 return -1;
856         }
857         cp = buf;
858
859         while (*cp)
860         {
861                 /* Skip blanks before the parameter name */
862                 if (isspace(*cp))
863                 {
864                         cp++;
865                         continue;
866                 }
867
868                 /* Get the parameter name */
869                 pname = cp;
870                 while (*cp)
871                 {
872                         if (*cp == '=')
873                         {
874                                 break;
875                         }
876                         if (isspace(*cp))
877                         {
878                                 *cp++ = '\0';
879                                 while (*cp)
880                                 {
881                                         if (!isspace(*cp))
882                                         {
883                                                 break;
884                                         }
885                                         cp++;
886                                 }
887                                 break;
888                         }
889                         cp++;
890                 }
891
892                 /* Check that there is a following '=' */
893                 if (*cp != '=')
894                 {
895                         sprintf(errorMessage,
896                         "ERROR: PQconnectdb() - Missing '=' after '%s' in conninfo\n",
897                                         pname);
898                         free(buf);
899                         return -1;
900                 }
901                 *cp++ = '\0';
902
903                 /* Skip blanks after the '=' */
904                 while (*cp)
905                 {
906                         if (!isspace(*cp))
907                         {
908                                 break;
909                         }
910                         cp++;
911                 }
912
913                 pval = cp;
914
915                 if (*cp != '\'')
916                 {
917                         cp2 = pval;
918                         while (*cp)
919                         {
920                                 if (isspace(*cp))
921                                 {
922                                         *cp++ = '\0';
923                                         break;
924                                 }
925                                 if (*cp == '\\')
926                                 {
927                                         cp++;
928                                         if (*cp != '\0')
929                                         {
930                                                 *cp2++ = *cp++;
931                                         }
932                                 }
933                                 else
934                                 {
935                                         *cp2++ = *cp++;
936                                 }
937                         }
938                         *cp2 = '\0';
939                 }
940                 else
941                 {
942                         cp2 = pval;
943                         cp++;
944                         for (;;)
945                         {
946                                 if (*cp == '\0')
947                                 {
948                                         sprintf(errorMessage,
949                                                         "ERROR: PQconnectdb() - unterminated quoted string in conninfo\n");
950                                         free(buf);
951                                         return -1;
952                                 }
953                                 if (*cp == '\\')
954                                 {
955                                         cp++;
956                                         if (*cp != '\0')
957                                         {
958                                                 *cp2++ = *cp++;
959                                         }
960                                         continue;
961                                 }
962                                 if (*cp == '\'')
963                                 {
964                                         *cp2 = '\0';
965                                         cp++;
966                                         break;
967                                 }
968                                 *cp2++ = *cp++;
969                         }
970                 }
971
972                 /* ----------
973                  * Now we have the name and the value. Search
974                  * for the param record.
975                  * ----------
976                  */
977                 for (option = PQconninfoOptions; option->keyword != NULL; option++)
978                 {
979                         if (!strcmp(option->keyword, pname))
980                         {
981                                 break;
982                         }
983                 }
984                 if (option->keyword == NULL)
985                 {
986                         sprintf(errorMessage,
987                                         "ERROR: PQconnectdb() - unknown option '%s'\n",
988                                         pname);
989                         free(buf);
990                         return -1;
991                 }
992
993                 /* ----------
994                  * Store the value
995                  * ----------
996                  */
997                 option->val = strdup(pval);
998         }
999
1000         free(buf);
1001
1002         /* ----------
1003          * Get the fallback resources for parameters not specified
1004          * in the conninfo string.
1005          * ----------
1006          */
1007         for (option = PQconninfoOptions; option->keyword != NULL; option++)
1008         {
1009                 if (option->val != NULL)
1010                         continue;                       /* Value was in conninfo */
1011
1012                 /* ----------
1013                  * Try to get the environment variable fallback
1014                  * ----------
1015                  */
1016                 if (option->environ != NULL)
1017                 {
1018                         if ((tmp = getenv(option->environ)) != NULL)
1019                         {
1020                                 option->val = strdup(tmp);
1021                                 continue;
1022                         }
1023                 }
1024
1025                 /* ----------
1026                  * No environment variable specified or this one isn't set -
1027                  * try compiled in
1028                  * ----------
1029                  */
1030                 if (option->compiled != NULL)
1031                 {
1032                         option->val = strdup(option->compiled);
1033                         continue;
1034                 }
1035
1036                 /* ----------
1037                  * Special handling for user
1038                  * ----------
1039                  */
1040                 if (!strcmp(option->keyword, "user"))
1041                 {
1042                         tmp = fe_getauthname(errortmp);
1043                         if (tmp)
1044                         {
1045                                 option->val = strdup(tmp);
1046                         }
1047                 }
1048
1049                 /* ----------
1050                  * Special handling for dbname
1051                  * ----------
1052                  */
1053                 if (!strcmp(option->keyword, "dbname"))
1054                 {
1055                         tmp = conninfo_getval("user");
1056                         if (tmp)
1057                         {
1058                                 option->val = strdup(tmp);
1059                         }
1060                 }
1061         }
1062
1063         return 0;
1064 }
1065
1066
1067 static char *
1068 conninfo_getval(char *keyword)
1069 {
1070         PQconninfoOption *option;
1071
1072         for (option = PQconninfoOptions; option->keyword != NULL; option++)
1073         {
1074                 if (!strcmp(option->keyword, keyword))
1075                 {
1076                         return option->val;
1077                 }
1078         }
1079
1080         return NULL;
1081 }
1082
1083
1084 static void
1085 conninfo_free()
1086 {
1087         PQconninfoOption *option;
1088
1089         for (option = PQconninfoOptions; option->keyword != NULL; option++)
1090         {
1091                 if (option->val != NULL)
1092                 {
1093                         free(option->val);
1094                         option->val = NULL;
1095                 }
1096         }
1097 }
1098
1099 /* =========== accessor functions for PGconn ========= */
1100 char       *
1101 PQdb(PGconn *conn)
1102 {
1103         if (!conn)
1104         {
1105                 fprintf(stderr, "PQdb() -- pointer to PGconn is null\n");
1106                 return (char *) NULL;
1107         }
1108         return conn->dbName;
1109 }
1110
1111 char       *
1112 PQuser(PGconn *conn)
1113 {
1114         if (!conn)
1115         {
1116                 fprintf(stderr, "PQuser() -- pointer to PGconn is null\n");
1117                 return (char *) NULL;
1118         }
1119         return conn->pguser;
1120 }
1121
1122 char       *
1123 PQhost(PGconn *conn)
1124 {
1125         if (!conn)
1126         {
1127                 fprintf(stderr, "PQhost() -- pointer to PGconn is null\n");
1128                 return (char *) NULL;
1129         }
1130
1131         return conn->pghost;
1132 }
1133
1134 char       *
1135 PQoptions(PGconn *conn)
1136 {
1137         if (!conn)
1138         {
1139                 fprintf(stderr, "PQoptions() -- pointer to PGconn is null\n");
1140                 return (char *) NULL;
1141         }
1142         return conn->pgoptions;
1143 }
1144
1145 char       *
1146 PQtty(PGconn *conn)
1147 {
1148         if (!conn)
1149         {
1150                 fprintf(stderr, "PQtty() -- pointer to PGconn is null\n");
1151                 return (char *) NULL;
1152         }
1153         return conn->pgtty;
1154 }
1155
1156 char       *
1157 PQport(PGconn *conn)
1158 {
1159         if (!conn)
1160         {
1161                 fprintf(stderr, "PQport() -- pointer to PGconn is null\n");
1162                 return (char *) NULL;
1163         }
1164         return conn->pgport;
1165 }
1166
1167 ConnStatusType
1168 PQstatus(PGconn *conn)
1169 {
1170         if (!conn)
1171         {
1172                 fprintf(stderr, "PQstatus() -- pointer to PGconn is null\n");
1173                 return CONNECTION_BAD;
1174         }
1175         return conn->status;
1176 }
1177
1178 char       *
1179 PQerrorMessage(PGconn *conn)
1180 {
1181         if (!conn)
1182         {
1183                 fprintf(stderr, "PQerrorMessage() -- pointer to PGconn is null\n");
1184                 return (char *) NULL;
1185         }
1186         return conn->errorMessage;
1187 }
1188
1189 void
1190 PQtrace(PGconn *conn, FILE *debug_port)
1191 {
1192         if (conn == NULL ||
1193                 conn->status == CONNECTION_BAD)
1194         {
1195                 return;
1196         }
1197         PQuntrace(conn);
1198         conn->Pfdebug = debug_port;
1199 }
1200
1201 void
1202 PQuntrace(PGconn *conn)
1203 {
1204         if (conn == NULL ||
1205                 conn->status == CONNECTION_BAD)
1206         {
1207                 return;
1208         }
1209         if (conn->Pfdebug)
1210         {
1211                 fflush(conn->Pfdebug);
1212                 conn->Pfdebug = NULL;
1213         }
1214 }