On Sun, Jun 5, 2011 at 1:06 PM, Josh Kupershmidt <[email protected]> wrote:
> On Sun, Jun 5, 2011 at 10:21 AM, Gurjeet Singh <[email protected]>
> wrote:
> > On Sat, May 21, 2011 at 11:59 AM, Josh Kupershmidt <[email protected]>
> > wrote:
>
> > Tweaks applied, but omitted the C variable names as I don't think that
> adds
> > much value.
>
> Your rewordings are fine, but the the article "the" is missing in a
> few spots, e.g.
> * "uses \ir command" -> "uses the \ir command"
> * "to currently processing file" -> "to the currently processing file"
> * "same as \i command" -> "same as the \i command"
>
> I think "processing" is better (and consistent with the rest of the
> comments) than "processed" here:
> + * the file from where the currently processed file (if any) is located.
>
> > New version of the patch attached. Thanks for the review.
>
> I think the patch is in pretty good shape now. The memory leak is gone
> AFAICT, and the comments and documentation updates look good.
>
Attached an updated patch.
If you find it ready for committer, please mark it so in the commitfest app.
Thanks,
--
Gurjeet Singh
EnterpriseDB Corporation
The Enterprise PostgreSQL Company
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index eaf901d..9bd6d93 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1626,6 +1626,30 @@ Tue Oct 26 21:40:57 CEST 1999
<varlistentry>
+ <term><literal>\ir <replaceable class="parameter">filename</replaceable></literal></term>
+ <listitem>
+ <para>
+ The <literal>\ir</> command is similar to <literal>\i</>, but is useful for files which
+ include and execute other files.
+ </para>
+
+ <para>
+ When used within a file loaded via <literal>\i</literal>, <literal>\ir</literal>, or
+ <option>-f</option>, if the <replaceable class="parameter">filename</replaceable>
+ is specified using a relative path, then the location of the file will be determined
+ relative to the currently executing file's location.
+ </para>
+
+ <para>
+ If <replaceable class="parameter">filename</replaceable> is given as an absolute path,
+ or if this command is used in interactive mode, then <literal>\ir</> behaves the same
+ as the <literal>\i</> command.
+ </para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
<term><literal>\l</literal> (or <literal>\list</literal>)</term>
<term><literal>\l+</literal> (or <literal>\list+</literal>)</term>
<listitem>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 378330b..faa3087 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -785,10 +785,15 @@ exec_command(const char *cmd,
/* \i is include file */
- else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
+ /* \ir is include file relative to file currently being processed */
+ 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);
+ char *fname = psql_scan_slash_option(scan_state,
+ OT_NORMAL, NULL, true);
+
+ bool include_relative = (strcmp(cmd, "ir") == 0
+ || strcmp(cmd, "include_relative") == 0);
if (!fname)
{
@@ -798,7 +803,7 @@ exec_command(const char *cmd,
else
{
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 *relative_file = NULL;
PGresult *res;
if (!filename)
@@ -1986,6 +1995,39 @@ process_file(char *filename, bool single_txn)
if (strcmp(filename, "-") != 0)
{
canonicalize_path(filename);
+
+ /*
+ * If the currently processing file uses the \ir command, and the
+ * 'filename' parameter to the command is given as a relative file path,
+ * then we resolve this path relative to the currently processing file.
+ *
+ * If the \ir command was executed in interactive mode (i.e. not via \i,
+ * \ir or -f) the we treat it the same as the \i command.
+ */
+ if (use_relative_path && pset.inputfile)
+ {
+ char *last_slash;
+
+ /* find the / that splits the file from its path */
+ last_slash = strrchr(pset.inputfile, '/');
+
+ if (last_slash && !is_absolute_path(filename))
+ {
+ size_t dir_len = (last_slash - pset.inputfile) + 1;
+ size_t file_len = strlen(filename);
+
+ relative_file = pg_malloc(dir_len + 1 + file_len + 1);
+
+ relative_file[0] = '\0';
+ strncat(relative_file, pset.inputfile, dir_len);
+ strcat(relative_file, filename);
+
+ canonicalize_path(relative_file);
+
+ filename = relative_file;
+ }
+ }
+
fd = fopen(filename, PG_BINARY_R);
}
else
@@ -1993,6 +2035,9 @@ process_file(char *filename, bool single_txn)
if (!fd)
{
+ if (relative_file != NULL)
+ free(relative_file);
+
psql_error("%s: %s\n", filename, strerror(errno));
return EXIT_FAILURE;
}
@@ -2034,6 +2079,9 @@ error:
if (fd != stdin)
fclose(fd);
+ if (relative_file != NULL)
+ free(relative_file);
+
pset.inputfile = oldfilename;
return result;
}
diff --git a/src/bin/psql/command.h b/src/bin/psql/command.h
index 852d645..9d0c31c 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 ac5edca..d459934 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -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 execute commands from FILE, placed relative to currently processing file\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 7228f9d..2e28d86 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 7b8078c..3c17eec 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 9a7eca0..b86b0f0 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
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers