aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2011-07-06 11:45:13 -0400
committerRobert Haas <rhaas@postgresql.org>2011-07-06 11:45:13 -0400
commitc7f23494c1103f87bcf1ef7cbfcd626e73edb337 (patch)
tree7986492776b72dae25a10615076658879440aa03 /src
parent5ac6b767893281cab5c974b039400118851d548b (diff)
downloadpostgresql-c7f23494c1103f87bcf1ef7cbfcd626e73edb337.tar.gz
postgresql-c7f23494c1103f87bcf1ef7cbfcd626e73edb337.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/bin/psql/command.c37
-rw-r--r--src/bin/psql/command.h2
-rw-r--r--src/bin/psql/help.c3
-rw-r--r--src/bin/psql/settings.h2
-rw-r--r--src/bin/psql/startup.c6
-rw-r--r--src/bin/psql/tab-complete.c3
-rw-r--r--src/include/port.h1
-rw-r--r--src/port/path.c11
8 files changed, 53 insertions, 12 deletions
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 378330b96ae..16ff9e91e55 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -784,8 +784,9 @@ exec_command(const char *cmd,
}
- /* \i is include file */
- else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
+ /* \i and \ir include files */
+ else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0
+ || strcmp(cmd, "ir") == 0 || strcmp(cmd, "include_relative") == 0)
{
char *fname = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, true);
@@ -797,8 +798,12 @@ exec_command(const char *cmd,
}
else
{
+ bool include_relative;
+
+ include_relative = (strcmp(cmd, "ir") == 0
+ || strcmp(cmd, "include_relative") == 0);
expand_tilde(&fname);
- success = (process_file(fname, false) == EXIT_SUCCESS);
+ success = (process_file(fname, false, include_relative) == EXIT_SUCCESS);
free(fname);
}
}
@@ -1969,15 +1974,19 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
* process_file
*
* Read commands from filename and then them to the main processing loop
- * Handler for \i, but can be used for other things as well. Returns
+ * Handler for \i and \ir, but can be used for other things as well. Returns
* MainLoop() error code.
+ *
+ * If use_relative_path is true and filename is not an absolute path, then open
+ * the file from where the currently processed file (if any) is located.
*/
int
-process_file(char *filename, bool single_txn)
+process_file(char *filename, bool single_txn, bool use_relative_path)
{
FILE *fd;
int result;
char *oldfilename;
+ char relpath[MAXPGPATH];
PGresult *res;
if (!filename)
@@ -1986,6 +1995,24 @@ process_file(char *filename, bool single_txn)
if (strcmp(filename, "-") != 0)
{
canonicalize_path(filename);
+
+ /*
+ * If we were asked to resolve the pathname relative to the location
+ * of the currently executing script, and there is one, and this is
+ * a relative pathname, then prepend all but the last pathname
+ * component of the current script to this pathname.
+ */
+ if (use_relative_path && pset.inputfile && !is_absolute_path(filename)
+ && !has_drive_prefix(filename))
+ {
+ snprintf(relpath, MAXPGPATH, "%s", pset.inputfile);
+ get_parent_directory(relpath);
+ join_path_components(relpath, relpath, filename);
+ canonicalize_path(relpath);
+
+ filename = relpath;
+ }
+
fd = fopen(filename, PG_BINARY_R);
}
else
diff --git a/src/bin/psql/command.h b/src/bin/psql/command.h
index 852d645cfd0..9d0c31c1030 100644
--- a/src/bin/psql/command.h
+++ b/src/bin/psql/command.h
@@ -27,7 +27,7 @@ typedef enum _backslashResult
extern backslashResult HandleSlashCmds(PsqlScanState scan_state,
PQExpBuffer query_buf);
-extern int process_file(char *filename, bool single_txn);
+extern int process_file(char *filename, bool single_txn, bool use_relative_path);
extern bool do_pset(const char *param,
const char *value,
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index ac5edca65dd..e56ab61ac63 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -158,7 +158,7 @@ slashUsage(unsigned short int pager)
{
FILE *output;
- output = PageOutput(92, pager);
+ output = PageOutput(93, pager);
/* if you add/remove a line here, change the row count above */
@@ -184,6 +184,7 @@ slashUsage(unsigned short int pager)
fprintf(output, _(" \\copy ... perform SQL COPY with data stream to the client host\n"));
fprintf(output, _(" \\echo [STRING] write string to standard output\n"));
fprintf(output, _(" \\i FILE execute commands from file\n"));
+ fprintf(output, _(" \\ir FILE as \\i, but relative to location of current script\n"));
fprintf(output, _(" \\o [FILE] send all query results to file or |pipe\n"));
fprintf(output, _(" \\qecho [STRING] write string to query output stream (see \\o)\n"));
fprintf(output, "\n");
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
index 7228f9d0eea..3aebf532991 100644
--- a/src/bin/psql/settings.h
+++ b/src/bin/psql/settings.h
@@ -81,7 +81,7 @@ typedef struct _psqlSettings
bool cur_cmd_interactive;
int sversion; /* backend server version */
const char *progname; /* in case you renamed psql */
- char *inputfile; /* for error reporting */
+ char *inputfile; /* file being currently processed, if any */
char *dirname; /* current directory for \s display */
uint64 lineno; /* also for error reporting */
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 7b8078c21e4..3c17eece7b8 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -256,7 +256,7 @@ main(int argc, char *argv[])
if (!options.no_psqlrc)
process_psqlrc(argv[0]);
- successResult = process_file(options.action_string, options.single_txn);
+ successResult = process_file(options.action_string, options.single_txn, false);
}
/*
@@ -604,9 +604,9 @@ process_psqlrc_file(char *filename)
sprintf(psqlrc, "%s-%s", filename, PG_VERSION);
if (access(psqlrc, R_OK) == 0)
- (void) process_file(psqlrc, false);
+ (void) process_file(psqlrc, false, false);
else if (access(filename, R_OK) == 0)
- (void) process_file(filename, false);
+ (void) process_file(filename, false, false);
free(psqlrc);
}
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 32f418306cd..4f7df367e5a 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -735,7 +735,7 @@ psql_completion(char *text, int start, int end)
"\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL",
"\\dn", "\\do", "\\dp", "\\drds", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du",
"\\e", "\\echo", "\\ef", "\\encoding",
- "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
+ "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\ir", "\\l",
"\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
"\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
"\\set", "\\sf", "\\t", "\\T",
@@ -2874,6 +2874,7 @@ psql_completion(char *text, int start, int end)
strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
strcmp(prev_wd, "\\g") == 0 ||
strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
+ strcmp(prev_wd, "\\ir") == 0 || strcmp(prev_wd, "\\include_relative") == 0 ||
strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
strcmp(prev_wd, "\\s") == 0 ||
strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
diff --git a/src/include/port.h b/src/include/port.h
index 4c7ed643177..2cab65fbde7 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -34,6 +34,7 @@ extern bool pg_set_block(pgsocket sock);
/* Portable path handling for Unix/Win32 (in path.c) */
+extern bool has_drive_prefix(const char *filename);
extern char *first_dir_separator(const char *filename);
extern char *last_dir_separator(const char *filename);
extern char *first_path_var_separator(const char *pathlist);
diff --git a/src/port/path.c b/src/port/path.c
index 6991bc7247b..13ca4f3f1c1 100644
--- a/src/port/path.c
+++ b/src/port/path.c
@@ -75,6 +75,17 @@ skip_drive(const char *path)
#endif
/*
+ * has_drive_prefix
+ *
+ * Return true if the given pathname has a drive prefix.
+ */
+bool
+has_drive_prefix(const char *path)
+{
+ return skip_drive(path) != path;
+}
+
+/*
* first_dir_separator
*
* Find the location of the first directory separator, return