Fwd: psql include file using relative path

Started by Gurjeet Singhalmost 15 years ago12 messages
#1Gurjeet Singh
singh.gurjeet@gmail.com
2 attachment(s)

psql has the ability to execute commands from a file, but if one wishes
to develop and provide a modularized set of sql files, then psql is not very
helpful because the \i command can open file paths either if they are
absolute paths or if they are palced correctly relative to psql's current
working directory.

Attached patch adds a new meta-command to psql, '\ir' that allows the user
to process files relative to currently processing file.

Also attached is a sample use case ir_sample. One can extract it _anywhere_
on the filesystem and invoke psql with the path to main.sql and the rest of
the files will be automatically included from that location.

Sample session:

[/tmp]$ psql -f ~/dev/ir_sample/main.sql
processing main.sql
BEGIN
processing subdir1/1.sql
processing subdir1/2.sql
processing subdir2/1.sql
processing subdir2/subdir2.1/1.sql
processing subdir2/2.sql
processing subdir2/3.sql
COMMIT

And here's what the sample's directory structure and files look like:

[ir_sample]$ find ./ -name "*.sql" | while read f; do echo === $f ====; cat
$f; done
=== ./main.sql ====
\echo processing main.sql
BEGIN;
\ir subdir1/1.sql
\ir subdir1/2.sql
\ir subdir2/1.sql
\ir subdir2/2.sql
\ir subdir2/3.sql
COMMIT;
=== ./subdir1/1.sql ====
\echo processing subdir1/1.sql
=== ./subdir1/2.sql ====
\echo processing subdir1/2.sql
=== ./subdir2/subdir2.1/1.sql ====
\echo processing subdir2/subdir2.1/1.sql
=== ./subdir2/1.sql ====
\echo processing subdir2/1.sql
\ir subdir2.1/1.sql
=== ./subdir2/2.sql ====
\echo processing subdir2/2.sql
=== ./subdir2/3.sql ====
\echo processing subdir2/3.sql

Regards,
--
Gurjeet Singh
EnterpriseDB Corporation <http://www.enterprisedb.com/&gt;
The Enterprise PostgreSQL <http://www.postgresql.org/&gt; Company

Attachments:

