Skip to content

Commit c7f2349

Browse files
committed
Add \ir command to psql.
\ir is short for "include relative"; when used from a script, the supplied pathname will be interpreted relative to the input file, rather than to the current working directory. Gurjeet Singh, reviewed by Josh Kupershmidt, with substantial further cleanup by me.
1 parent 5ac6b76 commit c7f2349

File tree

9 files changed

+68
-12
lines changed

9 files changed

+68
-12
lines changed

doc/src/sgml/ref/psql-ref.sgml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,6 +1625,21 @@ Tue Oct 26 21:40:57 CEST 1999
16251625
</varlistentry>
16261626

16271627

1628+
<varlistentry>
1629+
<term><literal>\ir <replaceable class="parameter">filename</replaceable></literal></term>
1630+
<listitem>
1631+
<para>
1632+
The <literal>\ir</> command is similar to <literal>\i</>, but resolves
1633+
relative pathnames differently. When executing in interactive mode,
1634+
the two commands behave identically. However, when invoked from a
1635+
script, <literal>\ir</literal> interprets pathnames relative to the
1636+
directory in which the script is located, rather than the current
1637+
working directory.
1638+
</para>
1639+
</listitem>
1640+
</varlistentry>
1641+
1642+
16281643
<varlistentry>
16291644
<term><literal>\l</literal> (or <literal>\list</literal>)</term>
16301645
<term><literal>\l+</literal> (or <literal>\list+</literal>)</term>

src/bin/psql/command.c

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -784,8 +784,9 @@ exec_command(const char *cmd,
784784
}
785785

786786

