LCOV - code coverage report
Current view: top level - src/fe_utils - connect_utils.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 42 59 71.2 %
Date: 2024-02-28 21:11:04 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-2024, 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 host+port+user
      29             :  * as before, else we might create password exposure hazards.)
      30             :  */
      31             : PGconn *
      32         582 : 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         582 :     if (!allow_password_reuse && password)
      43             :     {
      44           0 :         free(password);
      45           0 :         password = NULL;
      46             :     }
      47             : 
      48         582 :     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         582 :         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         582 :         keywords[i] = "host";
      67         582 :         values[i++] = cparams->pghost;
      68         582 :         keywords[i] = "port";
      69         582 :         values[i++] = cparams->pgport;
      70         582 :         keywords[i] = "user";
      71         582 :         values[i++] = cparams->pguser;
      72         582 :         keywords[i] = "password";
      73         582 :         values[i++] = password;
      74         582 :         keywords[i] = "dbname";
      75         582 :         values[i++] = cparams->dbname;
      76         582 :         if (cparams->override_dbname)
      77             :         {
      78         194 :             keywords[i] = "dbname";
      79         194 :             values[i++] = cparams->override_dbname;
      80             :         }
      81         582 :         keywords[i] = "fallback_application_name";
      82         582 :         values[i++] = progname;
      83         582 :         keywords[i] = NULL;
      84         582 :         values[i++] = NULL;
      85             :         Assert(i <= lengthof(keywords));
      86             : 
      87         582 :         new_pass = false;
      88         582 :         conn = PQconnectdbParams(keywords, values, true);
      89             : 
      90         582 :         if (!conn)
      91           0 :             pg_fatal("could not connect to database %s: out of memory",
      92             :                      cparams->dbname);
      93             : 
      94             :         /*
      95             :          * No luck?  Trying asking (again) for a password.
      96             :          */
      97         592 :         if (PQstatus(conn) == CONNECTION_BAD &&
      98          10 :             PQconnectionNeedsPassword(conn) &&
      99           0 :             cparams->prompt_password != TRI_NO)
     100             :         {
     101           0 :             PQfinish(conn);
     102           0 :             free(password);
     103           0 :             password = simple_prompt("Password: ", false);
     104           0 :             new_pass = true;
     105             :         }
     106         582 :     } while (new_pass);
     107             : 
     108             :     /* check to see that the backend connection was successfully made */
     109         582 :     if (PQstatus(conn) == CONNECTION_BAD)
     110             :     {
     111          10 :         if (fail_ok)
     112             :         {
     113           0 :             PQfinish(conn);
     114           0 :             return NULL;
     115             :         }
     116          10 :         pg_fatal("%s", PQerrorMessage(conn));
     117             :     }
     118             : 
     119             :     /* Start strict; callers may override this. */
     120         572 :     PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL, echo));
     121             : 
     122         572 :     return conn;
     123             : }
     124             : 
     125             : /*
     126             :  * Try to connect to the appropriate maintenance database.
     127             :  *
     128             :  * This differs from connectDatabase only in that it has a rule for
     129             :  * inserting a default "dbname" if none was given (which is why cparams
     130             :  * is not const).  Note that cparams->dbname should typically come from
     131             :  * a --maintenance-db command line parameter.
     132             :  */
     133             : PGconn *
     134         204 : connectMaintenanceDatabase(ConnParams *cparams,
     135             :                            const char *progname, bool echo)
     136             : {
     137             :     PGconn     *conn;
     138             : 
     139             :     /* If a maintenance database name was specified, just connect to it. */
     140         204 :     if (cparams->dbname)
     141           0 :         return connectDatabase(cparams, progname, echo, false, false);
     142             : 
     143             :     /* Otherwise, try postgres first and then template1. */
     144         204 :     cparams->dbname = "postgres";
     145         204 :     conn = connectDatabase(cparams, progname, echo, true, false);
     146         204 :     if (!conn)
     147             :     {
     148           0 :         cparams->dbname = "template1";
     149           0 :         conn = connectDatabase(cparams, progname, echo, false, false);
     150             :     }
     151         204 :     return conn;
     152             : }
     153             : 
     154             : /*
     155             :  * Disconnect the given connection, canceling any statement if one is active.
     156             :  */
     157             : void
     158         372 : disconnectDatabase(PGconn *conn)
     159             : {
     160             :     char        errbuf[256];
     161             : 
     162             :     Assert(conn != NULL);
     163             : 
     164         372 :     if (PQtransactionStatus(conn) == PQTRANS_ACTIVE)
     165             :     {
     166             :         PGcancel   *cancel;
     167             : 
     168           0 :         if ((cancel = PQgetCancel(conn)))
     169             :         {
     170           0 :             (void) PQcancel(cancel, errbuf, sizeof(errbuf));
     171           0 :             PQfreeCancel(cancel);
     172             :         }
     173             :     }
     174             : 
     175         372 :     PQfinish(conn);
     176         372 : }

Generated by: LCOV version 1.14