LCOV - code coverage report
Current view: top level - src/fe_utils - connect_utils.c (source / functions) Hit Total Coverage
Test: PostgreSQL 15devel Lines: 43 62 69.4 %
Date: 2021-09-17 15:07:27 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * Facilities for frontend code to connect to and disconnect from databases.
       4             :  *
       5             :  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
       6             :  * Portions Copyright (c) 1994, Regents of the University of California
       7             :  *
       8             :  * src/fe_utils/connect_utils.c
       9             :  *
      10             :  *-------------------------------------------------------------------------
      11             :  */
      12             : #include "postgres_fe.h"
      13             : 
      14             : #include "common/connect.h"
      15             : #include "common/logging.h"
      16             : #include "common/string.h"
      17             : #include "fe_utils/connect_utils.h"
      18             : #include "fe_utils/query_utils.h"
      19             : 
      20             : /*
      21             :  * Make a database connection with the given parameters.
      22             :  *
      23             :  * An interactive password prompt is automatically issued if needed and
      24             :  * allowed by cparams->prompt_password.
      25             :  *
      26             :  * If allow_password_reuse is true, we will try to re-use any password
      27             :  * given during previous calls to this routine.  (Callers should not pass
      28             :  * allow_password_reuse=true unless reconnecting to the same database+user
      29             :  * as before, else we might create password exposure hazards.)
      30             :  */
      31             : PGconn *
      32         446 : connectDatabase(const ConnParams *cparams, const char *progname,
      33             :                 bool echo, bool fail_ok, bool allow_password_reuse)
      34             : {
      35             :     PGconn     *conn;
      36             :     bool        new_pass;
      37             :     static char *password = NULL;
      38             : 
      39             :     /* Callers must supply at least dbname; other params can be NULL */
      40             :     Assert(cparams->dbname);
      41             : 
      42         446 :     if (!allow_password_reuse && password)
      43             :     {
      44           0 :         free(password);
      45           0 :         password = NULL;
      46             :     }
      47             : 
      48         446 :     if (cparams->prompt_password == TRI_YES && password == NULL)
      49           0 :         password = simple_prompt("Password: ", false);
      50             : 
      51             :     /*
      52             :      * Start the connection.  Loop until we have a password if requested by
      53             :      * backend.
      54             :      */
      55             :     do
      56             :     {
      57             :         const char *keywords[8];
      58             :         const char *values[8];
      59         446 :         int         i = 0;
      60             : 
      61             :         /*
      62             :          * If dbname is a connstring, its entries can override the other
      63             :          * values obtained from cparams; but in turn, override_dbname can
      64             :          * override the dbname component of it.
      65             :          */
      66         446 :         keywords[i] = "host";
      67         446 :         values[i++] = cparams->pghost;
      68         446 :         keywords[i] = "port";
      69         446 :         values[i++] = cparams->pgport;
      70         446 :         keywords[i] = "user";
      71         446 :         values[i++] = cparams->pguser;
      72         446 :         keywords[i] = "password";
      73         446 :         values[i++] = password;
      74         446 :         keywords[i] = "dbname";
      75         446 :         values[i++] = cparams->dbname;
      76         446 :         if (cparams->override_dbname)
      77             :         {
      78         154 :             keywords[i] = "dbname";
      79         154 :             values[i++] = cparams->override_dbname;
      80             :         }
      81         446 :         keywords[i] = "fallback_application_name";
      82         446 :         values[i++] = progname;
      83         446 :         keywords[i] = NULL;
      84         446 :         values[i++] = NULL;
      85             :         Assert(i <= lengthof(keywords));
      86             : 
      87         446 :         new_pass = false;
      88         446 :         conn = PQconnectdbParams(keywords, values, true);
      89             : 
      90         446 :         if (!conn)
      91             :         {
      92           0 :             pg_log_error("could not connect to database %s: out of memory",
      93             :                          cparams->dbname);
      94           0 :             exit(1);
      95             :         }
      96             : 
      97             :         /*
      98             :          * No luck?  Trying asking (again) for a password.
      99             :          */
     100         450 :         if (PQstatus(conn) == CONNECTION_BAD &&
     101           4 :             PQconnectionNeedsPassword(conn) &&
     102           0 :             cparams->prompt_password != TRI_NO)
     103             :         {
     104           0 :             PQfinish(conn);
     105           0 :             if (password)
     106           0 :                 free(password);
     107           0 :             password = simple_prompt("Password: ", false);
     108           0 :             new_pass = true;
     109             :         }
     110         446 :     } while (new_pass);
     111             : 
     112             :     /* check to see that the backend connection was successfully made */
     113         446 :     if (PQstatus(conn) == CONNECTION_BAD)
     114             :     {
     115           4 :         if (fail_ok)
     116             :         {
     117           0 :             PQfinish(conn);
     118           0 :             return NULL;
     119             :         }
     120           4 :         pg_log_error("%s", PQerrorMessage(conn));
     121           4 :         exit(1);
     122             :     }
     123             : 
     124             :     /* Start strict; callers may override this. */
     125         442 :     PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL, echo));
     126             : 
     127         442 :     return conn;
     128             : }
     129             : 
     130             : /*
     131             :  * Try to connect to the appropriate maintenance database.
     132             :  *
     133             :  * This differs from connectDatabase only in that it has a rule for
     134             :  * inserting a default "dbname" if none was given (which is why cparams
     135             :  * is not const).  Note that cparams->dbname should typically come from
     136             :  * a --maintenance-db command line parameter.
     137             :  */
     138             : PGconn *
     139         130 : connectMaintenanceDatabase(ConnParams *cparams,
     140             :                            const char *progname, bool echo)
     141             : {
     142             :     PGconn     *conn;
     143             : 
     144             :     /* If a maintenance database name was specified, just connect to it. */
     145         130 :     if (cparams->dbname)
     146           0 :         return connectDatabase(cparams, progname, echo, false, false);
     147             : 
     148             :     /* Otherwise, try postgres first and then template1. */
     149         130 :     cparams->dbname = "postgres";
     150         130 :     conn = connectDatabase(cparams, progname, echo, true, false);
     151         130 :     if (!conn)
     152             :     {
     153           0 :         cparams->dbname = "template1";
     154           0 :         conn = connectDatabase(cparams, progname, echo, false, false);
     155             :     }
     156         130 :     return conn;
     157             : }
     158             : 
     159             : /*
     160             :  * Disconnect the given connection, canceling any statement if one is active.
     161             :  */
     162             : void
     163         314 : disconnectDatabase(PGconn *conn)
     164             : {
     165             :     char        errbuf[256];
     166             : 
     167             :     Assert(conn != NULL);
     168             : 
     169         314 :     if (PQtransactionStatus(conn) == PQTRANS_ACTIVE)
     170             :     {
     171             :         PGcancel   *cancel;
     172             : 
     173           0 :         if ((cancel = PQgetCancel(conn)))
     174             :         {
     175           0 :             (void) PQcancel(cancel, errbuf, sizeof(errbuf));
     176           0 :             PQfreeCancel(cancel);
     177             :         }
     178             :     }
     179             : 
     180         314 :     PQfinish(conn);
     181         314 : }

Generated by: LCOV version 1.13