787-
/* \i is include file */
788-
else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
787+
/* \i and \ir include files */
788+
else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0
789+
|| strcmp(cmd, "ir") == 0 || strcmp(cmd, "include_relative") == 0)
789790
{
790791
char *fname = psql_scan_slash_option(scan_state,
791792
OT_NORMAL, NULL, true);
@@ -797,8 +798,12 @@ exec_command(const char *cmd,
797798
}
798799
else
799800
{
801+
bool include_relative;
802+
803+
include_relative = (strcmp(cmd, "ir") == 0
804+
|| strcmp(cmd, "include_relative") == 0);
800805
expand_tilde(&fname);
801-
success = (process_file(fname, false) == EXIT_SUCCESS);
806+
success = (process_file(fname, false, include_relative) == EXIT_SUCCESS);
802807
free(fname);
803808
}
804809
}
@@ -1969,15 +1974,19 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
19691974
* process_file
19701975
*
19711976
* Read commands from filename and then them to the main processing loop
1972-
* Handler for \i, but can be used for other things as well. Returns
1977+
* Handler for \i and \ir, but can be used for other things as well. Returns
19731978
* MainLoop() error code.
1979+
*
1980+
* If use_relative_path is true and filename is not an absolute path, then open
1981+
* the file from where the currently processed file (if any) is located.
19741982
*/
19751983
int
1976-
process_file(char *filename, bool single_txn)
1984+
process_file(char *filename, bool single_txn, bool use_relative_path)
19771985
{
19781986
FILE *fd;
19791987
int result;
19801988
char *oldfilename;
1989+
char relpath[MAXPGPATH];
19811990
PGresult *res;
19821991

19831992
if (!filename)
@@ -1986,6 +1995,24 @@ process_file(char *filename, bool single_txn)
19861995
if (strcmp(filename, "-") != 0)
19871996
{
19881997
canonicalize_path(filename);
1998+
1999+
/*
2000+
* If we were asked to resolve the pathname relative to the location
2001+
* of the currently executing script, and there is one, and this is
2002+
* a relative pathname, then prepend all but the last pathname
2003+
* component of the current script to this pathname.
2004+
*/
2005+
if (use_relative_path && pset.inputfile && !is_absolute_path(filename)
2006+
&& !has_drive_prefix(filename))
2007+
{
2008+
snprintf(relpath, MAXPGPATH, "%s", pset.inputfile);
2009+
get_parent_directory(relpath);
2010+
join_path_components(relpath, relpath, filename);
2011+
canonicalize_path(relpath);
2012+
2013+
filename = relpath;
2014+
}
2015+
19892016
fd = fopen(filename, PG_BINARY_R);
19902017
}
19912018
else

src/bin/psql/command.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ typedef enum _backslashResult
2727
extern backslashResult HandleSlashCmds(PsqlScanState scan_state,
2828
PQExpBuffer query_buf);
2929

30-
extern int process_file(char *filename, bool single_txn);
30+
extern int process_file(char *filename, bool single_txn, bool use_relative_path);
3131

3232
extern bool do_pset(const char *param,
3333
const char *value,

src/bin/psql/help.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ slashUsage(unsigned short int pager)
158158
{
159159
FILE *output;
160160

161-
output = PageOutput(92, pager);
161+
output = PageOutput(93, pager);
162162

163163
/* if you add/remove a line here, change the row count above */
164164

@@ -184,6 +184,7 @@ slashUsage(unsigned short int pager)
184184
fprintf(output, _(" \\copy ... perform SQL COPY with data stream to the client host\n"));
185185
fprintf(output, _(" \\echo [STRING] write string to standard output\n"));
186186
fprintf(output, _(" \\i FILE execute commands from file\n"));
187+
fprintf(output, _(" \\ir FILE as \\i, but relative to location of current script\n"));
187188
fprintf(output, _(" \\o [FILE] send all query results to file or |pipe\n"));
188189
fprintf(output, _(" \\qecho [STRING] write string to query output stream (see \\o)\n"));
189190
fprintf(output, "\n");

src/bin/psql/settings.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ typedef struct _psqlSettings
8181
bool cur_cmd_interactive;
8282
int sversion; /* backend server version */
8383
const char *progname; /* in case you renamed psql */
84-
char *inputfile; /* for error reporting */
84+
char *inputfile; /* file being currently processed, if any */
8585
char *dirname; /* current directory for \s display */
8686

8787
uint64 lineno; /* also for error reporting */

src/bin/psql/startup.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ main(int argc, char *argv[])
256256
if (!options.no_psqlrc)
257257
process_psqlrc(argv[0]);
258258

259-
successResult = process_file(options.action_string, options.single_txn);
259+
successResult = process_file(options.action_string, options.single_txn, false);
260260
}
261261

262262
/*
@@ -604,9 +604,9 @@ process_psqlrc_file(char *filename)
604604
sprintf(psqlrc, "%s-%s", filename, PG_VERSION);
605605

606606
if (access(psqlrc, R_OK) == 0)
607-
(void) process_file(psqlrc, false);
607+
(void) process_file(psqlrc, false, false);
608608
else if (access(filename, R_OK) == 0)
609-
(void) process_file(filename, false);
609+
(void) process_file(filename, false, false);
610610
free(psqlrc);
611611
}
612612

src/bin/psql/tab-complete.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ psql_completion(char *text, int start, int end)
735735
"\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL",
736736
"\\dn", "\\do", "\\dp", "\\drds", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du",
737737
"\\e", "\\echo", "\\ef", "\\encoding",
738-
"\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
738+
"\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\ir", "\\l",
739739
"\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
740740
"\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
741741
"\\set", "\\sf", "\\t", "\\T",
@@ -2874,6 +2874,7 @@ psql_completion(char *text, int start, int end)
28742874
strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
28752875
strcmp(prev_wd, "\\g") == 0 ||
28762876
strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
2877+
strcmp(prev_wd, "\\ir") == 0 || strcmp(prev_wd, "\\include_relative") == 0 ||
28772878
strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
28782879
strcmp(prev_wd, "\\s") == 0 ||
28792880
strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0

src/include/port.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ extern bool pg_set_block(pgsocket sock);
3434

3535
/* Portable path handling for Unix/Win32 (in path.c) */
3636

37+
extern bool has_drive_prefix(const char *filename);
3738
extern char *first_dir_separator(const char *filename);
3839
extern char *last_dir_separator(const char *filename);
3940
extern char *first_path_var_separator(const char *pathlist);

src/port/path.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,17 @@ skip_drive(const char *path)
7474
#define skip_drive(path) (path)
7575
#endif
7676

77+
/*
78+
* has_drive_prefix
79+
*
80+
* Return true if the given pathname has a drive prefix.
81+
*/
82+
bool
83+
has_drive_prefix(const char *path)
84+
{
85+
return skip_drive(path) != path;
86+
}
87+
7788
/*
7889
* first_dir_separator
7990
*

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy