LCOV - code coverage report
Current view: top level - src/bin/pg_dump - connectdb.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 151 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 3 0
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * connectdb.c
       4              :  *    This is a common file connection to the database.
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7              :  * Portions Copyright (c) 1994, Regents of the University of California
       8              :  *
       9              :  * IDENTIFICATION
      10              :  *    src/bin/pg_dump/connectdb.c
      11              :  *
      12              :  *-------------------------------------------------------------------------
      13              :  */
      14              : 
      15              : #include "postgres_fe.h"
      16              : 
      17              : #include "common/connect.h"
      18              : #include "common/logging.h"
      19              : #include "common/string.h"
      20              : #include "connectdb.h"
      21              : #include "dumputils.h"
      22              : #include "fe_utils/string_utils.h"
      23              : 
      24              : static char *constructConnStr(const char **keywords, const char **values);
      25              : 
      26              : /*
      27              :  * ConnectDatabase
      28              :  *
      29              :  * Make a database connection with the given parameters.  An
      30              :  * interactive password prompt is automatically issued if required.
      31              :  *
      32              :  * If fail_on_error is false, we return NULL without printing any message
      33              :  * on failure, but preserve any prompted password for the next try.
      34              :  *
      35              :  * On success, the 'connstr' is set to a connection string containing
      36              :  * the options used and 'server_version' is set to version so that caller
      37              :  * can use them.
      38              :  */
      39              : PGconn *
      40            0 : ConnectDatabase(const char *dbname, const char *connection_string,
      41              :                                 const char *pghost, const char *pgport, const char *pguser,
      42              :                                 trivalue prompt_password, bool fail_on_error, const char *progname,
      43              :                                 const char **connstr, int *server_version, char *password,
      44              :                                 char *override_dbname)
      45              : {
      46            0 :         PGconn     *conn;
      47            0 :         bool            new_pass;
      48            0 :         const char *remoteversion_str;
      49            0 :         int                     my_version;
      50            0 :         const char **keywords = NULL;
      51            0 :         const char **values = NULL;
      52            0 :         PQconninfoOption *conn_opts = NULL;
      53            0 :         int                     server_version_temp;
      54              : 
      55            0 :         if (prompt_password == TRI_YES && !password)
      56            0 :                 password = simple_prompt("Password: ", false);
      57              : 
      58              :         /*
      59              :          * Start the connection.  Loop until we have a password if requested by
      60              :          * backend.
      61              :          */
      62            0 :         do
      63              :         {
      64            0 :                 int                     argcount = 8;
      65            0 :                 PQconninfoOption *conn_opt;
      66            0 :                 char       *err_msg = NULL;
      67            0 :                 int                     i = 0;
      68              : 
      69            0 :                 free(keywords);
      70            0 :                 free(values);
      71            0 :                 PQconninfoFree(conn_opts);
      72              : 
      73              :                 /*
      74              :                  * Merge the connection info inputs given in form of connection string
      75              :                  * and other options.  Explicitly discard any dbname value in the
      76              :                  * connection string; otherwise, PQconnectdbParams() would interpret
      77              :                  * that value as being itself a connection string.
      78              :                  */
      79            0 :                 if (connection_string)
      80              :                 {
      81            0 :                         conn_opts = PQconninfoParse(connection_string, &err_msg);
      82            0 :                         if (conn_opts == NULL)
      83            0 :                                 pg_fatal("%s", err_msg);
      84              : 
      85            0 :                         for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
      86              :                         {
      87            0 :                                 if (conn_opt->val != NULL && conn_opt->val[0] != '\0' &&
      88            0 :                                         strcmp(conn_opt->keyword, "dbname") != 0)
      89            0 :                                         argcount++;
      90            0 :                         }
      91              : 
      92            0 :                         keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
      93            0 :                         values = pg_malloc0((argcount + 1) * sizeof(*values));
      94              : 
      95            0 :                         for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
      96              :                         {
      97            0 :                                 if (conn_opt->val != NULL && conn_opt->val[0] != '\0' &&
      98            0 :                                         strcmp(conn_opt->keyword, "dbname") != 0)
      99              :                                 {
     100            0 :                                         keywords[i] = conn_opt->keyword;
     101            0 :                                         values[i] = conn_opt->val;
     102            0 :                                         i++;
     103            0 :                                 }
     104            0 :                         }
     105            0 :                 }
     106              :                 else
     107              :                 {
     108            0 :                         keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
     109            0 :                         values = pg_malloc0((argcount + 1) * sizeof(*values));
     110              :                 }
     111              : 
     112            0 :                 if (pghost)
     113              :                 {
     114            0 :                         keywords[i] = "host";
     115            0 :                         values[i] = pghost;
     116            0 :                         i++;
     117            0 :                 }
     118            0 :                 if (pgport)
     119              :                 {
     120            0 :                         keywords[i] = "port";
     121            0 :                         values[i] = pgport;
     122            0 :                         i++;
     123            0 :                 }
     124            0 :                 if (pguser)
     125              :                 {
     126            0 :                         keywords[i] = "user";
     127            0 :                         values[i] = pguser;
     128            0 :                         i++;
     129            0 :                 }
     130            0 :                 if (password)
     131              :                 {
     132            0 :                         keywords[i] = "password";
     133            0 :                         values[i] = password;
     134            0 :                         i++;
     135            0 :                 }
     136            0 :                 if (dbname)
     137              :                 {
     138            0 :                         keywords[i] = "dbname";
     139            0 :                         values[i] = dbname;
     140            0 :                         i++;
     141            0 :                 }
     142            0 :                 if (override_dbname)
     143              :                 {
     144            0 :                         keywords[i] = "dbname";
     145            0 :                         values[i] = override_dbname;
     146            0 :                         i++;
     147            0 :                 }
     148              : 
     149            0 :                 keywords[i] = "fallback_application_name";
     150            0 :                 values[i] = progname;
     151            0 :                 i++;
     152              : 
     153            0 :                 new_pass = false;
     154            0 :                 conn = PQconnectdbParams(keywords, values, true);
     155              : 
     156            0 :                 if (!conn)
     157            0 :                         pg_fatal("could not connect to database \"%s\"", dbname);
     158              : 
     159            0 :                 if (PQstatus(conn) == CONNECTION_BAD &&
     160            0 :                         PQconnectionNeedsPassword(conn) &&
     161            0 :                         !password &&
     162            0 :                         prompt_password != TRI_NO)
     163              :                 {
     164            0 :                         PQfinish(conn);
     165            0 :                         password = simple_prompt("Password: ", false);
     166            0 :                         new_pass = true;
     167            0 :                 }
     168            0 :         } while (new_pass);
     169              : 
     170              :         /* check to see that the backend connection was successfully made */
     171            0 :         if (PQstatus(conn) == CONNECTION_BAD)
     172              :         {
     173            0 :                 if (fail_on_error)
     174            0 :                         pg_fatal("%s", PQerrorMessage(conn));
     175              :                 else
     176              :                 {
     177            0 :                         PQfinish(conn);
     178              : 
     179            0 :                         free(keywords);
     180            0 :                         free(values);
     181            0 :                         PQconninfoFree(conn_opts);
     182              : 
     183            0 :                         return NULL;
     184              :                 }
     185            0 :         }
     186              : 
     187              :         /*
     188              :          * Ok, connected successfully. If requested, remember the options used, in
     189              :          * the form of a connection string.
     190              :          */
     191            0 :         if (connstr)
     192            0 :                 *connstr = constructConnStr(keywords, values);
     193              : 
     194            0 :         free(keywords);
     195            0 :         free(values);
     196            0 :         PQconninfoFree(conn_opts);
     197              : 
     198              :         /* Check version */
     199            0 :         remoteversion_str = PQparameterStatus(conn, "server_version");
     200            0 :         if (!remoteversion_str)
     201            0 :                 pg_fatal("could not get server version");
     202              : 
     203            0 :         server_version_temp = PQserverVersion(conn);
     204            0 :         if (server_version_temp == 0)
     205            0 :                 pg_fatal("could not parse server version \"%s\"",
     206              :                                  remoteversion_str);
     207              : 
     208              :         /* If requested, then copy server version to out variable. */
     209            0 :         if (server_version)
     210            0 :                 *server_version = server_version_temp;
     211              : 
     212            0 :         my_version = PG_VERSION_NUM;
     213              : 
     214              :         /*
     215              :          * We allow the server to be back to 9.2, and up to any minor release of
     216              :          * our own major version.  (See also version check in pg_dump.c.)
     217              :          */
     218            0 :         if (my_version != server_version_temp
     219            0 :                 && (server_version_temp < 90200 ||
     220            0 :                         (server_version_temp / 100) > (my_version / 100)))
     221              :         {
     222            0 :                 pg_log_error("aborting because of server version mismatch");
     223            0 :                 pg_log_error_detail("server version: %s; %s version: %s",
     224              :                                                         remoteversion_str, progname, PG_VERSION);
     225            0 :                 exit_nicely(1);
     226              :         }
     227              : 
     228            0 :         PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL));
     229              : 
     230            0 :         return conn;
     231            0 : }
     232              : 
     233              : /*
     234              :  * constructConnStr
     235              :  *
     236              :  * Construct a connection string from the given keyword/value pairs. It is
     237              :  * used to pass the connection options to the pg_dump subprocess.
     238              :  *
     239              :  * The following parameters are excluded:
     240              :  *      dbname          - varies in each pg_dump invocation
     241              :  *      password        - it's not secure to pass a password on the command line
     242              :  *      fallback_application_name - we'll let pg_dump set it
     243              :  */
     244              : static char *
     245            0 : constructConnStr(const char **keywords, const char **values)
     246              : {
     247            0 :         PQExpBuffer buf = createPQExpBuffer();
     248            0 :         char       *connstr;
     249            0 :         int                     i;
     250            0 :         bool            firstkeyword = true;
     251              : 
     252              :         /* Construct a new connection string in key='value' format. */
     253            0 :         for (i = 0; keywords[i] != NULL; i++)
     254              :         {
     255            0 :                 if (strcmp(keywords[i], "dbname") == 0 ||
     256            0 :                         strcmp(keywords[i], "password") == 0 ||
     257            0 :                         strcmp(keywords[i], "fallback_application_name") == 0)
     258            0 :                         continue;
     259              : 
     260            0 :                 if (!firstkeyword)
     261            0 :                         appendPQExpBufferChar(buf, ' ');
     262            0 :                 firstkeyword = false;
     263            0 :                 appendPQExpBuffer(buf, "%s=", keywords[i]);
     264            0 :                 appendConnStrVal(buf, values[i]);
     265            0 :         }
     266              : 
     267            0 :         connstr = pg_strdup(buf->data);
     268            0 :         destroyPQExpBuffer(buf);
     269            0 :         return connstr;
     270            0 : }
     271              : 
     272              : /*
     273              :  * executeQuery
     274              :  *
     275              :  * Run a query, return the results, exit program on failure.
     276              :  */
     277              : PGresult *
     278            0 : executeQuery(PGconn *conn, const char *query)
     279              : {
     280            0 :         PGresult   *res;
     281              : 
     282            0 :         pg_log_info("executing %s", query);
     283              : 
     284            0 :         res = PQexec(conn, query);
     285            0 :         if (!res ||
     286            0 :                 PQresultStatus(res) != PGRES_TUPLES_OK)
     287              :         {
     288            0 :                 pg_log_error("query failed: %s", PQerrorMessage(conn));
     289            0 :                 pg_log_error_detail("Query was: %s", query);
     290            0 :                 PQfinish(conn);
     291            0 :                 exit_nicely(1);
     292              :         }
     293              : 
     294            0 :         return res;
     295            0 : }
        

Generated by: LCOV version 2.3.2-1