Add a \getenv command to psql.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 20 Dec 2021 18:17:58 +0000 (13:17 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 20 Dec 2021 18:17:58 +0000 (13:17 -0500)
\getenv fetches the value of an environment variable into a psql
variable.  This is the inverse of the \setenv command that was added
over ten years ago.  We'd not seen a compelling use-case for \getenv
at the time, but upcoming regression test refactoring provides a
sufficient reason to add it now.

Discussion: https://postgr.es/m/1655733.1639871614@sss.pgh.pa.us

doc/src/sgml/ref/psql-ref.sgml
src/bin/psql/command.c
src/test/regress/expected/psql.out
src/test/regress/sql/psql.sql

index 48248f750e5614f0967b5cd9304a7956804c9a0b..ae38d3dcc3ee71a434a6899bdb7b2f39f8cc77a7 100644 (file)
@@ -2237,6 +2237,28 @@ Tue Oct 26 21:40:57 CEST 1999
       </varlistentry>
 
 
+      <varlistentry>
+        <term><literal>\getenv <replaceable class="parameter">psql_var</replaceable> <replaceable class="parameter">env_var</replaceable></literal></term>
+
+        <listitem>
+        <para>
+         Gets the value of the environment
+         variable <replaceable class="parameter">env_var</replaceable>
+         and assigns it to the <application>psql</application>
+         variable <replaceable class="parameter">psql_var</replaceable>.
+         If <replaceable class="parameter">env_var</replaceable> is
+         not defined in the <application>psql</application> process's
+         environment, <replaceable class="parameter">psql_var</replaceable>
+         is not changed.  Example:
+<programlisting>
+=&gt; <userinput>\getenv home HOME</userinput>
+=&gt; <userinput>\echo :home</userinput>
+/home/postgres
+</programlisting></para>
+        </listitem>
+      </varlistentry>
+
+
       <varlistentry>
         <term><literal>\gexec</literal></term>
 
index ccd7b4810847ce5b5de72a9db0be296e9d77a8b3..fb3bab949487393dc33d0ecfff1d82ad92ad64e1 100644 (file)
@@ -98,6 +98,8 @@ static backslashResult process_command_g_options(char *first_option,
                                                 bool active_branch,
                                                 const char *cmd);
 static backslashResult exec_command_gdesc(PsqlScanState scan_state, bool active_branch);
+static backslashResult exec_command_getenv(PsqlScanState scan_state, bool active_branch,
+                                          const char *cmd);
 static backslashResult exec_command_gexec(PsqlScanState scan_state, bool active_branch);
 static backslashResult exec_command_gset(PsqlScanState scan_state, bool active_branch);
 static backslashResult exec_command_help(PsqlScanState scan_state, bool active_branch);
@@ -348,6 +350,8 @@ exec_command(const char *cmd,
        status = exec_command_g(scan_state, active_branch, cmd);
    else if (strcmp(cmd, "gdesc") == 0)
        status = exec_command_gdesc(scan_state, active_branch);
+   else if (strcmp(cmd, "getenv") == 0)
+       status = exec_command_getenv(scan_state, active_branch, cmd);
    else if (strcmp(cmd, "gexec") == 0)
        status = exec_command_gexec(scan_state, active_branch);
    else if (strcmp(cmd, "gset") == 0)
@@ -1481,6 +1485,43 @@ exec_command_gdesc(PsqlScanState scan_state, bool active_branch)
    return status;
 }
 
+/*
+ * \getenv -- set variable from environment variable
+ */
+static backslashResult
+exec_command_getenv(PsqlScanState scan_state, bool active_branch,
+                   const char *cmd)
+{
+   bool        success = true;
+
+   if (active_branch)
+   {
+       char       *myvar = psql_scan_slash_option(scan_state,
+                                                  OT_NORMAL, NULL, false);
+       char       *envvar = psql_scan_slash_option(scan_state,
+                                                   OT_NORMAL, NULL, false);
+
+       if (!myvar || !envvar)
+       {
+           pg_log_error("\\%s: missing required argument", cmd);
+           success = false;
+       }
+       else
+       {
+           char       *envval = getenv(envvar);
+
+           if (envval && !SetVariable(pset.vars, myvar, envval))
+               success = false;
+       }
+       free(myvar);
+       free(envvar);
+   }
+   else
+       ignore_slash_options(scan_state);
+
+   return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
+}
+
 /*
  * \gexec -- send query and execute each field of result
  */
index 930ce8597a1f470f8a03162dac24ea41684a980d..6428ebc507d7f9c0ec84cc90299910ddf0087805 100644 (file)
@@ -282,6 +282,18 @@ select '2000-01-01'::date as party_over
 (1 row)
 
 \unset FETCH_COUNT
+-- \setenv, \getenv
+-- ensure MYVAR isn't set
+\setenv MYVAR
+-- in which case, reading it doesn't change the target
+\getenv res MYVAR
+\echo :res
+:res
+-- now set it
+\setenv MYVAR 'environment value'
+\getenv res MYVAR
+\echo :res
+environment value
 -- show all pset options
 \pset
 border                   1
index e9d504baf21672b036836a1e2f54849c97e0b81c..d4e4fdbbb75c79e1250923809074c0f6f7c0c05c 100644 (file)
@@ -141,6 +141,18 @@ select 'drop table gexec_test', 'select ''2000-01-01''::date as party_over'
 
 \unset FETCH_COUNT
 
+-- \setenv, \getenv
+
+-- ensure MYVAR isn't set
+\setenv MYVAR
+-- in which case, reading it doesn't change the target
+\getenv res MYVAR
+\echo :res
+-- now set it
+\setenv MYVAR 'environment value'
+\getenv res MYVAR
+\echo :res
+
 -- show all pset options
 \pset