LCOV - code coverage report
Current view: top level - src/fe_utils - connect_utils.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 42 59 71.2 %
Date: 2024-12-02 19:14:57 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         670 : 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         670 :     if (!allow_password_reuse && password)
      43             :     {
      44           0 :         free(password);
      45           0 :         password = NULL;
      46             :     }
      47             : 
      48         670 :     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         670 :         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         670 :         keywords[i] = "host";
      67         670 :         values[i++] = cparams->pghost;
      68         670 :         keywords[i] = "port";
      69         670 :         values[i++] = cparams->pgport;
      70         670 :         keywords[i] = "user";
      71         670 :         values[i++] = cparams->pguser;
      72         670 :         keywords[i] = "password";
      73         670 :         values[i++] = password;
      74         670 :         keywords[i] = "dbname";
      75         670 :         values[i++] = cparams->dbname;
      76         670 :         if (cparams->override_dbname)
      77             :         {
      78         226 :             keywords[i] = "dbname";
      79         226 :             values[i++] = cparams->override_dbname;
      80             :         }
      81         670 :         keywords[i] = "fallback_application_name";
      82         670 :         values[i++] = progname;
      83         670 :         keywords[i] = NULL;
      84         670 :         values[i++] = NULL;
      85             :         Assert(i <= lengthof(keywords));
      86             : 
      87         670 :         new_pass = false;
      88         670 :         conn = PQconnectdbParams(keywords, values, true);
      89             : 
      90         670 :         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         680 :         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         670 :     } while (new_pass);
     107             : 
     108             :     /* check to see that the backend connection was successfully made */
     109         670 :     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         660 :     PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL, echo));
     121             : 
     122         660 :     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         246 : 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         246 :     if (cparams->dbname)
     141           0 :         return connectDatabase(cparams, progname, echo, false, false);
     142             : 
     143             :     /* Otherwise, try postgres first and then template1. */
     144         246 :     cparams->dbname = "postgres";
     145         246 :     conn = connectDatabase(cparams, progname, echo, true, false);
     146         246 :     if (!conn)
     147             :     {
     148           0 :         cparams->dbname = "template1";
     149           0 :         conn = connectDatabase(cparams, progname, echo, false, false);
     150             :     }
     151         246 :     return conn;
     152             : }
     153             : 
     154             : /*
     155             :  * Disconnect the given connection, canceling any statement if one is active.
     156             :  */
     157             : void
     158         414 : disconnectDatabase(PGconn *conn)
     159             : {
     160             :     Assert(conn != NULL);
     161             : 
     162         414 :     if (PQtransactionStatus(conn) == PQTRANS_ACTIVE)
     163             :     {
     164           0 :         PGcancelConn *cancelConn = PQcancelCreate(conn);
     165             : 
     166           0 :         (void) PQcancelBlocking(cancelConn);
     167           0 :         PQcancelFinish(cancelConn);
     168             :     }
     169             : 
     170         414 :     PQfinish(conn);
     171         414 : }

Generated by: LCOV version 1.14