psql_ir.patchtext/x-patch; charset=US-ASCII; name=psql_ir.patchDownload
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index d7cdcf6..bc3949e 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -785,7 +785,8 @@ 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 currently processed file */
+	else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0 || strcmp(cmd, "ir") == 0)
 	{
 		char	   *fname = psql_scan_slash_option(scan_state,
 												   OT_NORMAL, NULL, true);
@@ -798,7 +799,7 @@ exec_command(const char *cmd,
 		else
 		{
 			expand_tilde(&fname);
-			success = (process_file(fname, false) == EXIT_SUCCESS);
+			success = (process_file(fname, false, (cmd[1] == 'r')) == EXIT_SUCCESS);
 			free(fname);
 		}
 	}
@@ -1971,14 +1972,18 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
  * 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
  * 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;
 	PGresult   *res;
+	char	   *last_slash = NULL;
 
 	if (!filename)
 		return EXIT_FAILURE;
@@ -1986,6 +1991,29 @@ process_file(char *filename, bool single_txn)
 	if (strcmp(filename, "-") != 0)
 	{
 		canonicalize_path(filename);
+
+		if (use_relative_path && pset.inputfile)
+		{
+			/* 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);
+
+				char *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
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/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);
 }
 
ir_sample.tgzapplication/x-gzip; name=ir_sample.tgzDownload
#2Robert Haas
robertmhaas@gmail.com
In reply to: Gurjeet Singh (#1)
Re: Fwd: psql include file using relative path

On Thu, Feb 24, 2011 at 6:21 PM, Gurjeet Singh <singh.gurjeet@gmail.com> wrote:

    psql has the ability to execute commands from a file, but if one wishes
to develop and provide a modularized set of sql files, then psql is not very
helpful because the \i command can open file paths either if they are
absolute paths or if they are palced correctly relative to psql's current
working directory.

Attached patch adds a new meta-command to psql, '\ir' that allows the user
to process files relative to currently processing file.

Please add this patch to the currently open CommitFest at:

https://commitfest.postgresql.org/action/commitfest_view/open

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#3Ibrar Ahmed
ibrar.ahmad@gmail.com
In reply to: Robert Haas (#2)
Re: Fwd: psql include file using relative path

Gurjeet!

What about tab completion, like in \i command?

On Fri, Feb 25, 2011 at 5:07 AM, Robert Haas <robertmhaas@gmail.com> wrote:

On Thu, Feb 24, 2011 at 6:21 PM, Gurjeet Singh <singh.gurjeet@gmail.com> wrote:

    psql has the ability to execute commands from a file, but if one wishes
to develop and provide a modularized set of sql files, then psql is not very
helpful because the \i command can open file paths either if they are
absolute paths or if they are palced correctly relative to psql's current
working directory.

Attached patch adds a new meta-command to psql, '\ir' that allows the user
to process files relative to currently processing file.

Please add this patch to the currently open CommitFest at:

https://commitfest.postgresql.org/action/commitfest_view/open

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

--
   Ibrar Ahmed

#4Gurjeet Singh
singh.gurjeet@gmail.com
In reply to: Ibrar Ahmed (#3)
1 attachment(s)
Re: Fwd: psql include file using relative path

Attached patch implements tab completion. It also introduces the long-form
alternative \include_relative for \ir

Regards,

On Tue, Mar 8, 2011 at 2:18 PM, Ibrar Ahmed <ibrar.ahmad@gmail.com> wrote:

Gurjeet!

What about tab completion, like in \i command?

On Fri, Feb 25, 2011 at 5:07 AM, Robert Haas <robertmhaas@gmail.com>
wrote:

On Thu, Feb 24, 2011 at 6:21 PM, Gurjeet Singh <singh.gurjeet@gmail.com>

wrote:

psql has the ability to execute commands from a file, but if one

wishes

to develop and provide a modularized set of sql files, then psql is not

very

helpful because the \i command can open file paths either if they are
absolute paths or if they are palced correctly relative to psql's

current

working directory.

Attached patch adds a new meta-command to psql, '\ir' that allows the

user

to process files relative to currently processing file.

Please add this patch to the currently open CommitFest at:

https://commitfest.postgresql.org/action/commitfest_view/open

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

--
Ibrar Ahmed

--
Gurjeet Singh
EnterpriseDB <http://www.enterprisedb.com/&gt; Corporation
The Enterprise PostgreSQL <http://www.postgresql.org/&gt; Company

Attachments:

psql_ir.patch.gzapplication/x-gzip; name=psql_ir.patch.gzDownload
#5David Fetter
david@fetter.org
In reply to: Gurjeet Singh (#4)
Re: Fwd: psql include file using relative path

Being able to include relative paths is a really great feature, but
should it have a UI (well, API) distinct from fixed-path includes? My
first instinct is that it shouldn't, but I haven't really thought it
through thoroughly.

Cheers,
David (the tough coughs as he ploughs the dough)
On Tue, Mar 08, 2011 at 03:19:40PM -0500, Gurjeet Singh wrote:

Attached patch implements tab completion. It also introduces the long-form
alternative \include_relative for \ir

Regards,

On Tue, Mar 8, 2011 at 2:18 PM, Ibrar Ahmed <ibrar.ahmad@gmail.com> wrote:

Gurjeet!

What about tab completion, like in \i command?

On Fri, Feb 25, 2011 at 5:07 AM, Robert Haas <robertmhaas@gmail.com>
wrote:

On Thu, Feb 24, 2011 at 6:21 PM, Gurjeet Singh <singh.gurjeet@gmail.com>

wrote:

psql has the ability to execute commands from a file, but if one

wishes

to develop and provide a modularized set of sql files, then psql is not

very

helpful because the \i command can open file paths either if they are
absolute paths or if they are palced correctly relative to psql's

current

working directory.

Attached patch adds a new meta-command to psql, '\ir' that allows the

user

to process files relative to currently processing file.

Please add this patch to the currently open CommitFest at:

https://commitfest.postgresql.org/action/commitfest_view/open

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

--
Ibrar Ahmed

--
Gurjeet Singh
EnterpriseDB <http://www.enterprisedb.com/&gt; Corporation
The Enterprise PostgreSQL <http://www.postgresql.org/&gt; Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

--
David Fetter <david@fetter.org> http://fetter.org/
Phone: +1 415 235 3778 AIM: dfetter666 Yahoo!: dfetter
Skype: davidfetter XMPP: david.fetter@gmail.com
iCal: webcal://www.tripit.com/feed/ical/people/david74/tripit.ics

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate

#6Gurjeet Singh
singh.gurjeet@gmail.com
In reply to: David Fetter (#5)
Re: Fwd: psql include file using relative path

Good question, I hadn't thought of that either, and thinking about it a bit
I think we'd want to keep the current behaviour of \i and provide new
behaviour using a new command.

Say when we are processing a pretty nested file after multiple \ir commands,
a \i <relative path file> in any of those files should look for that file in
psql's CWD/PWD. That is what the user expects from \i command currently and
I don't think it'd be desirable to break that assumption.

Regards,

On Wed, Mar 9, 2011 at 4:41 PM, David Fetter <david@fetter.org> wrote:

Being able to include relative paths is a really great feature, but
should it have a UI (well, API) distinct from fixed-path includes? My
first instinct is that it shouldn't, but I haven't really thought it
through thoroughly.

Cheers,
David (the tough coughs as he ploughs the dough)
On Tue, Mar 08, 2011 at 03:19:40PM -0500, Gurjeet Singh wrote:

Attached patch implements tab completion. It also introduces the

long-form

alternative \include_relative for \ir

Regards,

On Tue, Mar 8, 2011 at 2:18 PM, Ibrar Ahmed <ibrar.ahmad@gmail.com>

wrote:

Gurjeet!

What about tab completion, like in \i command?

On Fri, Feb 25, 2011 at 5:07 AM, Robert Haas <robertmhaas@gmail.com>
wrote:

On Thu, Feb 24, 2011 at 6:21 PM, Gurjeet Singh <

singh.gurjeet@gmail.com>

wrote:

psql has the ability to execute commands from a file, but if one

wishes

to develop and provide a modularized set of sql files, then psql is

not

very

helpful because the \i command can open file paths either if they

are

absolute paths or if they are palced correctly relative to psql's

current

working directory.

Attached patch adds a new meta-command to psql, '\ir' that allows

the

user

to process files relative to currently processing file.

Please add this patch to the currently open CommitFest at:

https://commitfest.postgresql.org/action/commitfest_view/open

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

--
Ibrar Ahmed

--
Gurjeet Singh
EnterpriseDB <http://www.enterprisedb.com/&gt; Corporation
The Enterprise PostgreSQL <http://www.postgresql.org/&gt; Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

--
David Fetter <david@fetter.org> http://fetter.org/
Phone: +1 415 235 3778 AIM: dfetter666 Yahoo!: dfetter
Skype: davidfetter XMPP: david.fetter@gmail.com
iCal: webcal://www.tripit.com/feed/ical/people/david74/tripit.ics

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate

--
Gurjeet Singh
EnterpriseDB <http://www.enterprisedb.com/&gt; Corporation
The Enterprise PostgreSQL <http://www.postgresql.org/&gt; Company

#7David Fetter
david@fetter.org
In reply to: Gurjeet Singh (#6)
Re: Fwd: psql include file using relative path

On Wed, Mar 09, 2011 at 07:05:19PM -0500, Gurjeet Singh wrote:

Good question, I hadn't thought of that either, and thinking about
it a bit I think we'd want to keep the current behaviour of \i and
provide new behaviour using a new command.

Say when we are processing a pretty nested file after multiple \ir
commands, a \i <relative path file> in any of those files should
look for that file in psql's CWD/PWD. That is what the user expects
from \i command currently and I don't think it'd be desirable to
break that assumption.

I'm not sure I understand. Stuff that worked before would still work.

Should stuff break when it has a legitimately accessible path in it
just because that path is relative?

Cheers,
David.
--
David Fetter <david@fetter.org> http://fetter.org/
Phone: +1 415 235 3778 AIM: dfetter666 Yahoo!: dfetter
Skype: davidfetter XMPP: david.fetter@gmail.com
iCal: webcal://www.tripit.com/feed/ical/people/david74/tripit.ics

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate

#8Gurjeet Singh
singh.gurjeet@gmail.com
In reply to: David Fetter (#7)
Re: Fwd: psql include file using relative path

On Wed, Mar 9, 2011 at 7:32 PM, David Fetter <david@fetter.org> wrote:

On Wed, Mar 09, 2011 at 07:05:19PM -0500, Gurjeet Singh wrote:

Good question, I hadn't thought of that either, and thinking about
it a bit I think we'd want to keep the current behaviour of \i and
provide new behaviour using a new command.

Say when we are processing a pretty nested file after multiple \ir
commands, a \i <relative path file> in any of those files should
look for that file in psql's CWD/PWD. That is what the user expects
from \i command currently and I don't think it'd be desirable to
break that assumption.

I'm not sure I understand. Stuff that worked before would still work.

files present:
~/1.sql
~/package/main.sql
~/package/1.sql

psql's CWD: $HOME
psql executed as: psql -f ~/package/main.sql

Now if we kept \i and \ir separate then if main.sql does

\i 1.sql

it'd read ~/1.sql, which is the current behaviour,

and

\ir 1.sql

would read ~/package/1.sql .

If we folded \ir into \i then what would you want `\i 1.sql` to do? Read
1.sql from $HOME or the one that is main.sql's sibling.

Should stuff break when it has a legitimately accessible path in it
just because that path is relative?

Given the above test case, I think it'd be best if we introduced a new
command for this feature.

Regards,
--
Gurjeet Singh
EnterpriseDB <http://www.enterprisedb.com/&gt; Corporation
The Enterprise PostgreSQL <http://www.postgresql.org/&gt; Company

#9Andrew Dunstan
andrew@dunslane.net
In reply to: Gurjeet Singh (#8)
Re: Fwd: psql include file using relative path

On 03/09/2011 09:36 PM, Gurjeet Singh wrote:

If we folded \ir into \i then what would you want `\i 1.sql` to do?
Read 1.sql from $HOME or the one that is main.sql's sibling.

Should stuff break when it has a legitimately accessible path in it
just because that path is relative?

Given the above test case, I think it'd be best if we introduced a new
command for this feature.

I agree there's a good case for the new feature. I think someone
mentioned tab completion upthread, and that doesn't make so much sense
to me. This only makes sense nested in a script - in fact if it's not
called from inside an included script (via -f or \i) it should possibly
error out (if it already does this I apologise - I haven't looked at the
patch).

cheers

andrew

#10Gurjeet Singh
singh.gurjeet@gmail.com
In reply to: Andrew Dunstan (#9)
Re: Fwd: psql include file using relative path

On Wed, Mar 9, 2011 at 10:07 PM, Andrew Dunstan <andrew@dunslane.net> wrote:

I agree there's a good case for the new feature. I think someone mentioned
tab completion upthread, and that doesn't make so much sense to me. This
only makes sense nested in a script - in fact if it's not called from inside
an included script (via -f or \i) it should possibly error out (if it
already does this I apologise - I haven't looked at the patch).

I think \ir can stand on its own. In the patch, the \ir command falls back
to \i behaviour if there's no file being processed currently. So, I think
tab-completion makes sense for this command. And if someone wishes they can
stop using \i altogether and \ir will give them old and new bheaviour
seamlessly.

Regards,
--
Gurjeet Singh
EnterpriseDB <http://www.enterprisedb.com/&gt; Corporation
The Enterprise PostgreSQL <http://www.postgresql.org/&gt; Company

#11Robert Haas
robertmhaas@gmail.com
In reply to: David Fetter (#7)
Re: Fwd: psql include file using relative path

On Wed, Mar 9, 2011 at 7:32 PM, David Fetter <david@fetter.org> wrote:

On Wed, Mar 09, 2011 at 07:05:19PM -0500, Gurjeet Singh wrote:

Good question, I hadn't thought of that either, and thinking about
it a bit I think we'd want to keep the current behaviour of \i and
provide new behaviour using a new command.

Say when we are processing a pretty nested file after multiple \ir
commands, a \i <relative path file> in any of those files should
look for that file in psql's CWD/PWD. That is what the user expects
from \i command currently and I don't think it'd be desirable to
break that assumption.

I'm not sure I understand.  Stuff that worked before would still work.

Should stuff break when it has a legitimately accessible path in it
just because that path is relative?

You're confused. The point is whether the path is relative to PWD or
to the directory in which the currently executing script is located.
If you want to allow people to get either interpretation, you need two
commands.

In interactive use, I believe there's no difference between the two.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#12David Fetter
david@fetter.org
In reply to: Robert Haas (#11)
Re: Fwd: psql include file using relative path

On Wed, Mar 09, 2011 at 10:57:53PM -0500, Robert Haas wrote:

On Wed, Mar 9, 2011 at 7:32 PM, David Fetter <david@fetter.org> wrote:

On Wed, Mar 09, 2011 at 07:05:19PM -0500, Gurjeet Singh wrote:

Good question, I hadn't thought of that either, and thinking
about it a bit I think we'd want to keep the current behaviour of
\i and provide new behaviour using a new command.

Say when we are processing a pretty nested file after multiple
\ir commands, a \i <relative path file> in any of those files
should look for that file in psql's CWD/PWD. That is what the
user expects from \i command currently and I don't think it'd be
desirable to break that assumption.

I'm not sure I understand. �Stuff that worked before would still
work.

Should stuff break when it has a legitimately accessible path in
it just because that path is relative?

You're confused. The point is whether the path is relative to PWD
or to the directory in which the currently executing script is
located. If you want to allow people to get either interpretation,
you need two commands.

In interactive use, I believe there's no difference between the two.

Thanks for clearing that up :)

OK, nothing to see here. Move along ;)

Cheers,
David.
--
David Fetter <david@fetter.org> http://fetter.org/
Phone: +1 415 235 3778 AIM: dfetter666 Yahoo!: dfetter
Skype: davidfetter XMPP: david.fetter@gmail.com
iCal: webcal://www.tripit.com/feed/ical/people/david74/tripit.ics

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate