proposal: multiple psql option -c
Hi
can we support multiple "-c" option?
Why? Because some statements like VACUUM cannot be used together with any
other statements with single -c option. The current solution is using echo
and pipe op, but it is a complication in some complex scripts - higher
complication when you run psql via multiple sudo statement.
Example:
psql -c "select pg_stat_reset()" -c "vacuum full analyze" dbname
or on all db
psql -At -c "select datname from pg_databases" postgres | \
xargs -n 1 -P 3 psql -c "..." -c "..."
Ideas, notes, comments?
Regards
Pavel
On Thu, Jul 16, 2015 at 4:42 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:
Hi
can we support multiple "-c" option?
Why? Because some statements like VACUUM cannot be used together with any
other statements with single -c option. The current solution is using echo
and pipe op, but it is a complication in some complex scripts - higher
complication when you run psql via multiple sudo statement.
Example:
psql -c "select pg_stat_reset()" -c "vacuum full analyze" dbname
or on all db
psql -At -c "select datname from pg_databases" postgres | \
xargs -n 1 -P 3 psql -c "..." -c "..."Ideas, notes, comments?
Why you want it if we already have the -f option that cover this use case?
Regards,
--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL
Show quoted text
Timbira: http://www.timbira.com.br
Blog: http://fabriziomello.github.io
Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello
Github: http://github.com/fabriziomello
2015-07-16 22:07 GMT+02:00 Fabrízio de Royes Mello <fabriziomello@gmail.com>
:
On Thu, Jul 16, 2015 at 4:42 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:Hi
can we support multiple "-c" option?
Why? Because some statements like VACUUM cannot be used together with
any other statements with single -c option. The current solution is using
echo and pipe op, but it is a complication in some complex scripts - higher
complication when you run psql via multiple sudo statement.Example:
psql -c "select pg_stat_reset()" -c "vacuum full analyze" dbname
or on all db
psql -At -c "select datname from pg_databases" postgres | \
xargs -n 1 -P 3 psql -c "..." -c "..."Ideas, notes, comments?
Why you want it if we already have the -f option that cover this use case?
It doesn't help me - we would to run script or remote script (via ssh)
without necessity to create (and later drop) files on production servers.
remote execution of scripts is much more simple if you don't need to create
any script files.
Regards
Pavel
Show quoted text
Regards,
--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQLTimbira: http://www.timbira.com.br
Blog: http://fabriziomello.github.io
Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello
Github: http://github.com/fabriziomello
On Thu, Jul 16, 2015 at 1:44 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:
2015-07-16 22:07 GMT+02:00 Fabrízio de Royes Mello <
fabriziomello@gmail.com>:Why you want it if we already have the -f option that cover this use case?
It doesn't help me - we would to run script or remote script (via ssh)
without necessity to create (and later drop) files on production servers.
Does piping a series of commands into psql work in your scenario? You can
even say things like:
cat $local_file | ssh $production_server 'psql $database'
--
:wq
2015-07-16 23:10 GMT+02:00 Rosser Schwarz <rosser.schwarz@gmail.com>:
On Thu, Jul 16, 2015 at 1:44 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:2015-07-16 22:07 GMT+02:00 Fabrízio de Royes Mello <
fabriziomello@gmail.com>:Why you want it if we already have the -f option that cover this use
case?It doesn't help me - we would to run script or remote script (via ssh)
without necessity to create (and later drop) files on production servers.Does piping a series of commands into psql work in your scenario? You can
even say things like:cat $local_file | ssh $production_server 'psql $database'
probably not - the first remote command is sudo su - due security reasons
Show quoted text
--
:wq
On Thu, Jul 16, 2015 at 12:42 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:
Hi
can we support multiple "-c" option?
Why? Because some statements like VACUUM cannot be used together with any
other statements with single -c option. The current solution is using echo
and pipe op, but it is a complication in some complex scripts - higher
complication when you run psql via multiple sudo statement.Example:
psql -c "select pg_stat_reset()" -c "vacuum full analyze" dbname
or on all db
psql -At -c "select datname from pg_databases" postgres | \
xargs -n 1 -P 3 psql -c "..." -c "..."Ideas, notes, comments?
IMO, rather having multiple -c args, it would be good to have another flag
like "-C" which do accept and execute multiple SQL statements in sequential.
Best Regards,
Dinesh
manojadinesh.blogspot.com
Show quoted text
Regards
Pavel
2015-07-17 0:03 GMT+02:00 dinesh kumar <dineshkumar02@gmail.com>:
On Thu, Jul 16, 2015 at 12:42 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:Hi
can we support multiple "-c" option?
Why? Because some statements like VACUUM cannot be used together with any
other statements with single -c option. The current solution is using echo
and pipe op, but it is a complication in some complex scripts - higher
complication when you run psql via multiple sudo statement.Example:
psql -c "select pg_stat_reset()" -c "vacuum full analyze" dbname
or on all db
psql -At -c "select datname from pg_databases" postgres | \
xargs -n 1 -P 3 psql -c "..." -c "..."Ideas, notes, comments?
IMO, rather having multiple -c args, it would be good to have another flag
like "-C" which do accept and execute multiple SQL statements in sequential.
it is one possible solution too
multiple -c option has advantage of simple evaluation of backslash
statements .. -c "\l" -c "\dt" - but this advantage is not high important.
Pavel
Show quoted text
Best Regards,
Dinesh
manojadinesh.blogspot.comRegards
Pavel
it is one possible solution too
multiple -c option has advantage of simple evaluation of backslash
statements .. -c "\l" -c "\dt" - but this advantage is not high important.
Or just properly understand the ; ?
-c "select * from foo; update bar set baz = 'bing'; vacuum bar;"
JD
Pavel
Best Regards,
Dinesh
manojadinesh.blogspot.com <http://manojadinesh.blogspot.com>Regards
Pavel
--
Command Prompt, Inc. - http://www.commandprompt.com/ 503-667-4564
PostgreSQL Centered full stack support, consulting and development.
Announcing "I'm offended" is basically telling the world you can't
control your own emotions, so everyone else should do it for you.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2015-07-17 6:26 GMT+02:00 Joshua D. Drake <jd@commandprompt.com>:
it is one possible solution too
multiple -c option has advantage of simple evaluation of backslash
statements .. -c "\l" -c "\dt" - but this advantage is not high important.Or just properly understand the ; ?
-c "select * from foo; update bar set baz = 'bing'; vacuum bar;"
there is a risk of compatibility issues - all statements runs under one
transaction implicitly
Pavel
Show quoted text
JD
Pavel
Best Regards,
Dinesh
manojadinesh.blogspot.com <http://manojadinesh.blogspot.com>Regards
Pavel
--
Command Prompt, Inc. - http://www.commandprompt.com/ 503-667-4564
PostgreSQL Centered full stack support, consulting and development.
Announcing "I'm offended" is basically telling the world you can't
control your own emotions, so everyone else should do it for you.
On Thu, Jul 16, 2015 at 12:42 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
Hi
can we support multiple "-c" option?
Why? Because some statements like VACUUM cannot be used together with any other statements with single -c option. The current solution is using echo and pipe op, but it is a complication in some complex scripts - higher complication when you run psql via multiple sudo statement.
Example:
psql -c "select pg_stat_reset()" -c "vacuum full analyze" dbname
or on all db
psql -At -c "select datname from pg_databases" postgres | \
xargs -n 1 -P 3 psql -c "..." -c "..."
Ideas, notes, comments?
Hi,
Can't you handle this with a script on the target server ?
I have this one due to a profile issue:
cat cicrunpsql.sh
#!/bin/sh
# set the isdbx environment before calling psql with the passed arguments.
# required for remote calls with ssh
#example
# cicrunpsql.sh -Uisdb3 -c "select1"
# ssh isdb3@localhost cicrunpsql.sh -Uisdb3 -c "select1"
# remote calls per ssh do not get the profile automatically...
. ~/.profile || exit 1
psql "$@"
On Fri, Jul 17, 2015 at 12:36 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
Or just properly understand the ; ?
-c "select * from foo; update bar set baz = 'bing'; vacuum bar;"
there is a risk of compatibility issues - all statements runs under one
transaction implicitly
So what?
--
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
2015-07-23 17:52 GMT+02:00 Robert Haas <robertmhaas@gmail.com>:
On Fri, Jul 17, 2015 at 12:36 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:Or just properly understand the ; ?
-c "select * from foo; update bar set baz = 'bing'; vacuum bar;"
there is a risk of compatibility issues - all statements runs under one
transaction implicitlySo what?
[pavel@dhcppc2 ~]$ psql -c "insert into x
values(txid_current()::text);insert into x values(txid_current()::text)"
postgres
INSERT 0 1
[pavel@dhcppc2 ~]$ psql postgres -c "select * from x"
a
------
1888
1888
(2 rows)
I would to run -c command in separate transactions (when option
--single-transaction is not used).
Then is possible run
-c "select pg_reset ...()" -c "vacuum analyze ..."
Regards
Pavel
p.s.
the state string "INSERT 0 1" is buggy probably
Show quoted text
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Saturday, July 25, 2015, Pavel Stehule <pavel.stehule@gmail.com> wrote:
2015-07-23 17:52 GMT+02:00 Robert Haas <robertmhaas@gmail.com>:
On Fri, Jul 17, 2015 at 12:36 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:Or just properly understand the ; ?
-c "select * from foo; update bar set baz = 'bing'; vacuum bar;"
there is a risk of compatibility issues - all statements runs under one
transaction implicitlySo what?
[pavel@dhcppc2 ~]$ psql -c "insert into x
values(txid_current()::text);insert into x values(txid_current()::text)"
postgres
INSERT 0 1
the state string "INSERT 0 1" is buggy probably
How do you figure? The last statement only inserted one record.
To that point would you expect each separate -c to output its results to
the console?
David J.
2015-07-25 10:33 GMT+02:00 David G. Johnston <david.g.johnston@gmail.com>:
On Saturday, July 25, 2015, Pavel Stehule <pavel.stehule@gmail.com> wrote:
2015-07-23 17:52 GMT+02:00 Robert Haas <robertmhaas@gmail.com>:
On Fri, Jul 17, 2015 at 12:36 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:Or just properly understand the ; ?
-c "select * from foo; update bar set baz = 'bing'; vacuum bar;"
there is a risk of compatibility issues - all statements runs under one
transaction implicitlySo what?
[pavel@dhcppc2 ~]$ psql -c "insert into x
values(txid_current()::text);insert into x values(txid_current()::text)"
postgres
INSERT 0 1
the state string "INSERT 0 1" is buggy probablyHow do you figure? The last statement only inserted one record.
I understand now, it consistent with current design. So from this view it
is not error.
To that point would you expect each separate -c to output its results to
the console?
It will be nice side effect, but my primary problem was a impossibility to
combine VACUUM and any other statement to one simple psql call.
Pavel
Show quoted text
David J.
On Sat, Jul 25, 2015 at 5:27 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
It will be nice side effect, but my primary problem was a impossibility to
combine VACUUM and any other statement to one simple psql call.
Seems like you can do that easily enough:
[rhaas pgsql]$ (echo 'SELECT 1;'; echo 'VACUUM;'; echo 'SELECT 2;') | psql
?column?
----------
1
(1 row)
VACUUM
?column?
----------
2
(1 row)
--
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
2015-07-27 20:32 GMT+02:00 Robert Haas <robertmhaas@gmail.com>:
On Sat, Jul 25, 2015 at 5:27 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:It will be nice side effect, but my primary problem was a impossibility
to
combine VACUUM and any other statement to one simple psql call.
Seems like you can do that easily enough:
[rhaas pgsql]$ (echo 'SELECT 1;'; echo 'VACUUM;'; echo 'SELECT 2;') | psql
?column?
----------
1
(1 row)VACUUM
?column?
----------
2
(1 row)
how I can do it with xargs?
Regards
Pavel
Show quoted text
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Mon, Jul 27, 2015 at 2:37 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
2015-07-27 20:32 GMT+02:00 Robert Haas <robertmhaas@gmail.com>:
On Sat, Jul 25, 2015 at 5:27 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:It will be nice side effect, but my primary problem was a impossibility
to
combine VACUUM and any other statement to one simple psql call.Seems like you can do that easily enough:
[rhaas pgsql]$ (echo 'SELECT 1;'; echo 'VACUUM;'; echo 'SELECT 2;') | psql
?column?
----------
1
(1 row)VACUUM
?column?
----------
2
(1 row)how I can do it with xargs?
I don't specifically what you're trying to do, but I bet it's not that hard.
--
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
2015-07-27 20:47 GMT+02:00 Robert Haas <robertmhaas@gmail.com>:
On Mon, Jul 27, 2015 at 2:37 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:2015-07-27 20:32 GMT+02:00 Robert Haas <robertmhaas@gmail.com>:
On Sat, Jul 25, 2015 at 5:27 AM, Pavel Stehule <pavel.stehule@gmail.com
wrote:
It will be nice side effect, but my primary problem was a
impossibility
to
combine VACUUM and any other statement to one simple psql call.Seems like you can do that easily enough:
[rhaas pgsql]$ (echo 'SELECT 1;'; echo 'VACUUM;'; echo 'SELECT 2;') |
psql
?column?
----------
1
(1 row)VACUUM
?column?
----------
2
(1 row)how I can do it with xargs?
I don't specifically what you're trying to do, but I bet it's not that
hard.
I am trying to run parallel execution
psql -At -c "select datname from pg_database" postgres | xargs -n 1 -P 3
psql -c "select current_database()"
Pavel
Show quoted text
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On 07/27/2015 02:53 PM, Pavel Stehule wrote:
I am trying to run parallel execution
psql -At -c "select datname from pg_database" postgres | xargs -n 1 -P
3 psql -c "select current_database()"
I don't think it's going to be a hugely important feature, but I don't
see a problem with creating a new option (-C seems fine) which would
have the same effect as if the arguments were contatenated into a file
which is then used with -f. IIRC -c has some special characteristics
which means it's probably best not to try to extend it for this feature.
cheers
andrew
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Jul 27, 2015 at 2:53 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
I am trying to run parallel execution
psql -At -c "select datname from pg_database" postgres | xargs -n 1 -P 3
psql -c "select current_database()"
Put this in a shell script called run-psql:
#!/bin/bash
test $# = 0 && exit
for f in "${@:1:$(($#-1))}"; do
echo "$f" \;
done | psql "${@:$#}"
Then:
psql -At -c "select datname from pg_database" postgres | xargs -n 1 -P
3 ./run-psql "select current_database()" "vacuum" "select 1"
--
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
On 7/27/15 2:57 PM, Andrew Dunstan wrote:
psql -At -c "select datname from pg_database" postgres | xargs -n 1 -P
3 psql -c "select current_database()"I don't think it's going to be a hugely important feature, but I don't
see a problem with creating a new option (-C seems fine) which would
have the same effect as if the arguments were contatenated into a file
which is then used with -f. IIRC -c has some special characteristics
which means it's probably best not to try to extend it for this feature.
+1. I've occasionally wanted this as well.
I'd also vote for -C returning every state string as well.
--
Jim Nasby, Data Architect, Blue Treble Consulting, Austin TX
Data in Trouble? Get it in Treble! http://BlueTreble.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2015-07-27 21:57 GMT+02:00 Andrew Dunstan <andrew@dunslane.net>:
On 07/27/2015 02:53 PM, Pavel Stehule wrote:
I am trying to run parallel execution
psql -At -c "select datname from pg_database" postgres | xargs -n 1 -P 3
psql -c "select current_database()"I don't think it's going to be a hugely important feature, but I don't see
a problem with creating a new option (-C seems fine) which would have the
same effect as if the arguments were contatenated into a file which is then
used with -f. IIRC -c has some special characteristics which means it's
probably best not to try to extend it for this feature.
ok, I'll try to write patch.
Pavel
Show quoted text
cheers
andrew
2015-07-28 5:24 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:
2015-07-27 21:57 GMT+02:00 Andrew Dunstan <andrew@dunslane.net>:
On 07/27/2015 02:53 PM, Pavel Stehule wrote:
I am trying to run parallel execution
psql -At -c "select datname from pg_database" postgres | xargs -n 1 -P 3
psql -c "select current_database()"I don't think it's going to be a hugely important feature, but I don't
see a problem with creating a new option (-C seems fine) which would have
the same effect as if the arguments were contatenated into a file which is
then used with -f. IIRC -c has some special characteristics which means
it's probably best not to try to extend it for this feature.ok, I'll try to write patch.
I have a question. Can be -C option multiple?
The SQL is without problem, but what about \x command?
postgres=# \dt \dn select 10;
No relations found.
List of schemas
┌──────┬───────┐
│ Name │ Owner │
╞══════╪═══════╡
└──────┴───────┘
(0 rows)
\dn: extra argument "10;" ignored
some like
psql -C "\dt \dn" -C "select 10"
It is looking better than psql -c "\dt \dn \n select 10"
Regards
Pavel
Show quoted text
Pavel
cheers
andrew
2015-07-28 5:24 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:
2015-07-27 21:57 GMT+02:00 Andrew Dunstan <andrew@dunslane.net>:
On 07/27/2015 02:53 PM, Pavel Stehule wrote:
I am trying to run parallel execution
psql -At -c "select datname from pg_database" postgres | xargs -n 1 -P 3 psql -c "select current_database()"
I don't think it's going to be a hugely important feature, but I don't see a problem with creating a new option (-C seems fine) which would have the same effect as if the arguments were contatenated into a file which is then used with -f. IIRC -c has some special characteristics which means it's probably best not to try to extend it for this feature.
ok, I'll try to write patch.
I have a question. Can be -C option multiple?
hello,
Have you thought of how to support -1 along with -C ?
handle the input as with -f
that is, -1 -C would be equivalent to -c
and
psql -1 -C "sql_1; sql_2;" -C "sql_3; sql_4;"
=> ?
BEGIN;
sql_1;
sql_2;
END;
BEGIN;
sql_3;
sql_4;
END;
thoughts ?
The same logic could be added to -f
although I see less advantages as with adding -C
psql -1 -f "file1, file2" -f "file3, file4"
regards,
Marc Mamin
2015-07-28 10:43 GMT+02:00 Marc Mamin <M.Mamin@intershop.de>:
2015-07-28 5:24 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:
2015-07-27 21:57 GMT+02:00 Andrew Dunstan <andrew@dunslane.net>:
On 07/27/2015 02:53 PM, Pavel Stehule wrote:
I am trying to run parallel execution
psql -At -c "select datname from pg_database" postgres |
xargs -n 1 -P 3 psql -c "select current_database()"
I don't think it's going to be a hugely important feature, but I
don't see a problem with creating a new option (-C seems fine) which would
have the same effect as if the arguments were contatenated into a file
which is then used with -f. IIRC -c has some special characteristics which
means it's probably best not to try to extend it for this feature.ok, I'll try to write patch.
I have a question. Can be -C option multiple?
hello,
Have you thought of how to support -1 along with -C ?handle the input as with -f
that is, -1 -C would be equivalent to -c
and
psql -1 -C "sql_1; sql_2;" -C "sql_3; sql_4;"=> ?
BEGIN;
sql_1;
sql_2;
END;BEGIN;
sql_3;
sql_4;
END;thoughts ?
"-1" option is global -, I expected so following steps are more natural
BEGIN
sql_1;
sql_2;
sql_3;
sql_4;
END;
Regards
pavel
Show quoted text
The same logic could be added to -f
although I see less advantages as with adding -Cpsql -1 -f "file1, file2" -f "file3, file4"
regards,
Marc Mamin
On 17 July 2015 at 03:42, Pavel Stehule <pavel.stehule@gmail.com> wrote:
Hi
can we support multiple "-c" option?
Why? Because some statements like VACUUM cannot be used together with any
other statements with single -c option. The current solution is using echo
and pipe op, but it is a complication in some complex scripts - higher
complication when you run psql via multiple sudo statement.Example:
psql -c "select pg_stat_reset()" -c "vacuum full analyze" dbname
I don't see the point. Taking your 'sudo' issue into account, just:
sudo -u postgres psql <'__END__'
select pg_stat_reset();
vacuum full analyze;
__END__
or
echo -e 'select pg_stat_reset()\n vacuum full analyze;' | sudo -u postgres psql
or, of course, just run two commands.
There are plenty of existing ways to do this. Personally I find -c
awkward due to the need to worry about shell quoting and tend to
prefer a quoted here-document lots of the time anyway.
--
Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2015-07-28 10:43 GMT+02:00 Marc Mamin <M.Mamin@intershop.de>:
2015-07-28 5:24 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:
2015-07-27 21:57 GMT+02:00 Andrew Dunstan <andrew@dunslane.net>:
On 07/27/2015 02:53 PM, Pavel Stehule wrote:
I am trying to run parallel execution
psql -At -c "select datname from pg_database" postgres | xargs -n 1 -P 3 psql -c "select current_database()"
I don't think it's going to be a hugely important feature, but I don't see a problem with creating a new option (-C seems fine) which would have the same effect as if the arguments were contatenated into a file which is then used with -f. IIRC -c has some special characteristics which means it's probably best not to try to extend it for this feature.
ok, I'll try to write patch.
I have a question. Can be -C option multiple?
hello,
Have you thought of how to support -1 along with -C ?handle the input as with -f
that is, -1 -C would be equivalent to -c
and
psql -1 -C "sql_1; sql_2;" -C "sql_3; sql_4;"=> ?
BEGIN;
sql_1;
sql_2;
END;BEGIN;
sql_3;
sql_4;
END;thoughts ?
"-1" option is global -, I expected so following steps are more natural
BEGIN
sql_1;
sql_2;
sql_3;
sql_4;
END;
This is then exactly the same as -c.
If introducing multiple -C to better manage transaction handling,
why not enrich this new feature with the abilities to define batches of transactions ?
Marc
On 07/28/2015 04:43 AM, Marc Mamin wrote:
2015-07-28 5:24 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:
2015-07-27 21:57 GMT+02:00 Andrew Dunstan <andrew@dunslane.net>:
On 07/27/2015 02:53 PM, Pavel Stehule wrote:
I am trying to run parallel execution
psql -At -c "select datname from pg_database" postgres |
xargs -n 1 -P 3 psql -c "select current_database()"
I don't think it's going to be a hugely important feature,
but I don't see a problem with creating a new option (-C seems fine)
which would have the same effect as if the arguments were contatenated
into a file which is then used with -f. IIRC -c has some special
characteristics which means it's probably best not to try to extend it
for this feature.ok, I'll try to write patch.
I have a question. Can be -C option multiple?
hello,
Have you thought of how to support -1 along with -C ?handle the input as with -f
that is, -1 -C would be equivalent to -c
and
psql -1 -C "sql_1; sql_2;" -C "sql_3; sql_4;"=> ?
BEGIN;
sql_1;
sql_2;
END;BEGIN;
sql_3;
sql_4;
END;thoughts ?
The same logic could be added to -f
although I see less advantages as with adding -Cpsql -1 -f "file1, file2" -f "file3, file4"
This is way too complex and baroque. -1 should be global. Multiple -C
options should be concatenated. -f should not be touched.
cheers
andrew
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 07/28/2015 12:08 AM, Pavel Stehule wrote:
2015-07-28 5:24 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com
<mailto:pavel.stehule@gmail.com>>:2015-07-27 21:57 GMT+02:00 Andrew Dunstan <andrew@dunslane.net
<mailto:andrew@dunslane.net>>:On 07/27/2015 02:53 PM, Pavel Stehule wrote:
I am trying to run parallel execution
psql -At -c "select datname from pg_database" postgres |
xargs -n 1 -P 3 psql -c "select current_database()"I don't think it's going to be a hugely important feature, but
I don't see a problem with creating a new option (-C seems
fine) which would have the same effect as if the arguments
were contatenated into a file which is then used with -f. IIRC
-c has some special characteristics which means it's probably
best not to try to extend it for this feature.ok, I'll try to write patch.
I have a question. Can be -C option multiple?
The SQL is without problem, but what about \x command?
postgres=# \dt \dn select 10;
No relations found.
List of schemas
┌──────┬───────┐
│ Name │ Owner │
╞══════╪═══════╡
└──────┴───────┘
(0 rows)\dn: extra argument "10;" ignored
I don't understand the question.
You should include one sql or psql command per -C option, ISTM. e.g.
psql -C '\dt' -C '\dn' -C 'select 10;'
Isn't that what we're talking about with this whole proposal?
cheers
andrew
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2015-07-28 15:16 GMT+02:00 Andrew Dunstan <andrew@dunslane.net>:
On 07/28/2015 12:08 AM, Pavel Stehule wrote:
2015-07-28 5:24 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com <mailto:
pavel.stehule@gmail.com>>:2015-07-27 21:57 GMT+02:00 Andrew Dunstan <andrew@dunslane.net
<mailto:andrew@dunslane.net>>:On 07/27/2015 02:53 PM, Pavel Stehule wrote:
I am trying to run parallel execution
psql -At -c "select datname from pg_database" postgres |
xargs -n 1 -P 3 psql -c "select current_database()"I don't think it's going to be a hugely important feature, but
I don't see a problem with creating a new option (-C seems
fine) which would have the same effect as if the arguments
were contatenated into a file which is then used with -f. IIRC
-c has some special characteristics which means it's probably
best not to try to extend it for this feature.ok, I'll try to write patch.
I have a question. Can be -C option multiple?
The SQL is without problem, but what about \x command?
postgres=# \dt \dn select 10;
No relations found.
List of schemas
┌──────┬───────┐
│ Name │ Owner │
╞══════╪═══════╡
└──────┴───────┘
(0 rows)\dn: extra argument "10;" ignored
I don't understand the question.
You should include one sql or psql command per -C option, ISTM. e.g.
psql -C '\dt' -C '\dn' -C 'select 10;'
Isn't that what we're talking about with this whole proposal?
I am searching some agreement, how to solve a current "-c" limits. I am
100% for >>> psql -C '\dt' -C '\dn' -C 'select 10;' <<<
Regards
Pavel
Show quoted text
cheers
andrew
On 07/28/2015 11:52 AM, Pavel Stehule wrote:
2015-07-28 15:16 GMT+02:00 Andrew Dunstan <andrew@dunslane.net
<mailto:andrew@dunslane.net>>:On 07/28/2015 12:08 AM, Pavel Stehule wrote:
2015-07-28 5:24 GMT+02:00 Pavel Stehule
<pavel.stehule@gmail.com <mailto:pavel.stehule@gmail.com>
<mailto:pavel.stehule@gmail.com
<mailto:pavel.stehule@gmail.com>>>:2015-07-27 21:57 GMT+02:00 Andrew Dunstan
<andrew@dunslane.net <mailto:andrew@dunslane.net>
<mailto:andrew@dunslane.net <mailto:andrew@dunslane.net>>>:On 07/27/2015 02:53 PM, Pavel Stehule wrote:
I am trying to run parallel execution
psql -At -c "select datname from pg_database"
postgres |
xargs -n 1 -P 3 psql -c "select current_database()"I don't think it's going to be a hugely important
feature, but
I don't see a problem with creating a new option (-C seems
fine) which would have the same effect as if the arguments
were contatenated into a file which is then used with
-f. IIRC
-c has some special characteristics which means it's
probably
best not to try to extend it for this feature.ok, I'll try to write patch.
I have a question. Can be -C option multiple?
The SQL is without problem, but what about \x command?
postgres=# \dt \dn select 10;
No relations found.
List of schemas
┌──────┬───────┐
│ Name │ Owner │
╞══════╪═══════╡
└──────┴───────┘
(0 rows)\dn: extra argument "10;" ignored
I don't understand the question.
You should include one sql or psql command per -C option, ISTM. e.g.
psql -C '\dt' -C '\dn' -C 'select 10;'
Isn't that what we're talking about with this whole proposal?
I am searching some agreement, how to solve a current "-c" limits. I
am 100% for >>> psql -C '\dt' -C '\dn' -C 'select 10;' <<<
I think you're probably best off leaving -c alone. If there are issues
to be solved for -c they should be handled separately from the feature
we agree on.
cheers
andrew
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi
here is proof concept patch
It should be cleaned, but it demonstrates a work well
[pavel@localhost psql]$ ./psql -C 'select 10 x; select 20 y;' -C "\l"
postgres
x
----
10
(1 row)
y
----
20
(1 row)
List of databases
Name | Owner | Encoding | Collate | Ctype | Access
privileges
-----------+----------+----------+-------------+-------------+-----------------------
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
=c/postgres +
| | | | |
postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
=c/postgres +
| | | | |
postgres=CTc/postgres
(3 rows)
2015-07-28 18:46 GMT+02:00 Andrew Dunstan <andrew@dunslane.net>:
Show quoted text
On 07/28/2015 11:52 AM, Pavel Stehule wrote:
2015-07-28 15:16 GMT+02:00 Andrew Dunstan <andrew@dunslane.net <mailto:
andrew@dunslane.net>>:On 07/28/2015 12:08 AM, Pavel Stehule wrote:
2015-07-28 5:24 GMT+02:00 Pavel Stehule
<pavel.stehule@gmail.com <mailto:pavel.stehule@gmail.com>
<mailto:pavel.stehule@gmail.com
<mailto:pavel.stehule@gmail.com>>>:2015-07-27 21:57 GMT+02:00 Andrew Dunstan
<andrew@dunslane.net <mailto:andrew@dunslane.net>
<mailto:andrew@dunslane.net <mailto:andrew@dunslane.net>>>:On 07/27/2015 02:53 PM, Pavel Stehule wrote:
I am trying to run parallel execution
psql -At -c "select datname from pg_database"
postgres |
xargs -n 1 -P 3 psql -c "select current_database()"I don't think it's going to be a hugely important
feature, but
I don't see a problem with creating a new option (-C seems
fine) which would have the same effect as if the arguments
were contatenated into a file which is then used with
-f. IIRC
-c has some special characteristics which means it's
probably
best not to try to extend it for this feature.ok, I'll try to write patch.
I have a question. Can be -C option multiple?
The SQL is without problem, but what about \x command?
postgres=# \dt \dn select 10;
No relations found.
List of schemas
┌──────┬───────┐
│ Name │ Owner │
╞══════╪═══════╡
└──────┴───────┘
(0 rows)\dn: extra argument "10;" ignored
I don't understand the question.
You should include one sql or psql command per -C option, ISTM. e.g.
psql -C '\dt' -C '\dn' -C 'select 10;'
Isn't that what we're talking about with this whole proposal?
I am searching some agreement, how to solve a current "-c" limits. I am
100% for >>> psql -C '\dt' -C '\dn' -C 'select 10;' <<<I think you're probably best off leaving -c alone. If there are issues to
be solved for -c they should be handled separately from the feature we
agree on.cheers
andrew
Attachments:
psql.patchtext/x-patch; charset=US-ASCII; name=psql.patchDownload
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
new file mode 100644
index b6cef94..bfd5bf5
*** a/src/bin/psql/mainloop.c
--- b/src/bin/psql/mainloop.c
*************** MainLoop(FILE *source)
*** 43,48 ****
--- 43,49 ----
volatile promptStatus_t prompt_status = PROMPT_READY;
volatile int count_eof = 0;
volatile bool die_on_error = false;
+ Commands *cmd = pset.commands;
/* Save the prior command source */
FILE *prev_cmd_source;
*************** MainLoop(FILE *source)
*** 135,140 ****
--- 136,156 ----
prompt_status = PROMPT_READY;
line = gets_interactive(get_prompt(prompt_status));
}
+ else if (pset.commands != NULL)
+ {
+ pset.cur_cmd_interactive = false;
+
+ if (cmd != NULL)
+ {
+ line = cmd->actions;
+ cmd = cmd->next;
+ }
+ else
+ {
+ successResult = EXIT_SUCCESS;
+ break;
+ }
+ }
else
{
line = gets_fromFile(source);
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
new file mode 100644
index d34dc28..46d2a81
*** a/src/bin/psql/settings.h
--- b/src/bin/psql/settings.h
*************** enum trivalue
*** 77,82 ****
--- 77,88 ----
TRI_YES
};
+ typedef struct _Commands
+ {
+ char *actions;
+ struct _Commands *next;
+ } Commands;
+
typedef struct _psqlSettings
{
PGconn *db; /* connection to backend */
*************** typedef struct _psqlSettings
*** 129,134 ****
--- 135,141 ----
const char *prompt2;
const char *prompt3;
PGVerbosity verbosity; /* current error verbosity level */
+ Commands *commands;
} PsqlSettings;
extern PsqlSettings pset;
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
new file mode 100644
index 28ba75a..cbceb91
*** a/src/bin/psql/startup.c
--- b/src/bin/psql/startup.c
*************** enum _actions
*** 54,60 ****
ACT_SINGLE_SLASH,
ACT_LIST_DB,
ACT_SINGLE_QUERY,
! ACT_FILE
};
struct adhoc_opts
--- 54,61 ----
ACT_SINGLE_SLASH,
ACT_LIST_DB,
ACT_SINGLE_QUERY,
! ACT_FILE,
! ACT_COMMANDS
};
struct adhoc_opts
*************** main(int argc, char *argv[])
*** 158,163 ****
--- 159,166 ----
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
+ pset.commands = NULL;
+
parse_psql_options(argc, argv, &options);
/*
*************** main(int argc, char *argv[])
*** 326,331 ****
--- 329,340 ----
? EXIT_SUCCESS : EXIT_FAILURE;
}
+ else if (options.action == ACT_COMMANDS)
+ {
+ pset.notty = true;
+ successResult = MainLoop(stdin);
+ }
+
/*
* or otherwise enter interactive main loop
*/
*************** parse_psql_options(int argc, char *argv[
*** 403,409 ****
memset(options, 0, sizeof *options);
! while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
long_options, &optindex)) != -1)
{
switch (c)
--- 412,418 ----
memset(options, 0, sizeof *options);
! while ((c = getopt_long(argc, argv, "aAbc:C:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
long_options, &optindex)) != -1)
{
switch (c)
*************** parse_psql_options(int argc, char *argv[
*** 427,432 ****
--- 436,460 ----
else
options->action = ACT_SINGLE_QUERY;
break;
+ case 'C':
+ {
+ Commands *cmd = pg_malloc(sizeof(Commands));
+ Commands *ptr = pset.commands;
+
+ if (ptr == NULL)
+ pset.commands = cmd;
+ else
+ {
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = cmd;
+ }
+ cmd->next = NULL;
+ cmd->actions = pg_strdup(optarg);
+ options->action = ACT_COMMANDS;
+ }
+ break;
case 'd':
options->dbname = pg_strdup(optarg);
break;
Hi
2015-07-29 21:05 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:
Hi
here is proof concept patch
It should be cleaned, but it demonstrates a work well
[pavel@localhost psql]$ ./psql -C 'select 10 x; select 20 y;' -C "\l"
postgres
x
----
10
(1 row)y
----
20
(1 row)List of databases
Name | Owner | Encoding | Collate | Ctype | Access
privileges-----------+----------+----------+-------------+-------------+-----------------------
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
=c/postgres +
| | | | |
postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
=c/postgres +
| | | | |
postgres=CTc/postgres
(3 rows)2015-07-28 18:46 GMT+02:00 Andrew Dunstan <andrew@dunslane.net>:
On 07/28/2015 11:52 AM, Pavel Stehule wrote:
2015-07-28 15:16 GMT+02:00 Andrew Dunstan <andrew@dunslane.net <mailto:
andrew@dunslane.net>>:On 07/28/2015 12:08 AM, Pavel Stehule wrote:
2015-07-28 5:24 GMT+02:00 Pavel Stehule
<pavel.stehule@gmail.com <mailto:pavel.stehule@gmail.com>
<mailto:pavel.stehule@gmail.com
<mailto:pavel.stehule@gmail.com>>>:2015-07-27 21:57 GMT+02:00 Andrew Dunstan
<andrew@dunslane.net <mailto:andrew@dunslane.net>
<mailto:andrew@dunslane.net <mailto:andrew@dunslane.net>>>:On 07/27/2015 02:53 PM, Pavel Stehule wrote:
I am trying to run parallel execution
psql -At -c "select datname from pg_database"
postgres |
xargs -n 1 -P 3 psql -c "select current_database()"I don't think it's going to be a hugely important
feature, but
I don't see a problem with creating a new option (-C
seems
fine) which would have the same effect as if the
arguments
were contatenated into a file which is then used with
-f. IIRC
-c has some special characteristics which means it's
probably
best not to try to extend it for this feature.ok, I'll try to write patch.
I have a question. Can be -C option multiple?
The SQL is without problem, but what about \x command?
postgres=# \dt \dn select 10;
No relations found.
List of schemas
┌──────┬───────┐
│ Name │ Owner │
╞══════╪═══════╡
└──────┴───────┘
(0 rows)\dn: extra argument "10;" ignored
I don't understand the question.
You should include one sql or psql command per -C option, ISTM. e.g.
psql -C '\dt' -C '\dn' -C 'select 10;'
Isn't that what we're talking about with this whole proposal?
I am searching some agreement, how to solve a current "-c" limits. I am
100% for >>> psql -C '\dt' -C '\dn' -C 'select 10;' <<<I think you're probably best off leaving -c alone. If there are issues to
be solved for -c they should be handled separately from the feature we
agree on.cheers
andrew
here is finished patch - cleaned, tested - the significant change is using
-g --group-command instead "-C"
[pavel@localhost psql]$ ./psql postgres -g "select 10; select 20" -g
"select 30"
?column?
----------
10
(1 row)
?column?
----------
20
(1 row)
?column?
----------
30
(1 row)
Regards
Pavel
Attachments:
psql-group-command-01.patchtext/x-patch; charset=US-ASCII; name=psql-group-command-01.patchDownload
commit 9c71d3dbdc3b81f4f8535c93b69507fe5d9af897
Author: Pavel Stehule <pavel.stehule@gooddata.com>
Date: Wed Aug 26 13:03:56 2015 +0200
inital
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index f996865..750c4ae 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -223,6 +223,20 @@ EOF
</varlistentry>
<varlistentry>
+ <term><option>-g <replaceable class="parameter">command(s)</replaceable></></term>
+ <term><option>--group-command=<replaceable class="parameter">command(s)</replaceable></></term>
+ <listitem>
+ <para>
+ Specifies that <application>psql</application> is to execute one or
+ more command strings, <replaceable class="parameter">commands</replaceable>,
+ and then exit. This is useful in shell scripts. Start-up files
+ (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are
+ ignored with this option.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-h <replaceable class="parameter">hostname</replaceable></></term>
<term><option>--host=<replaceable class="parameter">hostname</replaceable></></term>
<listitem>
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index d3e3114..55aa423 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -79,6 +79,8 @@ usage(unsigned short int pager)
fprintf(output, _(" -c, --command=COMMAND run only single command (SQL or internal) and exit\n"));
fprintf(output, _(" -d, --dbname=DBNAME database name to connect to (default: \"%s\")\n"), env);
fprintf(output, _(" -f, --file=FILENAME execute commands from file, then exit\n"));
+ fprintf(output, _(" -g, --group-command=COMMAND\n"
+ " run more groups of commands (SQL or internal) and exit\n"));
fprintf(output, _(" -l, --list list available databases, then exit\n"));
fprintf(output, _(" -v, --set=, --variable=NAME=VALUE\n"
" set psql variable NAME to VALUE e.g.: -v ON_ERROR_STOP=1\n"));
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
index b6cef94..62db503 100644
--- a/src/bin/psql/mainloop.c
+++ b/src/bin/psql/mainloop.c
@@ -43,6 +43,7 @@ MainLoop(FILE *source)
volatile promptStatus_t prompt_status = PROMPT_READY;
volatile int count_eof = 0;
volatile bool die_on_error = false;
+ GroupCommand *cmd = pset.group_commands;
/* Save the prior command source */
FILE *prev_cmd_source;
@@ -135,6 +136,20 @@ MainLoop(FILE *source)
prompt_status = PROMPT_READY;
line = gets_interactive(get_prompt(prompt_status));
}
+ else if (pset.group_commands != NULL)
+ {
+ /* Is there some unprocessed group command? */
+ if (cmd != NULL)
+ {
+ line = cmd->actions;
+ cmd = cmd->next;
+ }
+ else
+ {
+ successResult = EXIT_SUCCESS;
+ break;
+ }
+ }
else
{
line = gets_fromFile(source);
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
index d34dc28..d23d67a 100644
--- a/src/bin/psql/settings.h
+++ b/src/bin/psql/settings.h
@@ -77,6 +77,12 @@ enum trivalue
TRI_YES
};
+typedef struct _GroupCommand
+{
+ char *actions;
+ struct _GroupCommand *next;
+} GroupCommand;
+
typedef struct _psqlSettings
{
PGconn *db; /* connection to backend */
@@ -129,6 +135,7 @@ typedef struct _psqlSettings
const char *prompt2;
const char *prompt3;
PGVerbosity verbosity; /* current error verbosity level */
+ GroupCommand *group_commands;
} PsqlSettings;
extern PsqlSettings pset;
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 28ba75a..9c3f91f 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -54,7 +54,8 @@ enum _actions
ACT_SINGLE_SLASH,
ACT_LIST_DB,
ACT_SINGLE_QUERY,
- ACT_FILE
+ ACT_FILE,
+ ACT_GROUP_COMMANDS
};
struct adhoc_opts
@@ -158,6 +159,8 @@ main(int argc, char *argv[])
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
+ pset.group_commands = NULL;
+
parse_psql_options(argc, argv, &options);
/*
@@ -326,6 +329,13 @@ main(int argc, char *argv[])
? EXIT_SUCCESS : EXIT_FAILURE;
}
+ else if (options.action == ACT_GROUP_COMMANDS)
+ {
+ pset.notty = true;
+ SetVariableBool(pset.vars, "SINGLELINE");
+ successResult = MainLoop(stdin);
+ }
+
/*
* or otherwise enter interactive main loop
*/
@@ -370,6 +380,7 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
{"file", required_argument, NULL, 'f'},
{"field-separator", required_argument, NULL, 'F'},
{"field-separator-zero", no_argument, NULL, 'z'},
+ {"group-command", required_argument, NULL, 'g'},
{"host", required_argument, NULL, 'h'},
{"html", no_argument, NULL, 'H'},
{"list", no_argument, NULL, 'l'},
@@ -401,9 +412,12 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
int optindex;
int c;
+ bool cmd_opt_is_used = false;
+ bool group_cmd_opt_is_used = false;
+
memset(options, 0, sizeof *options);
- while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
+ while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:g:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
long_options, &optindex)) != -1)
{
switch (c)
@@ -418,6 +432,8 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
SetVariable(pset.vars, "ECHO", "errors");
break;
case 'c':
+ cmd_opt_is_used = true;
+
options->action_string = pg_strdup(optarg);
if (optarg[0] == '\\')
{
@@ -444,6 +460,27 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
pset.popt.topt.fieldSep.separator_zero = false;
break;
+ case 'g':
+ {
+ GroupCommand *cmd = pg_malloc(sizeof(GroupCommand));
+ GroupCommand *ptr = pset.group_commands;
+
+ group_cmd_opt_is_used = true;
+
+ if (ptr == NULL)
+ pset.group_commands = cmd;
+ else
+ {
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = cmd;
+ }
+ cmd->next = NULL;
+ cmd->actions = pg_strdup(optarg);
+ options->action = ACT_GROUP_COMMANDS;
+ }
+ break;
case 'h':
options->host = pg_strdup(optarg);
break;
@@ -600,6 +637,13 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
}
}
+ if (cmd_opt_is_used && group_cmd_opt_is_used)
+ {
+ fprintf(stderr, _("%s: options -c/--command and -g/--group_command cannot be used together\n"),
+ pset.progname);
+ exit(EXIT_FAILURE);
+ }
+
/*
* if we still have arguments, use it as the database name and username
*/
other example related to using psql in pipeline
[pavel@localhost psql]$ ./psql postgres -q -g "vacuum analyze pg_attribute"
-g "\echo :DBNAME"
postgres
Hi
2015-08-26 13:12 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:
Hi
2015-07-29 21:05 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:
Hi
here is proof concept patch
It should be cleaned, but it demonstrates a work well
[pavel@localhost psql]$ ./psql -C 'select 10 x; select 20 y;' -C "\l"
postgres
x
----
10
(1 row)y
----
20
(1 row)List of databases
Name | Owner | Encoding | Collate | Ctype | Access
privileges-----------+----------+----------+-------------+-------------+-----------------------
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
=c/postgres +
| | | | |
postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
=c/postgres +
| | | | |
postgres=CTc/postgres
(3 rows)2015-07-28 18:46 GMT+02:00 Andrew Dunstan <andrew@dunslane.net>:
On 07/28/2015 11:52 AM, Pavel Stehule wrote:
2015-07-28 15:16 GMT+02:00 Andrew Dunstan <andrew@dunslane.net <mailto:
andrew@dunslane.net>>:On 07/28/2015 12:08 AM, Pavel Stehule wrote:
2015-07-28 5:24 GMT+02:00 Pavel Stehule
<pavel.stehule@gmail.com <mailto:pavel.stehule@gmail.com>
<mailto:pavel.stehule@gmail.com
<mailto:pavel.stehule@gmail.com>>>:2015-07-27 21:57 GMT+02:00 Andrew Dunstan
<andrew@dunslane.net <mailto:andrew@dunslane.net>
<mailto:andrew@dunslane.net <mailto:andrew@dunslane.net>>>:On 07/27/2015 02:53 PM, Pavel Stehule wrote:
I am trying to run parallel execution
psql -At -c "select datname from pg_database"
postgres |
xargs -n 1 -P 3 psql -c "select current_database()"I don't think it's going to be a hugely important
feature, but
I don't see a problem with creating a new option (-C
seems
fine) which would have the same effect as if the
arguments
were contatenated into a file which is then used with
-f. IIRC
-c has some special characteristics which means it's
probably
best not to try to extend it for this feature.ok, I'll try to write patch.
I have a question. Can be -C option multiple?
The SQL is without problem, but what about \x command?
postgres=# \dt \dn select 10;
No relations found.
List of schemas
┌──────┬───────┐
│ Name │ Owner │
╞══════╪═══════╡
└──────┴───────┘
(0 rows)\dn: extra argument "10;" ignored
I don't understand the question.
You should include one sql or psql command per -C option, ISTM. e.g.
psql -C '\dt' -C '\dn' -C 'select 10;'
Isn't that what we're talking about with this whole proposal?
I am searching some agreement, how to solve a current "-c" limits. I am
100% for >>> psql -C '\dt' -C '\dn' -C 'select 10;' <<<I think you're probably best off leaving -c alone. If there are issues
to be solved for -c they should be handled separately from the feature we
agree on.cheers
andrew
here is finished patch - cleaned, tested - the significant change is using
-g --group-command instead "-C"[pavel@localhost psql]$ ./psql postgres -g "select 10; select 20" -g
"select 30"
?column?
----------
10
(1 row)?column?
----------
20
(1 row)?column?
----------
30
(1 row)Regards
with -1 option support
Show quoted text
Pavel
Attachments:
psql-group-command-02.patchtext/x-patch; charset=US-ASCII; name=psql-group-command-02.patchDownload
commit bef661b7c822f4fe9f004bf55645a3e47e514bc8
Author: Pavel Stehule <pavel.stehule@gooddata.com>
Date: Wed Aug 26 13:03:56 2015 +0200
inital
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index f996865..750c4ae 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -223,6 +223,20 @@ EOF
</varlistentry>
<varlistentry>
+ <term><option>-g <replaceable class="parameter">command(s)</replaceable></></term>
+ <term><option>--group-command=<replaceable class="parameter">command(s)</replaceable></></term>
+ <listitem>
+ <para>
+ Specifies that <application>psql</application> is to execute one or
+ more command strings, <replaceable class="parameter">commands</replaceable>,
+ and then exit. This is useful in shell scripts. Start-up files
+ (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are
+ ignored with this option.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-h <replaceable class="parameter">hostname</replaceable></></term>
<term><option>--host=<replaceable class="parameter">hostname</replaceable></></term>
<listitem>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 6181a61..277e980 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -2292,7 +2292,6 @@ process_file(char *filename, bool single_txn, bool use_relative_path)
int result;
char *oldfilename;
char relpath[MAXPGPATH];
- PGresult *res;
if (!filename)
{
@@ -2337,37 +2336,8 @@ process_file(char *filename, bool single_txn, bool use_relative_path)
oldfilename = pset.inputfile;
pset.inputfile = filename;
- if (single_txn)
- {
- if ((res = PSQLexec("BEGIN")) == NULL)
- {
- if (pset.on_error_stop)
- {
- result = EXIT_USER;
- goto error;
- }
- }
- else
- PQclear(res);
- }
-
- result = MainLoop(fd);
+ result = MainLoop(fd, single_txn);
- if (single_txn)
- {
- if ((res = PSQLexec("COMMIT")) == NULL)
- {
- if (pset.on_error_stop)
- {
- result = EXIT_USER;
- goto error;
- }
- }
- else
- PQclear(res);
- }
-
-error:
if (fd != stdin)
fclose(fd);
@@ -2375,8 +2345,6 @@ error:
return result;
}
-
-
static const char *
_align2string(enum printFormat in)
{
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index d3e3114..55aa423 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -79,6 +79,8 @@ usage(unsigned short int pager)
fprintf(output, _(" -c, --command=COMMAND run only single command (SQL or internal) and exit\n"));
fprintf(output, _(" -d, --dbname=DBNAME database name to connect to (default: \"%s\")\n"), env);
fprintf(output, _(" -f, --file=FILENAME execute commands from file, then exit\n"));
+ fprintf(output, _(" -g, --group-command=COMMAND\n"
+ " run more groups of commands (SQL or internal) and exit\n"));
fprintf(output, _(" -l, --list list available databases, then exit\n"));
fprintf(output, _(" -v, --set=, --variable=NAME=VALUE\n"
" set psql variable NAME to VALUE e.g.: -v ON_ERROR_STOP=1\n"));
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
index b6cef94..4147238 100644
--- a/src/bin/psql/mainloop.c
+++ b/src/bin/psql/mainloop.c
@@ -24,8 +24,8 @@
* This loop is re-entrant. May be called by \i command
* which reads input from a file.
*/
-int
-MainLoop(FILE *source)
+static int
+_MainLoop(FILE *source)
{
PsqlScanState scan_state; /* lexer working state */
volatile PQExpBuffer query_buf; /* buffer for query being accumulated */
@@ -43,6 +43,7 @@ MainLoop(FILE *source)
volatile promptStatus_t prompt_status = PROMPT_READY;
volatile int count_eof = 0;
volatile bool die_on_error = false;
+ GroupCommand *cmd = pset.group_commands;
/* Save the prior command source */
FILE *prev_cmd_source;
@@ -135,6 +136,20 @@ MainLoop(FILE *source)
prompt_status = PROMPT_READY;
line = gets_interactive(get_prompt(prompt_status));
}
+ else if (pset.group_commands != NULL)
+ {
+ /* Is there some unprocessed group command? */
+ if (cmd != NULL)
+ {
+ line = cmd->actions;
+ cmd = cmd->next;
+ }
+ else
+ {
+ successResult = EXIT_SUCCESS;
+ break;
+ }
+ }
else
{
line = gets_fromFile(source);
@@ -451,6 +466,43 @@ MainLoop(FILE *source)
return successResult;
} /* MainLoop() */
+/*
+ * Transactional MainLoop
+ *
+ * allow to execute all statements in single transaction
+ */
+int
+MainLoop(FILE *source, bool single_txn)
+{
+ int result;
+ PGresult *res;
+
+ if (single_txn)
+ {
+ if ((res = PSQLexec("BEGIN")) == NULL)
+ {
+ if (pset.on_error_stop)
+ return EXIT_USER;
+ }
+ else
+ PQclear(res);
+ }
+
+ result = _MainLoop(source);
+
+ if (single_txn)
+ {
+ if ((res = PSQLexec("COMMIT")) == NULL)
+ {
+ if (pset.on_error_stop)
+ return EXIT_USER;
+ }
+ else
+ PQclear(res);
+ }
+
+ return result;
+}
/*
* psqlscan.c is #include'd here instead of being compiled on its own.
diff --git a/src/bin/psql/mainloop.h b/src/bin/psql/mainloop.h
index 8f1325c..53c9a11 100644
--- a/src/bin/psql/mainloop.h
+++ b/src/bin/psql/mainloop.h
@@ -10,6 +10,6 @@
#include "postgres_fe.h"
-int MainLoop(FILE *source);
+int MainLoop(FILE *source, bool single_txn);
#endif /* MAINLOOP_H */
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
index d34dc28..d23d67a 100644
--- a/src/bin/psql/settings.h
+++ b/src/bin/psql/settings.h
@@ -77,6 +77,12 @@ enum trivalue
TRI_YES
};
+typedef struct _GroupCommand
+{
+ char *actions;
+ struct _GroupCommand *next;
+} GroupCommand;
+
typedef struct _psqlSettings
{
PGconn *db; /* connection to backend */
@@ -129,6 +135,7 @@ typedef struct _psqlSettings
const char *prompt2;
const char *prompt3;
PGVerbosity verbosity; /* current error verbosity level */
+ GroupCommand *group_commands;
} PsqlSettings;
extern PsqlSettings pset;
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 28ba75a..4c9383f 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -54,7 +54,8 @@ enum _actions
ACT_SINGLE_SLASH,
ACT_LIST_DB,
ACT_SINGLE_QUERY,
- ACT_FILE
+ ACT_FILE,
+ ACT_GROUP_COMMANDS
};
struct adhoc_opts
@@ -158,6 +159,8 @@ main(int argc, char *argv[])
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
+ pset.group_commands = NULL;
+
parse_psql_options(argc, argv, &options);
/*
@@ -326,6 +329,13 @@ main(int argc, char *argv[])
? EXIT_SUCCESS : EXIT_FAILURE;
}
+ else if (options.action == ACT_GROUP_COMMANDS)
+ {
+ pset.notty = true;
+ SetVariableBool(pset.vars, "SINGLELINE");
+ successResult = MainLoop(NULL, options.single_txn);
+ }
+
/*
* or otherwise enter interactive main loop
*/
@@ -338,7 +348,7 @@ main(int argc, char *argv[])
if (!pset.quiet)
printf(_("Type \"help\" for help.\n\n"));
initializeInput(options.no_readline ? 0 : 1);
- successResult = MainLoop(stdin);
+ successResult = MainLoop(stdin, false);
}
/* clean up */
@@ -370,6 +380,7 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
{"file", required_argument, NULL, 'f'},
{"field-separator", required_argument, NULL, 'F'},
{"field-separator-zero", no_argument, NULL, 'z'},
+ {"group-command", required_argument, NULL, 'g'},
{"host", required_argument, NULL, 'h'},
{"html", no_argument, NULL, 'H'},
{"list", no_argument, NULL, 'l'},
@@ -401,9 +412,12 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
int optindex;
int c;
+ bool cmd_opt_is_used = false;
+ bool group_cmd_opt_is_used = false;
+
memset(options, 0, sizeof *options);
- while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
+ while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:g:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
long_options, &optindex)) != -1)
{
switch (c)
@@ -418,6 +432,8 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
SetVariable(pset.vars, "ECHO", "errors");
break;
case 'c':
+ cmd_opt_is_used = true;
+
options->action_string = pg_strdup(optarg);
if (optarg[0] == '\\')
{
@@ -444,6 +460,27 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
pset.popt.topt.fieldSep.separator_zero = false;
break;
+ case 'g':
+ {
+ GroupCommand *cmd = pg_malloc(sizeof(GroupCommand));
+ GroupCommand *ptr = pset.group_commands;
+
+ group_cmd_opt_is_used = true;
+
+ if (ptr == NULL)
+ pset.group_commands = cmd;
+ else
+ {
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = cmd;
+ }
+ cmd->next = NULL;
+ cmd->actions = pg_strdup(optarg);
+ options->action = ACT_GROUP_COMMANDS;
+ }
+ break;
case 'h':
options->host = pg_strdup(optarg);
break;
@@ -600,6 +637,13 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
}
}
+ if (cmd_opt_is_used && group_cmd_opt_is_used)
+ {
+ fprintf(stderr, _("%s: options -c/--command and -g/--group_command cannot be used together\n"),
+ pset.progname);
+ exit(EXIT_FAILURE);
+ }
+
/*
* if we still have arguments, use it as the database name and username
*/
On 8/26/15 8:15 AM, Pavel Stehule wrote:
+ and then exit. This is useful in shell scripts. Start-up files + (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are + ignored with this option.
Sorry if this was discussed and I missed it, but I think this is a bad
idea. There's already an option to control this. More important, there's
no option to force the rc files to be used, so if -g disables them you'd
be stuck with that.
I agree that the rc files are a danger when scripting, but if we want to
do something about that then it needs to be consistent for ALL
non-interactive use.
--
Jim Nasby, Data Architect, Blue Treble Consulting, Austin TX
Experts in Analytics, Data Architecture and PostgreSQL
Data in Trouble? Get it in Treble! http://BlueTreble.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Aug 28, 2015 at 4:07 PM, Jim Nasby <Jim.Nasby@bluetreble.com> wrote:
On 8/26/15 8:15 AM, Pavel Stehule wrote:
+ and then exit. This is useful in shell scripts. Start-up files + (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are + ignored with this option.Sorry if this was discussed and I missed it, but I think this is a bad
idea. There's already an option to control this. More important, there's no
option to force the rc files to be used, so if -g disables them you'd be
stuck with that.I agree that the rc files are a danger when scripting, but if we want to
do something about that then it needs to be consistent for ALL
non-interactive use.
This ship has already sailed. The behavior described is consistent with
"-c" which "-g" should rightly conform with.
David J.
2015-08-28 22:07 GMT+02:00 Jim Nasby <Jim.Nasby@bluetreble.com>:
On 8/26/15 8:15 AM, Pavel Stehule wrote:
+ and then exit. This is useful in shell scripts. Start-up files + (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are + ignored with this option.Sorry if this was discussed and I missed it, but I think this is a bad
idea. There's already an option to control this. More important, there's no
option to force the rc files to be used, so if -g disables them you'd be
stuck with that.I agree that the rc files are a danger when scripting, but if we want to
do something about that then it needs to be consistent for ALL
non-interactive use.
I don't see any problem to load rc files - but should I do it by default? I
prefer
1. default - don't read rc
2. possible long option for forcing load rc for -c and -g
3. possible long option for forcing load any file as rc for -c and -g
Regards
Pavel
Show quoted text
--
Jim Nasby, Data Architect, Blue Treble Consulting, Austin TX
Experts in Analytics, Data Architecture and PostgreSQLData in Trouble? Get it in Treble! http://BlueTreble.com
On Fri, Aug 28, 2015 at 4:18 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:
2015-08-28 22:07 GMT+02:00 Jim Nasby <Jim.Nasby@bluetreble.com>:
On 8/26/15 8:15 AM, Pavel Stehule wrote:
+ and then exit. This is useful in shell scripts. Start-up files + (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are + ignored with this option.Sorry if this was discussed and I missed it, but I think this is a bad
idea. There's already an option to control this. More important, there's no
option to force the rc files to be used, so if -g disables them you'd be
stuck with that.I agree that the rc files are a danger when scripting, but if we want to
do something about that then it needs to be consistent for ALL
non-interactive use.I don't see any problem to load rc files - but should I do it by default?
I prefer1. default - don't read rc
2. possible long option for forcing load rc for -c and -g
3. possible long option for forcing load any file as rc for -c and -g
--psqlrc
; read the standard rc files
--no-psqlrc ; do not read the standard rc files
It belongs in a separate patch, though.
In this patch -g should disable the reading of the standard rc files.
Yet another option could be added that allows the user to point to a
different set of rc files. Its presence should not cause the
include/exclude behavior to change. That way you can setup a psql wrapper
function or alias that uses a different rc file while still having control
over whether it is included or excluded. The problem here is exploding the
logic in order to deal with both a system and a user rc file.
This would be yet another patch.
My $0.02
David J.
On 8/28/15 3:31 PM, David G. Johnston wrote:
--psqlrc
; read the standard rc files
--no-psqlrc ; do not read the standard rc filesIt belongs in a separate patch, though.
In this patch -g should disable the reading of the standard rc files.
Agreed; I didn't realize -c disabled psqlrc.
Yet another option could be added that allows the user to point to a
different set of rc files. Its presence should not cause the
include/exclude behavior to change. That way you can setup a psql
wrapper function or alias that uses a different rc file while still
having control over whether it is included or excluded. The problem
here is exploding the logic in order to deal with both a system and a
user rc file.
If we had a \i variation that didn't fail if the file wasn't readable
you could use that to pull a system psqlrc in from your custom one.
--
Jim Nasby, Data Architect, Blue Treble Consulting, Austin TX
Experts in Analytics, Data Architecture and PostgreSQL
Data in Trouble? Get it in Treble! http://BlueTreble.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2015-08-28 23:01 GMT+02:00 Jim Nasby <Jim.Nasby@bluetreble.com>:
On 8/28/15 3:31 PM, David G. Johnston wrote:
--psqlrc
; read the standard rc files
--no-psqlrc ; do not read the standard rc filesIt belongs in a separate patch, though.
In this patch -g should disable the reading of the standard rc files.
Agreed; I didn't realize -c disabled psqlrc.
Yet another option could be added that allows the user to point to a
different set of rc files. Its presence should not cause the
include/exclude behavior to change. That way you can setup a psql
wrapper function or alias that uses a different rc file while still
having control over whether it is included or excluded. The problem
here is exploding the logic in order to deal with both a system and a
user rc file.If we had a \i variation that didn't fail if the file wasn't readable you
could use that to pull a system psqlrc in from your custom one.
The import any file is not problem with -g command - so special option is
not necessary probably
psql postgres -g "\i somefile" -g "select xxx" -g "..."
Regards
Pavel
Show quoted text
--
Jim Nasby, Data Architect, Blue Treble Consulting, Austin TX
Experts in Analytics, Data Architecture and PostgreSQL
Data in Trouble? Get it in Treble! http://BlueTreble.com
2015-08-28 22:31 GMT+02:00 David G. Johnston <david.g.johnston@gmail.com>:
On Fri, Aug 28, 2015 at 4:18 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:2015-08-28 22:07 GMT+02:00 Jim Nasby <Jim.Nasby@bluetreble.com>:
On 8/26/15 8:15 AM, Pavel Stehule wrote:
+ and then exit. This is useful in shell scripts. Start-up files + (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are + ignored with this option.Sorry if this was discussed and I missed it, but I think this is a bad
idea. There's already an option to control this. More important, there's no
option to force the rc files to be used, so if -g disables them you'd be
stuck with that.I agree that the rc files are a danger when scripting, but if we want to
do something about that then it needs to be consistent for ALL
non-interactive use.I don't see any problem to load rc files - but should I do it by default?
I prefer1. default - don't read rc
2. possible long option for forcing load rc for -c and -g
3. possible long option for forcing load any file as rc for -c and -g--psqlrc
; read the standard rc files
--no-psqlrc ; do not read the standard rc filesIt belongs in a separate patch, though.
sure
In this patch -g should disable the reading of the standard rc files.
it does
Yet another option could be added that allows the user to point to a
different set of rc files. Its presence should not cause the
include/exclude behavior to change. That way you can setup a psql wrapper
function or alias that uses a different rc file while still having control
over whether it is included or excluded. The problem here is exploding the
logic in order to deal with both a system and a user rc file.
I am not against, but it is not neccessary - you can use -g for reading
some files and later -g for some special action
Regards
Pavel
Show quoted text
This would be yet another patch.
My $0.02
David J.
Pavel,
with -1 option support
FWIW, I have tried to apply this patch against master (7f11724) and
there is a minor error, see below.
From patch:
patching file src/bin/psql/settings.h
Hunk #2 FAILED at 135.
1 out of 2 hunks FAILED -- saving rejects to file src/bin/psql/settings.h.rej
From settings.h.rej:
--- src/bin/psql/settings.h
+++ src/bin/psql/settings.h
@@ -135,6 +141,7 @@
const char *prompt2;
const char *prompt3;
PGVerbosity verbosity; /* current error verbosity level */
+ GroupCommand *group_commands;
} PsqlSettings;
extern PsqlSettings pset;
-Adam
--
Adam Brightwell - adam.brightwell@crunchydatasolutions.com
Database Engineer - www.crunchydatasolutions.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi
2015-09-21 16:46 GMT+02:00 Adam Brightwell <
adam.brightwell@crunchydatasolutions.com>:
Pavel,
with -1 option support
FWIW, I have tried to apply this patch against master (7f11724) and
there is a minor error, see below.From patch:
patching file src/bin/psql/settings.h
Hunk #2 FAILED at 135.
1 out of 2 hunks FAILED -- saving rejects to file
src/bin/psql/settings.h.rejFrom settings.h.rej:
--- src/bin/psql/settings.h +++ src/bin/psql/settings.h @@ -135,6 +141,7 @@ const char *prompt2; const char *prompt3; PGVerbosity verbosity; /* current error verbosity level */ + GroupCommand *group_commands; } PsqlSettings;extern PsqlSettings pset;
yes, it was broken by context visibility patch.
fixed patch attached
Regards
Pavel
Show quoted text
-Adam
--
Adam Brightwell - adam.brightwell@crunchydatasolutions.com
Database Engineer - www.crunchydatasolutions.com
Attachments:
psql-group-command-03.patchtext/x-patch; charset=US-ASCII; name=psql-group-command-03.patchDownload
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
new file mode 100644
index 212dbfa..c932bb2
*** a/doc/src/sgml/ref/psql-ref.sgml
--- b/doc/src/sgml/ref/psql-ref.sgml
*************** EOF
*** 223,228 ****
--- 223,242 ----
</varlistentry>
<varlistentry>
+ <term><option>-g <replaceable class="parameter">command(s)</replaceable></></term>
+ <term><option>--group-command=<replaceable class="parameter">command(s)</replaceable></></term>
+ <listitem>
+ <para>
+ Specifies that <application>psql</application> is to execute one or
+ more command strings, <replaceable class="parameter">commands</replaceable>,
+ and then exit. This is useful in shell scripts. Start-up files
+ (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are
+ ignored with this option.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-h <replaceable class="parameter">hostname</replaceable></></term>
<term><option>--host=<replaceable class="parameter">hostname</replaceable></></term>
<listitem>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
new file mode 100644
index 50d3ff5..73ed5c1
*** a/src/bin/psql/command.c
--- b/src/bin/psql/command.c
*************** process_file(char *filename, bool single
*** 2293,2299 ****
int result;
char *oldfilename;
char relpath[MAXPGPATH];
- PGresult *res;
if (!filename)
{
--- 2293,2298 ----
*************** process_file(char *filename, bool single
*** 2338,2374 ****
oldfilename = pset.inputfile;
pset.inputfile = filename;
! if (single_txn)
! {
! if ((res = PSQLexec("BEGIN")) == NULL)
! {
! if (pset.on_error_stop)
! {
! result = EXIT_USER;
! goto error;
! }
! }
! else
! PQclear(res);
! }
!
! result = MainLoop(fd);
!
! if (single_txn)
! {
! if ((res = PSQLexec("COMMIT")) == NULL)
! {
! if (pset.on_error_stop)
! {
! result = EXIT_USER;
! goto error;
! }
! }
! else
! PQclear(res);
! }
- error:
if (fd != stdin)
fclose(fd);
--- 2337,2344 ----
oldfilename = pset.inputfile;
pset.inputfile = filename;
! result = MainLoop(fd, single_txn);
if (fd != stdin)
fclose(fd);
*************** error:
*** 2376,2383 ****
return result;
}
-
-
static const char *
_align2string(enum printFormat in)
{
--- 2346,2351 ----
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
new file mode 100644
index 5b63e76..2ef4ea6
*** a/src/bin/psql/help.c
--- b/src/bin/psql/help.c
*************** usage(unsigned short int pager)
*** 83,88 ****
--- 83,90 ----
fprintf(output, _(" -c, --command=COMMAND run only single command (SQL or internal) and exit\n"));
fprintf(output, _(" -d, --dbname=DBNAME database name to connect to (default: \"%s\")\n"), env);
fprintf(output, _(" -f, --file=FILENAME execute commands from file, then exit\n"));
+ fprintf(output, _(" -g, --group-command=COMMAND\n"
+ " run more groups of commands (SQL or internal) and exit\n"));
fprintf(output, _(" -l, --list list available databases, then exit\n"));
fprintf(output, _(" -v, --set=, --variable=NAME=VALUE\n"
" set psql variable NAME to VALUE\n"
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
new file mode 100644
index b6cef94..4147238
*** a/src/bin/psql/mainloop.c
--- b/src/bin/psql/mainloop.c
***************
*** 24,31 ****
* This loop is re-entrant. May be called by \i command
* which reads input from a file.
*/
! int
! MainLoop(FILE *source)
{
PsqlScanState scan_state; /* lexer working state */
volatile PQExpBuffer query_buf; /* buffer for query being accumulated */
--- 24,31 ----
* This loop is re-entrant. May be called by \i command
* which reads input from a file.
*/
! static int
! _MainLoop(FILE *source)
{
PsqlScanState scan_state; /* lexer working state */
volatile PQExpBuffer query_buf; /* buffer for query being accumulated */
*************** MainLoop(FILE *source)
*** 43,48 ****
--- 43,49 ----
volatile promptStatus_t prompt_status = PROMPT_READY;
volatile int count_eof = 0;
volatile bool die_on_error = false;
+ GroupCommand *cmd = pset.group_commands;
/* Save the prior command source */
FILE *prev_cmd_source;
*************** MainLoop(FILE *source)
*** 135,140 ****
--- 136,155 ----
prompt_status = PROMPT_READY;
line = gets_interactive(get_prompt(prompt_status));
}
+ else if (pset.group_commands != NULL)
+ {
+ /* Is there some unprocessed group command? */
+ if (cmd != NULL)
+ {
+ line = cmd->actions;
+ cmd = cmd->next;
+ }
+ else
+ {
+ successResult = EXIT_SUCCESS;
+ break;
+ }
+ }
else
{
line = gets_fromFile(source);
*************** MainLoop(FILE *source)
*** 451,456 ****
--- 466,508 ----
return successResult;
} /* MainLoop() */
+ /*
+ * Transactional MainLoop
+ *
+ * allow to execute all statements in single transaction
+ */
+ int
+ MainLoop(FILE *source, bool single_txn)
+ {
+ int result;
+ PGresult *res;
+
+ if (single_txn)
+ {
+ if ((res = PSQLexec("BEGIN")) == NULL)
+ {
+ if (pset.on_error_stop)
+ return EXIT_USER;
+ }
+ else
+ PQclear(res);
+ }
+
+ result = _MainLoop(source);
+
+ if (single_txn)
+ {
+ if ((res = PSQLexec("COMMIT")) == NULL)
+ {
+ if (pset.on_error_stop)
+ return EXIT_USER;
+ }
+ else
+ PQclear(res);
+ }
+
+ return result;
+ }
/*
* psqlscan.c is #include'd here instead of being compiled on its own.
diff --git a/src/bin/psql/mainloop.h b/src/bin/psql/mainloop.h
new file mode 100644
index 8f1325c..53c9a11
*** a/src/bin/psql/mainloop.h
--- b/src/bin/psql/mainloop.h
***************
*** 10,15 ****
#include "postgres_fe.h"
! int MainLoop(FILE *source);
#endif /* MAINLOOP_H */
--- 10,15 ----
#include "postgres_fe.h"
! int MainLoop(FILE *source, bool single_txn);
#endif /* MAINLOOP_H */
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
new file mode 100644
index 1885bb1..29455ac
*** a/src/bin/psql/settings.h
--- b/src/bin/psql/settings.h
*************** enum trivalue
*** 77,82 ****
--- 77,88 ----
TRI_YES
};
+ typedef struct _GroupCommand
+ {
+ char *actions;
+ struct _GroupCommand *next;
+ } GroupCommand;
+
typedef struct _psqlSettings
{
PGconn *db; /* connection to backend */
*************** typedef struct _psqlSettings
*** 130,135 ****
--- 136,142 ----
const char *prompt3;
PGVerbosity verbosity; /* current error verbosity level */
PGContextVisibility show_context; /* current context display level */
+ GroupCommand *group_commands;
} PsqlSettings;
extern PsqlSettings pset;
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
new file mode 100644
index 7aa997d..df334b4
*** a/src/bin/psql/startup.c
--- b/src/bin/psql/startup.c
*************** enum _actions
*** 54,60 ****
ACT_SINGLE_SLASH,
ACT_LIST_DB,
ACT_SINGLE_QUERY,
! ACT_FILE
};
struct adhoc_opts
--- 54,61 ----
ACT_SINGLE_SLASH,
ACT_LIST_DB,
ACT_SINGLE_QUERY,
! ACT_FILE,
! ACT_GROUP_COMMANDS
};
struct adhoc_opts
*************** main(int argc, char *argv[])
*** 159,164 ****
--- 160,167 ----
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
+ pset.group_commands = NULL;
+
parse_psql_options(argc, argv, &options);
/*
*************** main(int argc, char *argv[])
*** 327,332 ****
--- 330,342 ----
? EXIT_SUCCESS : EXIT_FAILURE;
}
+ else if (options.action == ACT_GROUP_COMMANDS)
+ {
+ pset.notty = true;
+ SetVariableBool(pset.vars, "SINGLELINE");
+ successResult = MainLoop(NULL, options.single_txn);
+ }
+
/*
* or otherwise enter interactive main loop
*/
*************** main(int argc, char *argv[])
*** 339,345 ****
if (!pset.quiet)
printf(_("Type \"help\" for help.\n\n"));
initializeInput(options.no_readline ? 0 : 1);
! successResult = MainLoop(stdin);
}
/* clean up */
--- 349,355 ----
if (!pset.quiet)
printf(_("Type \"help\" for help.\n\n"));
initializeInput(options.no_readline ? 0 : 1);
! successResult = MainLoop(stdin, false);
}
/* clean up */
*************** parse_psql_options(int argc, char *argv[
*** 371,376 ****
--- 381,387 ----
{"file", required_argument, NULL, 'f'},
{"field-separator", required_argument, NULL, 'F'},
{"field-separator-zero", no_argument, NULL, 'z'},
+ {"group-command", required_argument, NULL, 'g'},
{"host", required_argument, NULL, 'h'},
{"html", no_argument, NULL, 'H'},
{"list", no_argument, NULL, 'l'},
*************** parse_psql_options(int argc, char *argv[
*** 402,410 ****
int optindex;
int c;
memset(options, 0, sizeof *options);
! while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
long_options, &optindex)) != -1)
{
switch (c)
--- 413,424 ----
int optindex;
int c;
+ bool cmd_opt_is_used = false;
+ bool group_cmd_opt_is_used = false;
+
memset(options, 0, sizeof *options);
! while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:g:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
long_options, &optindex)) != -1)
{
switch (c)
*************** parse_psql_options(int argc, char *argv[
*** 419,424 ****
--- 433,440 ----
SetVariable(pset.vars, "ECHO", "errors");
break;
case 'c':
+ cmd_opt_is_used = true;
+
options->action_string = pg_strdup(optarg);
if (optarg[0] == '\\')
{
*************** parse_psql_options(int argc, char *argv[
*** 445,450 ****
--- 461,487 ----
pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
pset.popt.topt.fieldSep.separator_zero = false;
break;
+ case 'g':
+ {
+ GroupCommand *cmd = pg_malloc(sizeof(GroupCommand));
+ GroupCommand *ptr = pset.group_commands;
+
+ group_cmd_opt_is_used = true;
+
+ if (ptr == NULL)
+ pset.group_commands = cmd;
+ else
+ {
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = cmd;
+ }
+ cmd->next = NULL;
+ cmd->actions = pg_strdup(optarg);
+ options->action = ACT_GROUP_COMMANDS;
+ }
+ break;
case 'h':
options->host = pg_strdup(optarg);
break;
*************** parse_psql_options(int argc, char *argv[
*** 601,606 ****
--- 638,650 ----
}
}
+ if (cmd_opt_is_used && group_cmd_opt_is_used)
+ {
+ fprintf(stderr, _("%s: options -c/--command and -g/--group_command cannot be used together\n"),
+ pset.progname);
+ exit(EXIT_FAILURE);
+ }
+
/*
* if we still have arguments, use it as the database name and username
*/
On Sat, Oct 31, 2015 at 2:50 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
fixed patch attached
The documentation included in this patch doesn't really make it clear
why -g is different from or better than -c.
--
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
2015-11-03 4:16 GMT+01:00 Robert Haas <robertmhaas@gmail.com>:
On Sat, Oct 31, 2015 at 2:50 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:fixed patch attached
The documentation included in this patch doesn't really make it clear
why -g is different from or better than -c.
I wrote some text. But needs some work of native speaker.
Regards
Pavel
Show quoted text
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Attachments:
psql-group-command-04.patchtext/x-patch; charset=US-ASCII; name=psql-group-command-04.patchDownload
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
new file mode 100644
index 212dbfa..18ff8e5
*** a/doc/src/sgml/ref/psql-ref.sgml
--- b/doc/src/sgml/ref/psql-ref.sgml
*************** EOF
*** 223,228 ****
--- 223,268 ----
</varlistentry>
<varlistentry>
+ <term><option>-g <replaceable class="parameter">command(s)</replaceable></></term>
+ <term><option>--group-command=<replaceable class="parameter">command(s)</replaceable></></term>
+ <listitem>
+ <para>
+ Specifies that <application>psql</application> is to execute one or
+ more command strings, <replaceable class="parameter">commands</replaceable>,
+ and then exit. This is useful in shell scripts. Start-up files
+ (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are
+ ignored with this option.
+ </para>
+
+ <para>
+ There are a few differences between <option>-c</option> and
+ <option>-g</option> options. The option <option>-c</option> can be used
+ only once. The option <option>-g</option> can be used more times.
+ This can simplify writing some non trivial SQL commands. With the
+ <option>-g</option> option it is possible to call several <application>psql</application>
+ parametrized backslash commands. When you execute multiple SQL
+ commands via <option>-c</option> option, only result of last command
+ is returned. The execution started by <option>-g</option> option shows
+ result of all commands.
+ </para>
+
+ <para>
+ Another difference is in wrapping the transaction. The <option>-c</option>
+ option runs commands in one transaction. The <option>-g</option> option
+ uses autocommit mode by default. This allows running multiple commads
+ which would otherwise not be allowed to execute within one transaction.
+ This is typical for <command>VACUUM</command> command.
+ <programlisting>
+ psql -Atq -g "VACUUM FULL foo; SELECT pg_relation_size('foo')"
+ psql -Atq -g "VACUUM FULL foo" -g "SELECT pg_relation_size('foo')"
+ </programlisting>
+
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-h <replaceable class="parameter">hostname</replaceable></></term>
<term><option>--host=<replaceable class="parameter">hostname</replaceable></></term>
<listitem>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
new file mode 100644
index 50d3ff5..73ed5c1
*** a/src/bin/psql/command.c
--- b/src/bin/psql/command.c
*************** process_file(char *filename, bool single
*** 2293,2299 ****
int result;
char *oldfilename;
char relpath[MAXPGPATH];
- PGresult *res;
if (!filename)
{
--- 2293,2298 ----
*************** process_file(char *filename, bool single
*** 2338,2374 ****
oldfilename = pset.inputfile;
pset.inputfile = filename;
! if (single_txn)
! {
! if ((res = PSQLexec("BEGIN")) == NULL)
! {
! if (pset.on_error_stop)
! {
! result = EXIT_USER;
! goto error;
! }
! }
! else
! PQclear(res);
! }
!
! result = MainLoop(fd);
!
! if (single_txn)
! {
! if ((res = PSQLexec("COMMIT")) == NULL)
! {
! if (pset.on_error_stop)
! {
! result = EXIT_USER;
! goto error;
! }
! }
! else
! PQclear(res);
! }
- error:
if (fd != stdin)
fclose(fd);
--- 2337,2344 ----
oldfilename = pset.inputfile;
pset.inputfile = filename;
! result = MainLoop(fd, single_txn);
if (fd != stdin)
fclose(fd);
*************** error:
*** 2376,2383 ****
return result;
}
-
-
static const char *
_align2string(enum printFormat in)
{
--- 2346,2351 ----
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
new file mode 100644
index 5b63e76..2ef4ea6
*** a/src/bin/psql/help.c
--- b/src/bin/psql/help.c
*************** usage(unsigned short int pager)
*** 83,88 ****
--- 83,90 ----
fprintf(output, _(" -c, --command=COMMAND run only single command (SQL or internal) and exit\n"));
fprintf(output, _(" -d, --dbname=DBNAME database name to connect to (default: \"%s\")\n"), env);
fprintf(output, _(" -f, --file=FILENAME execute commands from file, then exit\n"));
+ fprintf(output, _(" -g, --group-command=COMMAND\n"
+ " run more groups of commands (SQL or internal) and exit\n"));
fprintf(output, _(" -l, --list list available databases, then exit\n"));
fprintf(output, _(" -v, --set=, --variable=NAME=VALUE\n"
" set psql variable NAME to VALUE\n"
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
new file mode 100644
index b6cef94..4147238
*** a/src/bin/psql/mainloop.c
--- b/src/bin/psql/mainloop.c
***************
*** 24,31 ****
* This loop is re-entrant. May be called by \i command
* which reads input from a file.
*/
! int
! MainLoop(FILE *source)
{
PsqlScanState scan_state; /* lexer working state */
volatile PQExpBuffer query_buf; /* buffer for query being accumulated */
--- 24,31 ----
* This loop is re-entrant. May be called by \i command
* which reads input from a file.
*/
! static int
! _MainLoop(FILE *source)
{
PsqlScanState scan_state; /* lexer working state */
volatile PQExpBuffer query_buf; /* buffer for query being accumulated */
*************** MainLoop(FILE *source)
*** 43,48 ****
--- 43,49 ----
volatile promptStatus_t prompt_status = PROMPT_READY;
volatile int count_eof = 0;
volatile bool die_on_error = false;
+ GroupCommand *cmd = pset.group_commands;
/* Save the prior command source */
FILE *prev_cmd_source;
*************** MainLoop(FILE *source)
*** 135,140 ****
--- 136,155 ----
prompt_status = PROMPT_READY;
line = gets_interactive(get_prompt(prompt_status));
}
+ else if (pset.group_commands != NULL)
+ {
+ /* Is there some unprocessed group command? */
+ if (cmd != NULL)
+ {
+ line = cmd->actions;
+ cmd = cmd->next;
+ }
+ else
+ {
+ successResult = EXIT_SUCCESS;
+ break;
+ }
+ }
else
{
line = gets_fromFile(source);
*************** MainLoop(FILE *source)
*** 451,456 ****
--- 466,508 ----
return successResult;
} /* MainLoop() */
+ /*
+ * Transactional MainLoop
+ *
+ * allow to execute all statements in single transaction
+ */
+ int
+ MainLoop(FILE *source, bool single_txn)
+ {
+ int result;
+ PGresult *res;
+
+ if (single_txn)
+ {
+ if ((res = PSQLexec("BEGIN")) == NULL)
+ {
+ if (pset.on_error_stop)
+ return EXIT_USER;
+ }
+ else
+ PQclear(res);
+ }
+
+ result = _MainLoop(source);
+
+ if (single_txn)
+ {
+ if ((res = PSQLexec("COMMIT")) == NULL)
+ {
+ if (pset.on_error_stop)
+ return EXIT_USER;
+ }
+ else
+ PQclear(res);
+ }
+
+ return result;
+ }
/*
* psqlscan.c is #include'd here instead of being compiled on its own.
diff --git a/src/bin/psql/mainloop.h b/src/bin/psql/mainloop.h
new file mode 100644
index 8f1325c..53c9a11
*** a/src/bin/psql/mainloop.h
--- b/src/bin/psql/mainloop.h
***************
*** 10,15 ****
#include "postgres_fe.h"
! int MainLoop(FILE *source);
#endif /* MAINLOOP_H */
--- 10,15 ----
#include "postgres_fe.h"
! int MainLoop(FILE *source, bool single_txn);
#endif /* MAINLOOP_H */
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
new file mode 100644
index 1885bb1..29455ac
*** a/src/bin/psql/settings.h
--- b/src/bin/psql/settings.h
*************** enum trivalue
*** 77,82 ****
--- 77,88 ----
TRI_YES
};
+ typedef struct _GroupCommand
+ {
+ char *actions;
+ struct _GroupCommand *next;
+ } GroupCommand;
+
typedef struct _psqlSettings
{
PGconn *db; /* connection to backend */
*************** typedef struct _psqlSettings
*** 130,135 ****
--- 136,142 ----
const char *prompt3;
PGVerbosity verbosity; /* current error verbosity level */
PGContextVisibility show_context; /* current context display level */
+ GroupCommand *group_commands;
} PsqlSettings;
extern PsqlSettings pset;
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
new file mode 100644
index 7aa997d..df334b4
*** a/src/bin/psql/startup.c
--- b/src/bin/psql/startup.c
*************** enum _actions
*** 54,60 ****
ACT_SINGLE_SLASH,
ACT_LIST_DB,
ACT_SINGLE_QUERY,
! ACT_FILE
};
struct adhoc_opts
--- 54,61 ----
ACT_SINGLE_SLASH,
ACT_LIST_DB,
ACT_SINGLE_QUERY,
! ACT_FILE,
! ACT_GROUP_COMMANDS
};
struct adhoc_opts
*************** main(int argc, char *argv[])
*** 159,164 ****
--- 160,167 ----
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
+ pset.group_commands = NULL;
+
parse_psql_options(argc, argv, &options);
/*
*************** main(int argc, char *argv[])
*** 327,332 ****
--- 330,342 ----
? EXIT_SUCCESS : EXIT_FAILURE;
}
+ else if (options.action == ACT_GROUP_COMMANDS)
+ {
+ pset.notty = true;
+ SetVariableBool(pset.vars, "SINGLELINE");
+ successResult = MainLoop(NULL, options.single_txn);
+ }
+
/*
* or otherwise enter interactive main loop
*/
*************** main(int argc, char *argv[])
*** 339,345 ****
if (!pset.quiet)
printf(_("Type \"help\" for help.\n\n"));
initializeInput(options.no_readline ? 0 : 1);
! successResult = MainLoop(stdin);
}
/* clean up */
--- 349,355 ----
if (!pset.quiet)
printf(_("Type \"help\" for help.\n\n"));
initializeInput(options.no_readline ? 0 : 1);
! successResult = MainLoop(stdin, false);
}
/* clean up */
*************** parse_psql_options(int argc, char *argv[
*** 371,376 ****
--- 381,387 ----
{"file", required_argument, NULL, 'f'},
{"field-separator", required_argument, NULL, 'F'},
{"field-separator-zero", no_argument, NULL, 'z'},
+ {"group-command", required_argument, NULL, 'g'},
{"host", required_argument, NULL, 'h'},
{"html", no_argument, NULL, 'H'},
{"list", no_argument, NULL, 'l'},
*************** parse_psql_options(int argc, char *argv[
*** 402,410 ****
int optindex;
int c;
memset(options, 0, sizeof *options);
! while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
long_options, &optindex)) != -1)
{
switch (c)
--- 413,424 ----
int optindex;
int c;
+ bool cmd_opt_is_used = false;
+ bool group_cmd_opt_is_used = false;
+
memset(options, 0, sizeof *options);
! while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:g:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
long_options, &optindex)) != -1)
{
switch (c)
*************** parse_psql_options(int argc, char *argv[
*** 419,424 ****
--- 433,440 ----
SetVariable(pset.vars, "ECHO", "errors");
break;
case 'c':
+ cmd_opt_is_used = true;
+
options->action_string = pg_strdup(optarg);
if (optarg[0] == '\\')
{
*************** parse_psql_options(int argc, char *argv[
*** 445,450 ****
--- 461,487 ----
pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
pset.popt.topt.fieldSep.separator_zero = false;
break;
+ case 'g':
+ {
+ GroupCommand *cmd = pg_malloc(sizeof(GroupCommand));
+ GroupCommand *ptr = pset.group_commands;
+
+ group_cmd_opt_is_used = true;
+
+ if (ptr == NULL)
+ pset.group_commands = cmd;
+ else
+ {
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = cmd;
+ }
+ cmd->next = NULL;
+ cmd->actions = pg_strdup(optarg);
+ options->action = ACT_GROUP_COMMANDS;
+ }
+ break;
case 'h':
options->host = pg_strdup(optarg);
break;
*************** parse_psql_options(int argc, char *argv[
*** 601,606 ****
--- 638,650 ----
}
}
+ if (cmd_opt_is_used && group_cmd_opt_is_used)
+ {
+ fprintf(stderr, _("%s: options -c/--command and -g/--group_command cannot be used together\n"),
+ pset.progname);
+ exit(EXIT_FAILURE);
+ }
+
/*
* if we still have arguments, use it as the database name and username
*/
On Tue, Nov 3, 2015 at 10:16 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
The documentation included in this patch doesn't really make it clear
why -g is different from or better than -c.I wrote some text. But needs some work of native speaker.
It does. It would be nice if some kind reviewer could help volunteer
to clean that up.
Upthread, it was suggested that this option be called -C rather than
-g, and personally I like that better. I don't really think there's
anything "grouped" about the -g option; it's just an upgraded version
of -c that does what we probably should have had -C do from the
beginning, but now don't want to change out of a concern for
backward-compatibility. I would propose to change not only the
user-visible option name but all of the internal things that call this
"group" or "grouped". Maybe introduce ACT_COMMAND_LINE or similar
instead of ACT_GROUP_COMMANDS.
Whatever else we do here, -1 on having both _MainLoop and MainLoop as
function names. That can't be anything but confusing.
--
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
2015-11-05 17:27 GMT+01:00 Robert Haas <robertmhaas@gmail.com>:
On Tue, Nov 3, 2015 at 10:16 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:The documentation included in this patch doesn't really make it clear
why -g is different from or better than -c.I wrote some text. But needs some work of native speaker.
It does. It would be nice if some kind reviewer could help volunteer
to clean that up.Upthread, it was suggested that this option be called -C rather than
-g, and personally I like that better. I don't really think there's
anything "grouped" about the -g option; it's just an upgraded version
of -c that does what we probably should have had -C do from the
beginning, but now don't want to change out of a concern for
backward-compatibility. I would propose to change not only the
user-visible option name but all of the internal things that call this
"group" or "grouped". Maybe introduce ACT_COMMAND_LINE or similar
instead of ACT_GROUP_COMMANDS.
-C is good, and if there will not by any objection, I am for it
Whatever else we do here, -1 on having both _MainLoop and MainLoop as
function names. That can't be anything but confusing.
I'll have free time at weekend, and I'll check it.
Regards
Pavel
Show quoted text
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Thu, Nov 5, 2015 at 5:27 PM, Robert Haas <robertmhaas@gmail.com> wrote:
I wrote some text. But needs some work of native speaker.
It does. It would be nice if some kind reviewer could help volunteer
to clean that up.
I'll give it a go sometime next week.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Thu, Nov 5, 2015 at 3:53 PM, Catalin Iacob <iacobcatalin@gmail.com> wrote:
On Thu, Nov 5, 2015 at 5:27 PM, Robert Haas <robertmhaas@gmail.com> wrote:
I wrote some text. But needs some work of native speaker.
It does. It would be nice if some kind reviewer could help volunteer
to clean that up.I'll give it a go sometime next week.
Thanks, that would be great!
I recommend comparing the section on -c and the section on -C, and
probably updating the former as well as adjusting the wording of the
latter. We don't want to repeat all the same details in both places,
but we hopefully want to give people a little clue that if they're
thinking about using -c, they may wish to instead consider -C.
--
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
Hi
2015-11-05 22:23 GMT+01:00 Robert Haas <robertmhaas@gmail.com>:
On Thu, Nov 5, 2015 at 3:53 PM, Catalin Iacob <iacobcatalin@gmail.com>
wrote:On Thu, Nov 5, 2015 at 5:27 PM, Robert Haas <robertmhaas@gmail.com>
wrote:
I wrote some text. But needs some work of native speaker.
It does. It would be nice if some kind reviewer could help volunteer
to clean that up.I'll give it a go sometime next week.
Thanks, that would be great!
I recommend comparing the section on -c and the section on -C, and
probably updating the former as well as adjusting the wording of the
latter. We don't want to repeat all the same details in both places,
but we hopefully want to give people a little clue that if they're
thinking about using -c, they may wish to instead consider -C.
-g was replaced by -C option and some other required changes.
I have not idea about good long name. In this moment I used
"multi-command". Can be changed freely.
The name of this patch is same (although it doesn't use "group-command"
internally anymore) due better orientation.
Regards
Pavel
Show quoted text
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Attachments:
psql-group-command-05.patchtext/x-patch; charset=US-ASCII; name=psql-group-command-05.patchDownload
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
new file mode 100644
index 5899bb4..3ef32d2
*** a/doc/src/sgml/ref/psql-ref.sgml
--- b/doc/src/sgml/ref/psql-ref.sgml
*************** EOF
*** 132,137 ****
--- 132,176 ----
</varlistentry>
<varlistentry>
+ <term><option>-C <replaceable class="parameter">command(s)</replaceable></></term>
+ <term><option>--multi-command=<replaceable class="parameter">command(s)</replaceable></></term>
+ <listitem>
+ <para>
+ Specifies that <application>psql</application> is to execute one or
+ more command strings, <replaceable class="parameter">commands</replaceable>,
+ and then exit. This is useful in shell scripts. Start-up files
+ (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are
+ ignored with this option.
+ </para>
+
+ <para>
+ There are a few differences between <option>-c</option> and
+ <option>-C</option> options. The option <option>-c</option> can be used
+ only once. The option <option>-C</option> can be used more times.
+ This can simplify writing some non trivial SQL commands. With the
+ <option>-C</option> option it is possible to call several <application>psql</application>
+ parametrized backslash commands. When you execute multiple SQL
+ commands via <option>-c</option> option, only result of last command
+ is returned. The execution started by <option>-C</option> option shows
+ result of all commands.
+ </para>
+
+ <para>
+ Another difference is in wrapping the transaction. The <option>-c</option>
+ option runs commands in one transaction. The <option>-C</option> option
+ uses autocommit mode by default. This allows running multiple commads
+ which would otherwise not be allowed to execute within one transaction.
+ This is typical for <command>VACUUM</command> command.
+ <programlisting>
+ psql -Atq -C "VACUUM FULL foo; SELECT pg_relation_size('foo')"
+ psql -Atq -C "VACUUM FULL foo" -C "SELECT pg_relation_size('foo')"
+ </programlisting>
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-d <replaceable class="parameter">dbname</replaceable></></term>
<term><option>--dbname=<replaceable class="parameter">dbname</replaceable></></term>
<listitem>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
new file mode 100644
index 72c00c1..1bc20d3
*** a/src/bin/psql/command.c
--- b/src/bin/psql/command.c
*************** process_file(char *filename, bool single
*** 2293,2299 ****
int result;
char *oldfilename;
char relpath[MAXPGPATH];
- PGresult *res;
if (!filename)
{
--- 2293,2298 ----
*************** process_file(char *filename, bool single
*** 2338,2374 ****
oldfilename = pset.inputfile;
pset.inputfile = filename;
! if (single_txn)
! {
! if ((res = PSQLexec("BEGIN")) == NULL)
! {
! if (pset.on_error_stop)
! {
! result = EXIT_USER;
! goto error;
! }
! }
! else
! PQclear(res);
! }
!
! result = MainLoop(fd);
!
! if (single_txn)
! {
! if ((res = PSQLexec("COMMIT")) == NULL)
! {
! if (pset.on_error_stop)
! {
! result = EXIT_USER;
! goto error;
! }
! }
! else
! PQclear(res);
! }
- error:
if (fd != stdin)
fclose(fd);
--- 2337,2344 ----
oldfilename = pset.inputfile;
pset.inputfile = filename;
! result = MainLoop(fd, single_txn);
if (fd != stdin)
fclose(fd);
*************** error:
*** 2376,2383 ****
return result;
}
-
-
static const char *
_align2string(enum printFormat in)
{
--- 2346,2351 ----
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
new file mode 100644
index 5b63e76..7058ada
*** a/src/bin/psql/help.c
--- b/src/bin/psql/help.c
*************** usage(unsigned short int pager)
*** 81,86 ****
--- 81,88 ----
if (!env)
env = user;
fprintf(output, _(" -c, --command=COMMAND run only single command (SQL or internal) and exit\n"));
+ fprintf(output, _(" -C, --multi-command=COMMAND\n"
+ " run more multiple commands (SQL or internal) and exit\n"));
fprintf(output, _(" -d, --dbname=DBNAME database name to connect to (default: \"%s\")\n"), env);
fprintf(output, _(" -f, --file=FILENAME execute commands from file, then exit\n"));
fprintf(output, _(" -l, --list list available databases, then exit\n"));
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
new file mode 100644
index b6cef94..930d2c5
*** a/src/bin/psql/mainloop.c
--- b/src/bin/psql/mainloop.c
***************
*** 25,31 ****
* which reads input from a file.
*/
int
! MainLoop(FILE *source)
{
PsqlScanState scan_state; /* lexer working state */
volatile PQExpBuffer query_buf; /* buffer for query being accumulated */
--- 25,31 ----
* which reads input from a file.
*/
int
! MainLoop(FILE *source, bool single_txn)
{
PsqlScanState scan_state; /* lexer working state */
volatile PQExpBuffer query_buf; /* buffer for query being accumulated */
*************** MainLoop(FILE *source)
*** 43,48 ****
--- 43,50 ----
volatile promptStatus_t prompt_status = PROMPT_READY;
volatile int count_eof = 0;
volatile bool die_on_error = false;
+ Commands *cmds = pset.commands;
+ PGresult *result;
/* Save the prior command source */
FILE *prev_cmd_source;
*************** MainLoop(FILE *source)
*** 60,65 ****
--- 62,79 ----
pset.lineno = 0;
pset.stmt_lineno = 1;
+ /* Start transaction when it is required before any allocation */
+ if (single_txn)
+ {
+ if ((result = PSQLexec("BEGIN")) == NULL)
+ {
+ if (pset.on_error_stop)
+ return EXIT_USER;
+ }
+ else
+ PQclear(result);
+ }
+
/* Create working state */
scan_state = psql_scan_create();
*************** MainLoop(FILE *source)
*** 135,140 ****
--- 149,168 ----
prompt_status = PROMPT_READY;
line = gets_interactive(get_prompt(prompt_status));
}
+ else if (pset.commands != NULL)
+ {
+ /* Is there some unprocessed multi command? */
+ if (cmds != NULL)
+ {
+ line = cmds->actions;
+ cmds = cmds->next;
+ }
+ else
+ {
+ successResult = EXIT_SUCCESS;
+ break;
+ }
+ }
else
{
line = gets_fromFile(source);
*************** MainLoop(FILE *source)
*** 429,434 ****
--- 457,474 ----
successResult = EXIT_BADCONN;
}
+ /* Commit success transaction */
+ if (single_txn && successResult == EXIT_SUCCESS)
+ {
+ if ((result = PSQLexec("COMMIT")) == NULL)
+ {
+ if (die_on_error)
+ successResult = EXIT_USER;
+ }
+ else
+ PQclear(result);
+ }
+
/*
* Let's just make real sure the SIGINT handler won't try to use
* sigint_interrupt_jmp after we exit this routine. If there is an outer
*************** MainLoop(FILE *source)
*** 451,457 ****
return successResult;
} /* MainLoop() */
-
/*
* psqlscan.c is #include'd here instead of being compiled on its own.
* This is because we need postgres_fe.h to be read before any system
--- 491,496 ----
diff --git a/src/bin/psql/mainloop.h b/src/bin/psql/mainloop.h
new file mode 100644
index 8f1325c..53c9a11
*** a/src/bin/psql/mainloop.h
--- b/src/bin/psql/mainloop.h
***************
*** 10,15 ****
#include "postgres_fe.h"
! int MainLoop(FILE *source);
#endif /* MAINLOOP_H */
--- 10,15 ----
#include "postgres_fe.h"
! int MainLoop(FILE *source, bool single_txn);
#endif /* MAINLOOP_H */
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
new file mode 100644
index 1885bb1..39ced85
*** a/src/bin/psql/settings.h
--- b/src/bin/psql/settings.h
*************** enum trivalue
*** 77,82 ****
--- 77,88 ----
TRI_YES
};
+ typedef struct _Commands
+ {
+ char *actions;
+ struct _Commands *next;
+ } Commands;
+
typedef struct _psqlSettings
{
PGconn *db; /* connection to backend */
*************** typedef struct _psqlSettings
*** 130,135 ****
--- 136,142 ----
const char *prompt3;
PGVerbosity verbosity; /* current error verbosity level */
PGContextVisibility show_context; /* current context display level */
+ Commands *commands;
} PsqlSettings;
extern PsqlSettings pset;
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
new file mode 100644
index 7aa997d..6118b07
*** a/src/bin/psql/startup.c
--- b/src/bin/psql/startup.c
*************** enum _actions
*** 54,60 ****
ACT_SINGLE_SLASH,
ACT_LIST_DB,
ACT_SINGLE_QUERY,
! ACT_FILE
};
struct adhoc_opts
--- 54,61 ----
ACT_SINGLE_SLASH,
ACT_LIST_DB,
ACT_SINGLE_QUERY,
! ACT_FILE,
! ACT_COMMAND_LINE
};
struct adhoc_opts
*************** main(int argc, char *argv[])
*** 159,164 ****
--- 160,167 ----
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
+ pset.commands = NULL;
+
parse_psql_options(argc, argv, &options);
/*
*************** main(int argc, char *argv[])
*** 327,332 ****
--- 330,344 ----
? EXIT_SUCCESS : EXIT_FAILURE;
}
+ else if (options.action == ACT_COMMAND_LINE)
+ {
+ pset.notty = true;
+
+ /* use singleline mode, doesn't need semicolon on the end line */
+ SetVariableBool(pset.vars, "SINGLELINE");
+ successResult = MainLoop(NULL, options.single_txn);
+ }
+
/*
* or otherwise enter interactive main loop
*/
*************** main(int argc, char *argv[])
*** 339,345 ****
if (!pset.quiet)
printf(_("Type \"help\" for help.\n\n"));
initializeInput(options.no_readline ? 0 : 1);
! successResult = MainLoop(stdin);
}
/* clean up */
--- 351,357 ----
if (!pset.quiet)
printf(_("Type \"help\" for help.\n\n"));
initializeInput(options.no_readline ? 0 : 1);
! successResult = MainLoop(stdin, false);
}
/* clean up */
*************** parse_psql_options(int argc, char *argv[
*** 375,380 ****
--- 387,393 ----
{"html", no_argument, NULL, 'H'},
{"list", no_argument, NULL, 'l'},
{"log-file", required_argument, NULL, 'L'},
+ {"multi-command", required_argument, NULL, 'C'},
{"no-readline", no_argument, NULL, 'n'},
{"single-transaction", no_argument, NULL, '1'},
{"output", required_argument, NULL, 'o'},
*************** parse_psql_options(int argc, char *argv[
*** 402,410 ****
int optindex;
int c;
memset(options, 0, sizeof *options);
! while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
long_options, &optindex)) != -1)
{
switch (c)
--- 415,426 ----
int optindex;
int c;
+ bool cmd_opt_is_used = false;
+ bool commands_opt_is_used = false;
+
memset(options, 0, sizeof *options);
! while ((c = getopt_long(argc, argv, "aAbc:C:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
long_options, &optindex)) != -1)
{
switch (c)
*************** parse_psql_options(int argc, char *argv[
*** 419,424 ****
--- 435,442 ----
SetVariable(pset.vars, "ECHO", "errors");
break;
case 'c':
+ cmd_opt_is_used = true;
+
options->action_string = pg_strdup(optarg);
if (optarg[0] == '\\')
{
*************** parse_psql_options(int argc, char *argv[
*** 428,433 ****
--- 446,472 ----
else
options->action = ACT_SINGLE_QUERY;
break;
+ case 'C':
+ {
+ Commands *cmds = pg_malloc(sizeof(Commands));
+ Commands *ptr = pset.commands;
+
+ commands_opt_is_used = true;
+
+ if (ptr == NULL)
+ pset.commands = cmds;
+ else
+ {
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = cmds;
+ }
+ cmds->next = NULL;
+ cmds->actions = pg_strdup(optarg);
+ options->action = ACT_COMMAND_LINE;
+ }
+ break;
case 'd':
options->dbname = pg_strdup(optarg);
break;
*************** parse_psql_options(int argc, char *argv[
*** 601,606 ****
--- 640,652 ----
}
}
+ if (cmd_opt_is_used && commands_opt_is_used)
+ {
+ fprintf(stderr, _("%s: options -c/--command and -C/--multi_command cannot be used together\n"),
+ pset.progname);
+ exit(EXIT_FAILURE);
+ }
+
/*
* if we still have arguments, use it as the database name and username
*/
On Tue, Nov 10, 2015 at 2:18 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
Hi
2015-11-05 22:23 GMT+01:00 Robert Haas <robertmhaas@gmail.com>:
On Thu, Nov 5, 2015 at 3:53 PM, Catalin Iacob <iacobcatalin@gmail.com>
wrote:On Thu, Nov 5, 2015 at 5:27 PM, Robert Haas <robertmhaas@gmail.com>
wrote:I wrote some text. But needs some work of native speaker.
It does. It would be nice if some kind reviewer could help volunteer
to clean that up.I'll give it a go sometime next week.
Thanks, that would be great!
I recommend comparing the section on -c and the section on -C, and
probably updating the former as well as adjusting the wording of the
latter. We don't want to repeat all the same details in both places,
but we hopefully want to give people a little clue that if they're
thinking about using -c, they may wish to instead consider -C.
Just catching up with this thread... Using a separate option looks
fine to me, and it's definitely better to leave -c alone due to its
transactional behavior. I guess that it is true that more than one
person got caught by the fact that -c was running all its stuff within
a single transaction, particularly when having queries that do not
like transaction blocks.
-g was replaced by -C option and some other required changes.
I have not idea about good long name. In this moment I used "multi-command".
Can be changed freely.
Or --command-multi, or --multiple-commands, though I have a good
history here at choosing bad names.
The name of this patch is same (although it doesn't use "group-command"
internally anymore) due better orientation.
I have been looking this patch a bit, and here are some comments:
/*
* process slash command if one was given to -c
*/
else if (options.action == ACT_SINGLE_SLASH)
This comment needs to be updated.
+ else if (options.action == ACT_COMMAND_LINE)
+ {
+ pset.notty = true;
+
+ /* use singleline mode, doesn't need semicolon on the
end line */
+ SetVariableBool(pset.vars, "SINGLELINE");
Er, enforcing an option is not user-friendly.
+ /* Is there some unprocessed multi command? */
"Check presence of unprocessed commands"
@@ -451,7 +491,6 @@ MainLoop(FILE *source)
return successResult;
} /* MainLoop() */
-
/*
This is unnecessary diff noise.
+ fprintf(stderr, _("%s: options -c/--command and
-C/--multi_command cannot be used together\n"),
+ pset.progname);
I would rather formulate that as "cannot use --opt1 and --opt2 together".
+ <term><option>-C <replaceable
class="parameter">command(s)</replaceable></></term>
Don't think you need the "(s)" here.
+ <para>
+ Specifies that <application>psql</application> is to execute one or
+ more command strings, <replaceable
class="parameter">commands</replaceable>,
+ and then exit. This is useful in shell scripts. Start-up files
+ (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are
+ ignored with this option.
+ </para>
This is a copy-paste of the same paragraph for option -c.
It seems to me that the documentation should specify that when -C is
used with -1 each individual series of commands is executed within a
transaction block. As far as I understood this command:
psql -1 -c 'SELECT 1;SELECT 2' -c 'SELECT 3;SELECT4'
is equivalent to that:
BEGIN:
SELECT 1;
SELECT 2;
COMMIT;
BEGIN:
SELECT 3;
SELECT 4;
COMMIT;
s/commads/commands/, and the documentation needs a good brush up:
- The first paragraph is a copy of what is used for -c
- Specifying multiple times -C concatenates those series of commands
into mutiple subsets running in their own transaction.
- Documentation should clearly mention what the interactions with -1.
Regards,
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Nov 11, 2015 at 7:01 AM, Michael Paquier <michael.paquier@gmail.com>
wrote:
It seems to me that the documentation should specify that when -C is
used with -1 each individual series of commands is executed within a
transaction block.
In summary:
Default (Not Single + Auto-Commit): One Transactions per parsed statement
in all -Cs [<neither option specified>]
Single + Auto-Commit: One Transaction per -C [--single-transaction] {same
as --no-auto-commit]
Not Single + Not Auto-Commit: One Transaction per -C [--no-auto-commit]
{same as --single-transaction}
Single + Not Auto-Commit: One Transaction covering all -Cs
[--no-auto-commit --single-transaction]
Explanation:
The transactional behavior of -C
can, with defaults, be described thusly:
BEGIN:
-C #1 Statement #1
COMMIT;
BEGIN;
-C #1 Statement #2
COMMIT;
BEGIN;
-C #2 Statement Only
COMMIT;
Basically the explicit representation of Auto-Commit "on" Mode
I don't understand how -c implements the promise of:
"""
If the command string contains multiple SQL commands, they are processed in
a single transaction, unless there are explicit BEGIN/COMMIT commands
included in the string to divide it into multiple transactions.
"""
But my gut (and Pavel) says that this is "legacy behavior" that should not
be carried over to -C. I would suggest going further and disallowing
transaction control statements within -C commands.
Now, in the presence of "--single-transaction" we would convert the
transactional behavior from that shown above to:
BEGIN;
-C #1 Statement #1
-C #1 Statement #2
COMMIT; -- auto-committed;
BEGIN;
-C #2
COMMIT;
Additionally, if the variable AUTOCOMMIT is "off" then the implicit script
should look like:
BEGIN;
-C #1 Statement #1
-C #2 Statement #2
-C #2
COMMIT;
So a "true" single transaction requires setting AUTOCOMMIT to off otherwise
you only get each -C singly.
I would suggest adding an action "--no-auto-commit" option to complete the
existence of the "--single-transaction" option. While the variable method
works it doesn't feel as clean now that we are adding this option that
(can) make direct use of it.
Specifying only --no-auto-commit results in:
BEGIN;
-C #1 Statement #1
-C #1 Statement #2
COMMIT;
BEGIN;
-C #2
COMMIT;
Which is redundant with specifying only "--single-transaction". Each -C
still commits otherwise you would just use the default.
David J.
On Thu, Nov 12, 2015 at 9:35 AM, David G. Johnston
<david.g.johnston@gmail.com> wrote:
On Wed, Nov 11, 2015 at 7:01 AM, Michael Paquier <michael.paquier@gmail.com>
wrote:It seems to me that the documentation should specify that when -C is
used with -1 each individual series of commands is executed within a
transaction block.In summary:
Default (Not Single + Auto-Commit): One Transactions per parsed statement in
all -Cs [<neither option specified>]
Single + Auto-Commit: One Transaction per -C [--single-transaction] {same as
--no-auto-commit]
Not Single + Not Auto-Commit: One Transaction per -C [--no-auto-commit]
{same as --single-transaction}
Single + Not Auto-Commit: One Transaction covering all -Cs [--no-auto-commit
--single-transaction]
Explanation:
I am assuming you refer to this command in your analysis: "#1
Statement #1" being the first statement of the first -C, "#1 Statement
#2" the second statement in the first -C switch, and "Statement Only"
the statement of of a second -C switch. Or simply that:
psql -C 'Statement1,Statement2' -C 'Statement'
The transactional behavior of -C
can, with defaults, be described thusly:
BEGIN:
-C #1 Statement #1
COMMIT;
BEGIN;
-C #1 Statement #2
COMMIT;
BEGIN;
-C #2 Statement Only
COMMIT;
Yep, that's what it does by going though MainLoop().
Basically the explicit representation of Auto-Commit "on" Mode
I don't understand how -c implements the promise of:
"""
If the command string contains multiple SQL commands, they are processed in
a single transaction, unless there are explicit BEGIN/COMMIT commands
included in the string to divide it into multiple transactions.
"""
-c simply processes everything it has within libpq in one shot. This
code path does not care about --single-transaction, and it relies on a
backend check to be sure that nothing not allowed within a transaction
block runs when multiple queries are passed though it.
But my gut (and Pavel) says that this is "legacy behavior" that should not
be carried over to -C. I would suggest going further and disallowing
transaction control statements within -C commands.Now, in the presence of "--single-transaction" we would convert the
transactional behavior from that shown above to:BEGIN;
-C #1 Statement #1
-C #1 Statement #2
COMMIT; -- auto-committed;
BEGIN;
-C #2
COMMIT;
Correct.
Additionally, if the variable AUTOCOMMIT is "off" then the implicit script
should look like:BEGIN;
-C #1 Statement #1
-C #2 Statement #2
-C #2
COMMIT;
So a "true" single transaction requires setting AUTOCOMMIT to off otherwise
you only get each -C singly.
Yeah, that's what -c does actually by relying on the backend to check
incompatibilities regarding stuff that should not run in transaction
blocks.
I would suggest adding an action "--no-auto-commit" option to complete the
existence of the "--single-transaction" option. While the variable method
works it doesn't feel as clean now that we are adding this option that (can)
make direct use of it.Specifying only --no-auto-commit results in:
BEGIN;
-C #1 Statement #1
-C #1 Statement #2
COMMIT;
BEGIN;
-C #2
COMMIT;
Which is redundant with specifying only "--single-transaction". Each -C
still commits otherwise you would just use the default.
Don't you mean that actually:
BEGIN;
-C #1 Statement #1
-C #1 Statement #2
-C #2
COMMIT;
By the way there is no much point to this option. It seems to me that
it is already possible to do it with --set AUTOCOMMIT=off.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2015-11-12 1:35 GMT+01:00 David G. Johnston <david.g.johnston@gmail.com>:
On Wed, Nov 11, 2015 at 7:01 AM, Michael Paquier <
michael.paquier@gmail.com> wrote:It seems to me that the documentation should specify that when -C is
used with -1 each individual series of commands is executed within a
transaction block.In summary:
Default (Not Single + Auto-Commit): One Transactions per parsed statement
in all -Cs [<neither option specified>]
Single + Auto-Commit: One Transaction per -C [--single-transaction] {same
as --no-auto-commit]
Not Single + Not Auto-Commit: One Transaction per -C [--no-auto-commit]
{same as --single-transaction}
Single + Not Auto-Commit: One Transaction covering all -Cs
[--no-auto-commit --single-transaction]
Explanation:The transactional behavior of -C
can, with defaults, be described thusly:BEGIN:
-C #1 Statement #1
COMMIT;
BEGIN;
-C #1 Statement #2
COMMIT;
BEGIN;
-C #2 Statement Only
COMMIT;Basically the explicit representation of Auto-Commit "on" Mode
I don't understand how -c implements the promise of:
"""
If the command string contains multiple SQL commands, they are processed
in a single transaction, unless there are explicit BEGIN/COMMIT commands
included in the string to divide it into multiple transactions.
"""
But my gut (and Pavel) says that this is "legacy behavior" that should not
be carried over to -C. I would suggest going further and disallowing
transaction control statements within -C commands.
This is relative difficult to implement - and from my view, it isn't
necessary
The implementation of "-c" is relative simple and then the options
"--single-transaction" or active autocommit has not effect. The string with
commands is pushed to server in one packet and it is processed as one
multicommand on server side. The implementation of "-C" is much more close
to interactive work - by default it is working in autocommit on mode and
following statements will be executed:
psql -C "cmd1;cmd2" -C "cmd3;cmd4"
executed statements:
cmd1;
cmd2;
cmd3;
cmd4;
or if you are thinking without implicit transactions:
BEGIN; cmd1; COMMIT;
BEGIN; cmd2; COMMIT;
BEGIN; cmd3; COMMIT;
BEGIN; cmd4; COMMIT;
when I use "--single-transaction", then the sequence of commands looks like:
BEGIN;
cmd1;
cmd2;
cmd3;
cmd4;
COMMIT;
I wouldn't to attach --single-transaction" option with individual "-C"
option, because the I feeling "--single-transaction" as global option.
More, partial transactions can be simply ensured by explicit transactions.
So I would to allow BEGIN,COMMIT in "-C" statements:
if I allow 'psql -C "BEGIN; cmd1; cmd2; COMMIT" -C "BEGIN; cmd3;cmd4;
COMMIT"
I am not big fan of some implicit transaction mechanisms and I prefer
simple joining implementation of "-C" with minimum design differences
against interactive work. This design looks simply.
The autocommit off mode is partially different, and I didn't though about
it. It requires explicit COMMIT (if it has to have some sense)
so if I run 'psql -C "cmd1;cmd2" -C"cmd3;cmd4"' in autocommit off mode,
then the result will be
BEGIN
cmd1;
cmd2;
cmd3;
cmd4;
-------- missing transaction end --- effective ROLLBACK -- it can good for
some "dry run" work.
but this mode can to allow
psql -C "cmd1;cmd2;COMMIT" -C "cmd3;cmd4; COMMIT"
It looks little bit obscure, but why not.
Using autocommit off and "--single-transaction" together is equivalent to
"--single-transaction" - but only in this case.
BEGIN; BEGIN; COMMIT; COMMIT isn't error
Regards
Pavel
Show quoted text
Now, in the presence of "--single-transaction" we would convert the
transactional behavior from that shown above to:BEGIN;
-C #1 Statement #1
-C #1 Statement #2
COMMIT; -- auto-committed;
BEGIN;
-C #2
COMMIT;Additionally, if the variable AUTOCOMMIT is "off" then the implicit script
should look like:BEGIN;
-C #1 Statement #1
-C #2 Statement #2
-C #2
COMMIT;So a "true" single transaction requires setting AUTOCOMMIT to off
otherwise you only get each -C singly.I would suggest adding an action "--no-auto-commit" option to complete the
existence of the "--single-transaction" option. While the variable method
works it doesn't feel as clean now that we are adding this option that
(can) make direct use of it.Specifying only --no-auto-commit results in:
BEGIN;
-C #1 Statement #1
-C #1 Statement #2
COMMIT;
BEGIN;
-C #2
COMMIT;Which is redundant with specifying only "--single-transaction". Each -C
still commits otherwise you would just use the default.David J.
So I promised I'd try to document this. I had a look at the proposed
semantics of -C and I think in the patch they're too complicated which
makes explaining them hard.
My assumptions about behaviour without this patch, from reading the
docs and some experimenting, correct me if I'm wrong:
1. psql normally splits its input by ; let's call each piece of the
split a statement
2. for every statement resulting after 1, if it's a \ command it's
interpreted internally, else a query with it is sent to the server,
the result is displayed
3. 1. and 2. happen when the input comes from a file (-f) or from stdin
4. autocommit off changes behaviour in that it sends a BEGIN before
any of the statements after the split in 1 (except for \ commands,
BEGIN or things like VACUUM which don't work within transactions)
5. --single-transaction changes behaviour in that it puts a BEGIN
before the whole input (not around each statement) and a COMMIT after
6. all of the above DON'T apply for -c which very different things: it
doesn't split and instead it sends everything, in one query to the
backend. The backend can execute such a thing (it splits itself by ;)
except in some cases like SELECT + VACUUM. Since the single query is
effectively a single transaction for the backend -c ignores
--single-transaction and autocommit off. Even more, when executing
such a multiple statement the backend only returns results for the
last statement of the query.
From the above it seems -c is a different thing altogether while other
behaviour allows 1 input with multiple commands, multiple results and
works the same on stdin and a file.
So my proposal is: allow a *single* argument for -C and treat its
content *exactly* like the input from stdin or from a file.
This answers all the questions about interactions with
--single-transaction and autocommit naturally: it behaves exactly like
stdin and -f behave today. And having a single parameter is similar to
having a single file or single stdin. Having multiple -C is also
confusing since it seems the statements in one -C are grouped somehow
and the ones in the next -C are another group so this starts feeling
like there's maybe a transaction per -C group etc.
Am I missing something or is it that simple?
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Nov 13, 2015 at 1:54 PM, Catalin Iacob <iacobcatalin@gmail.com>
wrote:
So I promised I'd try to document this. I had a look at the proposed
semantics of -C and I think in the patch they're too complicated which
makes explaining them hard.My assumptions about behaviour without this patch, from reading the
docs and some experimenting, correct me if I'm wrong:1. psql normally splits its input by ; let's call each piece of the
split a statement2. for every statement resulting after 1, if it's a \ command it's
interpreted internally, else a query with it is sent to the server,
the result is displayed3. 1. and 2. happen when the input comes from a file (-f) or from stdin
4. autocommit off changes behaviour in that it sends a BEGIN before
any of the statements after the split in 1 (except for \ commands,
BEGIN or things like VACUUM which don't work within transactions)5. --single-transaction changes behaviour in that it puts a BEGIN
before the whole input (not around each statement) and a COMMIT after6. all of the above DON'T apply for -c which very different things: it
doesn't split and instead it sends everything, in one query to the
backend. The backend can execute such a thing (it splits itself by ;)
except in some cases like SELECT + VACUUM. Since the single query is
effectively a single transaction for the backend -c ignores
--single-transaction and autocommit off. Even more, when executing
such a multiple statement the backend only returns results for the
last statement of the query.From the above it seems -c is a different thing altogether while other
behaviour allows 1 input with multiple commands, multiple results and
works the same on stdin and a file.So my proposal is: allow a *single* argument for -C and treat its
content *exactly* like the input from stdin or from a file.This answers all the questions about interactions with
--single-transaction and autocommit naturally: it behaves exactly like
stdin and -f behave today. And having a single parameter is similar to
having a single file or single stdin. Having multiple -C is also
confusing since it seems the statements in one -C are grouped somehow
and the ones in the next -C are another group so this starts feeling
like there's maybe a transaction per -C group etc.Am I missing something or is it that simple?
While not in patch form here is some food for thought.
Tweaks to -c to link it with -C
6c6
< Specifies that <application>psql</application> is to execute one
---
Specifies that <application>psql</application> is to execute the
12d11
< <para>
32a32,36
Furthermore, only a single instance of this parameter is accepted.
Attempting to provide multiple instances will result in the entire
shell command failing.
</para>
<para>
34,35c38,41
< the <option>-c</option> string often has unexpected results. It's
< better to feed multiple commands to
<application>psql</application>'s
---
the <option>-c</option> string often has unexpected results. Two
better options are available to execute multiple commands in a
controlled manner. You may use the -C option, described next, or
choose to feed multiple commands to
<application>psql</application>'s
Draft -C thoughts
<term><option>-C <replaceable
class="parameter">command(s)</replaceable></></term>
<term><option>--multi-command=<replaceable
class="parameter">command(s)</replaceable></></term>
<listitem>
<para>
Specifies that <application>psql</application> is to execute one or
more command strings, <replaceable
class="parameter">commands</replaceable>,
and then exit. This differs from -c in that multiple instances may
be present
on the same shell command.
</para>
<para>
Also unlike -c, individual <option>-C</option> commands and
statements are executed
in auto-commit mode. The following pseudo-code example describe the
script
that is effectively created.
</para>
<programlisting>
psql -C 'SELECT 1;SELECT 2' -C 'SELECT 3;SELECT4'
psql <<EOF
BEGIN;
SELECT 1;
COMMIT;
BEGIN;
SELECT 2;
COMMIT;
BEGIN;
SELECT 3;
COMMIT;
BEGIN;
SELECT 4;
COMMIT;
EOF
</programlisting>
<para>
Alternatively the option <option>--single-transaction</option> makes
the entire multi-command execute
within a single transaction. There is no option to have entire
<option>-C</option> commands commit
independently of each other; you have to issue separate psql shell
commands.
</para>
<para>
Output from the <option>-C</option> command behaves more script-like
than <option>-c</option> as each
statement within each command is output.
</para>
<para>
As with <option>-c</option> the Start-up files
(<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>)
are ignored if this option is present on the command-line.
</para>
<para>
One particular motivation for introducing <option>-C</option> is the
first command below fails if executed
using <option>-c</option> but now there are two equivalent command
lines that work.
<programlisting>
psql -Atq -C "VACUUM FULL foo; SELECT pg_relation_size('foo')"
psql -Atq -C "VACUUM FULL foo" -C "SELECT pg_relation_size('foo')"
</programlisting>
</para>
On 11/13/2015 03:54 PM, Catalin Iacob wrote:
So my proposal is: allow a *single* argument for -C and treat its
content *exactly* like the input from stdin or from a file.
That seems to me to get rid of the main motivation for this change,
which is to allow multiple such arguments, which together would as as if
they were all written to a file which was then invoked like -f file.
If we can only have a single such argument then the change is of
comparatively little value.
cheers
andrew
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sun, Nov 15, 2015 at 1:27 AM, Andrew Dunstan <andrew@dunslane.net> wrote:
That seems to me to get rid of the main motivation for this change, which is
to allow multiple such arguments, which together would as as if they were
all written to a file which was then invoked like -f file.
It seems to me the motivation is not "multiple command line arguments"
but sending multiple statements to the backend in one psql invocation
without needing bash specific here docs or a temporary file for -f.
Most combinations of such multiple statements can already be sent via
-c which sends them in one query, the backend executes them in one
transaction but the backend rejects some combinations like SELECT +
VACUUM.
I think the proposal was mislead by the apparent similarity with -c
and said "if -c can't do SELECT + VACUUM let's do a sort of repeated
-c and call that -C SELECT -C VACUUM". But why not do the same with -C
"SELECT 1; VACUUM" which works just like having a file with that
content works today but handier for scripts? Doesn't this solve the
exact need in this thread?
I'm arguing that sending multiple statements and executing each in one
transaction (the current proposed semantics of -C) is not like -c and
doesn't need to be "repeated -c" it's exactly like reading stdin or
file passed to -f and solves the original problem.But maybe I'm
missing something.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 11/15/2015 08:50 AM, Catalin Iacob wrote:
On Sun, Nov 15, 2015 at 1:27 AM, Andrew Dunstan <andrew@dunslane.net> wrote:
That seems to me to get rid of the main motivation for this change, which is
to allow multiple such arguments, which together would as as if they were
all written to a file which was then invoked like -f file.It seems to me the motivation is not "multiple command line arguments"
but sending multiple statements to the backend in one psql invocation
without needing bash specific here docs or a temporary file for -f.
Most combinations of such multiple statements can already be sent via
-c which sends them in one query, the backend executes them in one
transaction but the backend rejects some combinations like SELECT +
VACUUM.I think the proposal was mislead by the apparent similarity with -c
and said "if -c can't do SELECT + VACUUM let's do a sort of repeated
-c and call that -C SELECT -C VACUUM". But why not do the same with -C
"SELECT 1; VACUUM" which works just like having a file with that
content works today but handier for scripts? Doesn't this solve the
exact need in this thread?I'm arguing that sending multiple statements and executing each in one
transaction (the current proposed semantics of -C) is not like -c and
doesn't need to be "repeated -c" it's exactly like reading stdin or
file passed to -f and solves the original problem.But maybe I'm
missing something.
I suggest you review the original thread on this subject before a line
was ever written. "multiple" (see subject line on this whole thread) is
clearly what is being asked for. Making people turn that into a single
argument is not what was envisaged. See for example Pavel's original
example involving use of xargs where that's clearly not at all easy.
cheers
andrew
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 11/15/15 9:53 AM, Andrew Dunstan wrote:
I suggest you review the original thread on this subject before a line
was ever written. "multiple" (see subject line on this whole thread) is
clearly what is being asked for. Making people turn that into a single
argument is not what was envisaged. See for example Pavel's original
example involving use of xargs where that's clearly not at all easy.
I can see (small) value in having a new option that is like -c but
interprets the string as a fully-featured script like -f. (Small
because the same behavior can already be had with here strings in bash.)
The behavior should be exactly like -f, including all the behavior with
single-transaction and single-step modes or whatever.
But then I will point out that we currently don't handle multiple -f
options.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 11/15/2015 08:24 PM, Peter Eisentraut wrote:
On 11/15/15 9:53 AM, Andrew Dunstan wrote:
I suggest you review the original thread on this subject before a line
was ever written. "multiple" (see subject line on this whole thread) is
clearly what is being asked for. Making people turn that into a single
argument is not what was envisaged. See for example Pavel's original
example involving use of xargs where that's clearly not at all easy.I can see (small) value in having a new option that is like -c but
interprets the string as a fully-featured script like -f. (Small
because the same behavior can already be had with here strings in bash.)The behavior should be exactly like -f, including all the behavior with
single-transaction and single-step modes or whatever.But then I will point out that we currently don't handle multiple -f
options.
If we can only have one I would say the value is vanishingly small.
As to -f, I don't see why we shouldn't allow multiple such options, only
that nobody has bothered to do it.
cheers
andrew
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sun, Nov 15, 2015 at 3:53 PM, Andrew Dunstan <andrew@dunslane.net> wrote:
I suggest you review the original thread on this subject before a line was
ever written. "multiple" (see subject line on this whole thread) is clearly
what is being asked for. Making people turn that into a single argument is
not what was envisaged. See for example Pavel's original example involving
use of xargs where that's clearly not at all easy.
I couldn't see why it would matter to have multiple -C, but xargs
having -n which consumes more than 1 stdin item is indeed an use case.
When reading the thread I didn't notice it since I didn't know what -n
does.
But multiple -C is confusing since it suggests the groupings matter.
To me at least, it feels weird that -C "SELECT 1; SELECT 2;" -C
"SELECT 3;" is the same as -C "SELECT 1; SELECT 2; SELECT 3" and lots
of other combinations. It feels like the split in groups must mean
something, otherwise why would you support/use multiple groups?
Upthread at least somebody thought each -C group would/should be a
transaction and I can see this confusion coming up again and again,
enough to question whether this patch is an improvement over the
current situation. And if a single -C is too small of an improvement,
maybe it means the whole idea should be dropped. I think the same of
multiple -f as well: to me they're more confusing than helpful for the
same reason.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi
2015-11-16 17:16 GMT+01:00 Catalin Iacob <iacobcatalin@gmail.com>:
On Sun, Nov 15, 2015 at 3:53 PM, Andrew Dunstan <andrew@dunslane.net>
wrote:I suggest you review the original thread on this subject before a line
was
ever written. "multiple" (see subject line on this whole thread) is
clearly
what is being asked for. Making people turn that into a single argument
is
not what was envisaged. See for example Pavel's original example
involving
use of xargs where that's clearly not at all easy.
I couldn't see why it would matter to have multiple -C, but xargs
having -n which consumes more than 1 stdin item is indeed an use case.
When reading the thread I didn't notice it since I didn't know what -n
does.But multiple -C is confusing since it suggests the groupings matter
I disagree
The user can choose the best grouping for better readability and
maintainability.
There is not any real reason to limit
a) number of usage -C option
b) number of commands inside -C option.
The multiple usage of -C option is necessary - the backslash commands with
params have to be alone or last in group
But if it is not necessary, then requirement only one commands per option
is unfriendly
Regards
Pavel
Show quoted text
.
To me at least, it feels weird that -C "SELECT 1; SELECT 2;" -C
"SELECT 3;" is the same as -C "SELECT 1; SELECT 2; SELECT 3" and lots
of other combinations. It feels like the split in groups must mean
something, otherwise why would you support/use multiple groups?
Upthread at least somebody thought each -C group would/should be a
transaction and I can see this confusion coming up again and again,
enough to question whether this patch is an improvement over the
current situation. And if a single -C is too small of an improvement,
maybe it means the whole idea should be dropped. I think the same of
multiple -f as well: to me they're more confusing than helpful for the
same reason.
On 11/16/2015 11:16 AM, Catalin Iacob wrote:
On Sun, Nov 15, 2015 at 3:53 PM, Andrew Dunstan <andrew@dunslane.net> wrote:
I suggest you review the original thread on this subject before a line was
ever written. "multiple" (see subject line on this whole thread) is clearly
what is being asked for. Making people turn that into a single argument is
not what was envisaged. See for example Pavel's original example involving
use of xargs where that's clearly not at all easy.I couldn't see why it would matter to have multiple -C, but xargs
having -n which consumes more than 1 stdin item is indeed an use case.
When reading the thread I didn't notice it since I didn't know what -n
does.But multiple -C is confusing since it suggests the groupings matter.
To me at least, it feels weird that -C "SELECT 1; SELECT 2;" -C
"SELECT 3;" is the same as -C "SELECT 1; SELECT 2; SELECT 3" and lots
of other combinations. It feels like the split in groups must mean
something, otherwise why would you support/use multiple groups?Upthread at least somebody thought each -C group would/should be a
transaction and I can see this confusion coming up again and again,
enough to question whether this patch is an improvement over the
current situation. And if a single -C is too small of an improvement,
maybe it means the whole idea should be dropped. I think the same of
multiple -f as well: to me they're more confusing than helpful for the
same reason.
I honestly don't see what's so confusing about it, and if there is any
confusion then surely we could make sure what's happening is well
documented.
cheers
andrew
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Nov 16, 2015 at 6:05 PM, Andrew Dunstan <andrew@dunslane.net> wrote:
I honestly don't see what's so confusing about it, and if there is any
confusion then surely we could make sure what's happening is well
documented.
+1. I'm actually kind of wondering if we should just back up and
change the way -c works instead, and allow it to be specified more
than once. The current behavior is essentially a crock that has only
backward compatibility to recommend it, and not having two
confusingly-similar options is of some non-trivial value.
--
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
Robert Haas <robertmhaas@gmail.com> writes:
On Mon, Nov 16, 2015 at 6:05 PM, Andrew Dunstan <andrew@dunslane.net> wrote:
I honestly don't see what's so confusing about it, and if there is any
confusion then surely we could make sure what's happening is well
documented.
+1. I'm actually kind of wondering if we should just back up and
change the way -c works instead, and allow it to be specified more
than once. The current behavior is essentially a crock that has only
backward compatibility to recommend it, and not having two
confusingly-similar options is of some non-trivial value.
Well, it's not *entirely* true that it has only backwards compatibility
to recommend it: without -c in its current form, there would be no way
to test multiple-commands-in-one-PQexec cases without hacking up some
custom test infrastructure. That's not a very strong reason maybe, but
it's a reason. And backwards compatibility is usually a strong argument
around here anyway.
I've not been following this thread in any detail, but have we considered
the approach of allowing multiple -c and saying that each -c is a separate
PQexec (or backslash command)? So the semantics of one -c wouldn't change,
but commands submitted through multiple -c switches would behave
relatively unsurprisingly, and we wouldn't need two kinds of switch.
Another issue here is how -1 ought to interact with multiple -c.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Well, it's not *entirely* true that it has only backwards compatibility
to recommend it: without -c in its current form, there would be no way
to test multiple-commands-in-one-PQexec cases without hacking up some
custom test infrastructure. That's not a very strong reason maybe, but
it's a reason. And backwards compatibility is usually a strong argument
around here anyway.I've not been following this thread in any detail, but have we considered
the approach of allowing multiple -c and saying that each -c is a separate
PQexec (or backslash command)? So the semantics of one -c wouldn't change,
but commands submitted through multiple -c switches would behave
relatively unsurprisingly, and we wouldn't need two kinds of switch.
I believe it can work, but there are stronger limit of single PQexec call -
only result of last command is displayed.
Regards
Pavel
Show quoted text
Another issue here is how -1 ought to interact with multiple -c.
regards, tom lane
On Tue, Nov 17, 2015 at 2:25 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Robert Haas <robertmhaas@gmail.com> writes:
On Mon, Nov 16, 2015 at 6:05 PM, Andrew Dunstan <andrew@dunslane.net> wrote:
I honestly don't see what's so confusing about it, and if there is any
confusion then surely we could make sure what's happening is well
documented.+1. I'm actually kind of wondering if we should just back up and
change the way -c works instead, and allow it to be specified more
than once. The current behavior is essentially a crock that has only
backward compatibility to recommend it, and not having two
confusingly-similar options is of some non-trivial value.Well, it's not *entirely* true that it has only backwards compatibility
to recommend it: without -c in its current form, there would be no way
to test multiple-commands-in-one-PQexec cases without hacking up some
custom test infrastructure. That's not a very strong reason maybe, but
it's a reason.
True. We could have a --no-split-commands option for that case, perhaps.
And backwards compatibility is usually a strong argument
around here anyway.
Yeah, but not - at least in my book - at the expense of being stuck
with a confusing interface forever.
I've not been following this thread in any detail, but have we considered
the approach of allowing multiple -c and saying that each -c is a separate
PQexec (or backslash command)? So the semantics of one -c wouldn't change,
but commands submitted through multiple -c switches would behave
relatively unsurprisingly, and we wouldn't need two kinds of switch.Another issue here is how -1 ought to interact with multiple -c.
On a code level, I think the issue here is that ACT_SINGLE_QUERY
bypasses a lot of stuff that happens in the ACT_FILE case: directly in
main, there's process_psqlrc(); inside process_file(), there's the
single_txn handling; then inside MainLoop, there's splitting of
commands and cancel handling and various other stuff. In my
imagination, it's like this because originally psql wasn't nearly as
complicated as it is now, and as features got added in various places,
-c gradually diverged. I don't know whether that's really what
happened, but it seems to me that it would be good to bring those
things back together.
A few years ago there was a proposal to not only allow multiple -c
options, but to allow -c and -f to be intermingled. This seems really
rather useful; I'd like to be able to type psql -c do_this_first -f
script.sql and have that work. But of course it's kind of hard to
figure out how that should behave given the various differences
between -c and -f. I think in the long run we'll be better off
rationalizing the interface; I really doubt how many people, even on
this mailing list, can even enumerate all the differences between -c
and -f. If it's too complicated for hackers to remember, it's
probably not very good for users either.
--
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
2015-11-17 21:00 GMT+01:00 Robert Haas <robertmhaas@gmail.com>:
On Tue, Nov 17, 2015 at 2:25 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Robert Haas <robertmhaas@gmail.com> writes:
On Mon, Nov 16, 2015 at 6:05 PM, Andrew Dunstan <andrew@dunslane.net>
wrote:
I honestly don't see what's so confusing about it, and if there is any
confusion then surely we could make sure what's happening is well
documented.+1. I'm actually kind of wondering if we should just back up and
change the way -c works instead, and allow it to be specified more
than once. The current behavior is essentially a crock that has only
backward compatibility to recommend it, and not having two
confusingly-similar options is of some non-trivial value.Well, it's not *entirely* true that it has only backwards compatibility
to recommend it: without -c in its current form, there would be no way
to test multiple-commands-in-one-PQexec cases without hacking up some
custom test infrastructure. That's not a very strong reason maybe, but
it's a reason.True. We could have a --no-split-commands option for that case, perhaps.
And backwards compatibility is usually a strong argument
around here anyway.Yeah, but not - at least in my book - at the expense of being stuck
with a confusing interface forever.I've not been following this thread in any detail, but have we considered
the approach of allowing multiple -c and saying that each -c is aseparate
PQexec (or backslash command)? So the semantics of one -c wouldn't
change,
but commands submitted through multiple -c switches would behave
relatively unsurprisingly, and we wouldn't need two kinds of switch.Another issue here is how -1 ought to interact with multiple -c.
On a code level, I think the issue here is that ACT_SINGLE_QUERY
bypasses a lot of stuff that happens in the ACT_FILE case: directly in
main, there's process_psqlrc(); inside process_file(), there's the
single_txn handling; then inside MainLoop, there's splitting of
commands and cancel handling and various other stuff. In my
imagination, it's like this because originally psql wasn't nearly as
complicated as it is now, and as features got added in various places,
-c gradually diverged. I don't know whether that's really what
happened, but it seems to me that it would be good to bring those
things back together.A few years ago there was a proposal to not only allow multiple -c
options, but to allow -c and -f to be intermingled. This seems really
rather useful; I'd like to be able to type psql -c do_this_first -f
script.sql and have that work. But of course it's kind of hard to
figure out how that should behave given the various differences
between -c and -f. I think in the long run we'll be better off
rationalizing the interface; I really doubt how many people, even on
this mailing list, can even enumerate all the differences between -c
and -f. If it's too complicated for hackers to remember, it's
probably not very good for users either.
This shouldn't be hard. With proposed patch, you can do "-C '\i xxx' -C '\i
yyyy'" - that is effectively same like multiple -f
and this mix can be really useful }in any order).
Regards
Pavel
Show quoted text
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Robert Haas <robertmhaas@gmail.com> writes:
A few years ago there was a proposal to not only allow multiple -c
options, but to allow -c and -f to be intermingled. This seems really
rather useful; I'd like to be able to type psql -c do_this_first -f
script.sql and have that work. But of course it's kind of hard to
figure out how that should behave given the various differences
between -c and -f.
Hm. That's actually a good reason for changing -c, I guess. (Or else
introducing a -C that is compatible with -f, but I agree that that
seems a bit ugly.)
If we made -c handle its input just like it had come from a file,
then what would we need to explain to people that wanted the old
behavior? I guess we'd need to tell them to use --no-psqlrc and
--single-transaction at least, and "-v ON_ERROR_STOP=1". And
even then it wouldn't replicate the behavior of discarding all
but the last command output. (Maybe nobody out there is relying
on that, but I wouldn't bet on it.) And that's all still assuming
that they don't care about multi-command-per-PQexec in itself, but
only the easily user-visible differences.
So that is kind of looking like a mess, and 90% of the mess is from
not wanting to use a PQexec per -c switch, which if you ask me is
not very much of the value-add here. AFAICS the only thing that's
really in conflict with -f is the implied --no-psqlrc. How about
this design:
1. -c no longer implies --no-psqlrc. That's a backwards incompatibility,
but very easy to explain and very easy to work around.
2. You can have multiple -c and/or -f. Each -c is processed in
the traditional way, ie, either it's a single backslash command
or it's sent in a single PQexec. That doesn't seem to me to have
much impact on the behavior of adjacent -c or -f.
3. If you combine -1 with -c and/or -f, you get one BEGIN inserted
at the beginning and one COMMIT at the end. Nothing else changes.
As long as you put only one SQL command per -c, I don't think that
this definition has any real surprises. And we can discourage
people from putting more than one, saying that that will invoke
legacy behaviors you probably don't want.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 11/17/2015 04:13 PM, Tom Lane wrote:
Robert Haas <robertmhaas@gmail.com> writes:
A few years ago there was a proposal to not only allow multiple -c
options, but to allow -c and -f to be intermingled. This seems really
rather useful; I'd like to be able to type psql -c do_this_first -f
script.sql and have that work. But of course it's kind of hard to
figure out how that should behave given the various differences
between -c and -f.Hm. That's actually a good reason for changing -c, I guess. (Or else
introducing a -C that is compatible with -f, but I agree that that
seems a bit ugly.)If we made -c handle its input just like it had come from a file,
then what would we need to explain to people that wanted the old
behavior? I guess we'd need to tell them to use --no-psqlrc and
--single-transaction at least, and "-v ON_ERROR_STOP=1". And
even then it wouldn't replicate the behavior of discarding all
but the last command output. (Maybe nobody out there is relying
on that, but I wouldn't bet on it.) And that's all still assuming
that they don't care about multi-command-per-PQexec in itself, but
only the easily user-visible differences.So that is kind of looking like a mess, and 90% of the mess is from
not wanting to use a PQexec per -c switch, which if you ask me is
not very much of the value-add here. AFAICS the only thing that's
really in conflict with -f is the implied --no-psqlrc. How about
this design:1. -c no longer implies --no-psqlrc. That's a backwards incompatibility,
but very easy to explain and very easy to work around.2. You can have multiple -c and/or -f. Each -c is processed in
the traditional way, ie, either it's a single backslash command
or it's sent in a single PQexec. That doesn't seem to me to have
much impact on the behavior of adjacent -c or -f.3. If you combine -1 with -c and/or -f, you get one BEGIN inserted
at the beginning and one COMMIT at the end. Nothing else changes.As long as you put only one SQL command per -c, I don't think that
this definition has any real surprises. And we can discourage
people from putting more than one, saying that that will invoke
legacy behaviors you probably don't want.
WFM. The only reason I originally suggested -C was to avoid
compatibility issues. If we're prepared to take that on then I agree
it's better to do what you suggest.
I assume that we won't have any great difficulty in handling
intermingled -c and -f options in the correct order. Essentially I think
we'll have to have a unified list of such arguments.
cheers
andrew
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Tue, Nov 17, 2015 at 10:13 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
1. -c no longer implies --no-psqlrc. That's a backwards incompatibility,
but very easy to explain and very easy to work around.2. You can have multiple -c and/or -f. Each -c is processed in
the traditional way, ie, either it's a single backslash command
or it's sent in a single PQexec. That doesn't seem to me to have
much impact on the behavior of adjacent -c or -f.3. If you combine -1 with -c and/or -f, you get one BEGIN inserted
at the beginning and one COMMIT at the end. Nothing else changes.
And -v AUTOCOMMIT=off should do the same as now for -c: issue a BEGIN
before each single PQexec with the content of each -c.
I like it, it avoids what I didn't like about -C semantics since the
grouping now means something (single PQexec per group) and you even
see the effects of the grouping in the result (only last result of
group is returned). If you don't like that grouping (probably most
people won't) the solution is intuitive: split the group to multiple
-c.
Another incompatibility is that -1 is now silently ignored by -c so
for example psql -1 -c VACUUM now works and it won't work with the new
semantics. But this seems like a good thing because it reflects that
VACUUM doesn't work in a transaction so I don't think it should stop
this proposal from going ahead.
I'll try to write the documentation patch for these semantics sometime
next week.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
1. -c no longer implies --no-psqlrc. That's a backwards incompatibility,
but very easy to explain and very easy to work around.
This can be very surprising change. Can we disable it temporary by some
environment variable? like NOPSQLRC ?
2. You can have multiple -c and/or -f. Each -c is processed in
the traditional way, ie, either it's a single backslash command
or it's sent in a single PQexec. That doesn't seem to me to have
much impact on the behavior of adjacent -c or -f.3. If you combine -1 with -c and/or -f, you get one BEGIN inserted
at the beginning and one COMMIT at the end. Nothing else changes.As long as you put only one SQL command per -c, I don't think that
this definition has any real surprises. And we can discourage
people from putting more than one, saying that that will invoke
legacy behaviors you probably don't want.
+1
Pavel
Show quoted text
regards, tom lane
Pavel Stehule <pavel.stehule@gmail.com> writes:
1. -c no longer implies --no-psqlrc. That's a backwards incompatibility,
but very easy to explain and very easy to work around.
This can be very surprising change. Can we disable it temporary by some
environment variable? like NOPSQLRC ?
Why would that be better than "add -X to the psql call"?
I think generally the idea here is to have fewer warts, not more.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Nov 18, 2015 at 3:17 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Pavel Stehule <pavel.stehule@gmail.com> writes:
1. -c no longer implies --no-psqlrc. That's a backwards incompatibility,
but very easy to explain and very easy to work around.This can be very surprising change. Can we disable it temporary by some
environment variable? like NOPSQLRC ?Why would that be better than "add -X to the psql call"?
I think generally the idea here is to have fewer warts, not more.
Amen to that.
--
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
2015-11-18 21:17 GMT+01:00 Tom Lane <tgl@sss.pgh.pa.us>:
Pavel Stehule <pavel.stehule@gmail.com> writes:
1. -c no longer implies --no-psqlrc. That's a backwards
incompatibility,
but very easy to explain and very easy to work around.
This can be very surprising change. Can we disable it temporary by some
environment variable? like NOPSQLRC ?Why would that be better than "add -X to the psql call"?
I think generally the idea here is to have fewer warts, not more.
I can set environment variable once and all scripts will running without
psqlrc, without searching all scripts and editing. If we are breaking
compatibility, then we can be little bit friendly to admins, users, ...
It isn't necessary, but it can decrease a possible impacts
Pavel
Show quoted text
regards, tom lane
On Wed, Nov 18, 2015 at 5:49 PM, Catalin Iacob <iacobcatalin@gmail.com> wrote:
On Tue, Nov 17, 2015 at 10:13 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
1. -c no longer implies --no-psqlrc. That's a backwards incompatibility,
but very easy to explain and very easy to work around.2. You can have multiple -c and/or -f. Each -c is processed in
the traditional way, ie, either it's a single backslash command
or it's sent in a single PQexec. That doesn't seem to me to have
much impact on the behavior of adjacent -c or -f.3. If you combine -1 with -c and/or -f, you get one BEGIN inserted
at the beginning and one COMMIT at the end. Nothing else changes.
I'll try to write the documentation patch for these semantics sometime
next week.
Attached is my attempt at a documentation patch, feedback welcome. I'm
assuming Pavel will pick up the implementation, if not I could also
try it.
Attachments:
Update-docs-for-repeated-c.patchbinary/octet-stream; name=Update-docs-for-repeated-c.patchDownload
From dff689aa6518cd0100e296573e16f9175dd4c07e Mon Sep 17 00:00:00 2001
From: Catalin Iacob <iacobcatalin@gmail.com>
Date: Wed, 25 Nov 2015 08:04:43 +0100
Subject: [PATCH] Update docs for repeated -c
---
doc/src/sgml/ref/psql-ref.sgml | 106 ++++++++++++++++++++++++-----------------
1 file changed, 62 insertions(+), 44 deletions(-)
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 5899bb4..2928c92 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -38,9 +38,10 @@ PostgreSQL documentation
<productname>PostgreSQL</productname>. It enables you to type in
queries interactively, issue them to
<productname>PostgreSQL</productname>, and see the query results.
- Alternatively, input can be from a file. In addition, it provides a
- number of meta-commands and various shell-like features to
- facilitate writing scripts and automating a wide variety of tasks.
+ Alternatively, input can be from a file or from command line
+ arguments. In addition, it provides a number of meta-commands and various
+ shell-like features to facilitate writing scripts and automating a wide
+ variety of tasks.
</para>
</refsect1>
@@ -89,38 +90,45 @@ PostgreSQL documentation
<term><option>--command=<replaceable class="parameter">command</replaceable></></term>
<listitem>
<para>
- Specifies that <application>psql</application> is to execute one
- command string, <replaceable class="parameter">command</replaceable>,
- and then exit. This is useful in shell scripts. Start-up files
- (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are
- ignored with this option.
+ Specifies that <application>psql</application> is to execute the given
+ command string, <replaceable class="parameter">command</replaceable>.
+ This option can be repeated and combined in any order with
+ the <option>-f</option> option.
</para>
<para>
- <replaceable class="parameter">command</replaceable> must be either
- a command string that is completely parsable by the server (i.e.,
- it contains no <application>psql</application>-specific features),
- or a single backslash command. Thus you cannot mix
- <acronym>SQL</acronym> and <application>psql</application>
- meta-commands with this option. To achieve that, you could
- pipe the string into <application>psql</application>, for example:
- <literal>echo '\x \\ SELECT * FROM foo;' | psql</literal>.
+ <replaceable class="parameter">command</replaceable> must be either a
+ command string that is completely parsable by the server (i.e., it
+ contains no <application>psql</application>-specific features), or a
+ single backslash command. Thus you cannot mix
+ <acronym>SQL</acronym> and <application>psql</application> meta-commands
+ with this option. To achieve that, you could use
+ repeated <option>-c</option> options or pipe the string
+ into <application>psql</application>, for example:
+ <literal>psql -c '\x' -c 'SELECT * FROM foo;'</literal> or
+ <literal>echo '\x \\ SELECT * FROM foo;' | psql</literal>
(<literal>\\</> is the separator meta-command.)
</para>
<para>
- If the command string contains multiple SQL commands, they are
- processed in a single transaction, unless there are explicit
- <command>BEGIN</>/<command>COMMIT</> commands included in the
- string to divide it into multiple transactions. This is
- different from the behavior when the same string is fed to
- <application>psql</application>'s standard input. Also, only
- the result of the last SQL command is returned.
+ Each command string passed to <option>-c</option> is sent to the server
+ as a single query. Because of this, the server executes it as a single
+ transaction, even if a command string contains
+ multiple <acronym>SQL</acronym> commands, unless there are
+ explicit <command>BEGIN</>/<command>COMMIT</> commands included in the
+ string to divide it into multiple transactions. Also, the server only
+ returns the result of the last <acronym>SQL</acronym> command to the
+ client. This is different from the behavior when the same string with
+ multiple <acronym>SQL</acronym> commands is fed
+ to <application>psql</application>'s standard input because
+ then <application>psql</application> sends each <acronym>SQL</acronym>
+ command separately.
</para>
<para>
- Because of these legacy behaviors, putting more than one command in
- the <option>-c</option> string often has unexpected results. It's
- better to feed multiple commands to <application>psql</application>'s
- standard input, either using <application>echo</application> as
- illustrated above, or via a shell here-document, for example:
+ Because of the execution as a single query, putting more than one
+ command in the <option>-c</option> string often has unexpected results.
+ It's better to use repeated <option>-c</option> commands or feed
+ multiple commands to <application>psql</application>'s standard input,
+ either using <application>echo</application> as illustrated above, or
+ via a shell here-document, for example:
<programlisting>
psql <<EOF
\x
@@ -183,11 +191,13 @@ EOF
<term><option>--file=<replaceable class="parameter">filename</replaceable></></term>
<listitem>
<para>
- Use the file <replaceable class="parameter">filename</replaceable>
- as the source of commands instead of reading commands interactively.
- After the file is processed, <application>psql</application>
- terminates. This is in many ways equivalent to the meta-command
- <command>\i</command>.
+ Use the file <replaceable class="parameter">filename</replaceable> as
+ the source of commands instead of reading commands interactively. This
+ option can be repeated and combined in any order with
+ the <option>-c</option> option. After the commands in
+ every <option>-c</option> command string and <option>-f</option> file
+ are processed, <application>psql</application> terminates. This option
+ is in many ways equivalent to the meta-command <command>\i</command>.
</para>
<para>
@@ -539,20 +549,21 @@ EOF
<term><option>--single-transaction</option></term>
<listitem>
<para>
- When <application>psql</application> executes a script, adding
- this option wraps <command>BEGIN</>/<command>COMMIT</> around the
- script to execute it as a single transaction. This ensures that
- either all the commands complete successfully, or no changes are
- applied.
+ When <application>psql</application> executes commands from a script
+ and/or a <option>-c</option> option, adding this option
+ wraps <command>BEGIN</>/<command>COMMIT</> around all of those
+ commands as a whole to execute them as a single transaction. This
+ ensures that either all the commands complete successfully, or no
+ changes are applied.
</para>
<para>
- If the script itself uses <command>BEGIN</>, <command>COMMIT</>,
+ If the commands themselves
+ contain <command>BEGIN</>, <command>COMMIT</>,
or <command>ROLLBACK</>, this option will not have the desired
- effects.
- Also, if the script contains any command that cannot be executed
- inside a transaction block, specifying this option will cause that
- command (and hence the whole transaction) to fail.
+ effects. Also, if an individual command cannot be executed inside a
+ transaction block, specifying this option will cause the whole
+ transaction to fail.
</para>
</listitem>
</varlistentry>
@@ -3725,7 +3736,7 @@ PSQL_EDITOR_LINENUMBER_ARG='--line '
<term><filename>psqlrc</filename> and <filename>~/.psqlrc</filename></term>
<listitem>
<para>
- Unless it is passed an <option>-X</option> or <option>-c</option> option,
+ Unless it is passed an <option>-X</option> option,
<application>psql</application> attempts to read and execute commands
from the system-wide startup file (<filename>psqlrc</filename>) and then
the user's personal startup file (<filename>~/.psqlrc</filename>), after
@@ -3819,6 +3830,13 @@ PSQL_EDITOR_LINENUMBER_ARG='--line '
</para>
</listitem>
+ <listitem>
+ <para>
+ Before <productname>PostgreSQL</productname> 9.6, <option>-c</option>
+ used to imply <option>-X</option> and therefore it wouldn't
+ read <filename>psqlrc</filename> files, that is no longer the case.
+ </para>
+ </listitem>
</itemizedlist>
</refsect1>
--
2.6.2
Hi
2015-11-25 17:13 GMT+01:00 Catalin Iacob <iacobcatalin@gmail.com>:
On Wed, Nov 18, 2015 at 5:49 PM, Catalin Iacob <iacobcatalin@gmail.com>
wrote:On Tue, Nov 17, 2015 at 10:13 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
1. -c no longer implies --no-psqlrc. That's a backwards
incompatibility,
but very easy to explain and very easy to work around.
2. You can have multiple -c and/or -f. Each -c is processed in
the traditional way, ie, either it's a single backslash command
or it's sent in a single PQexec. That doesn't seem to me to have
much impact on the behavior of adjacent -c or -f.3. If you combine -1 with -c and/or -f, you get one BEGIN inserted
at the beginning and one COMMIT at the end. Nothing else changes.I'll try to write the documentation patch for these semantics sometime
next week.Attached is my attempt at a documentation patch, feedback welcome. I'm
assuming Pavel will pick up the implementation, if not I could also
try it.
I am sorry for delay - the end of year :(
Attached patch per Tom Lane proposal.
* multiple -c -f options are supported, the order of options is respected
* the statements for one -c options are executed in transactions
* Iacob's doc patch merged
Regards
Pavel
Attachments:
psql-group-command-07.patchtext/x-patch; charset=US-ASCII; name=psql-group-command-07.patchDownload
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
new file mode 100644
index 5899bb4..2928c92
*** a/doc/src/sgml/ref/psql-ref.sgml
--- b/doc/src/sgml/ref/psql-ref.sgml
*************** PostgreSQL documentation
*** 38,46 ****
<productname>PostgreSQL</productname>. It enables you to type in
queries interactively, issue them to
<productname>PostgreSQL</productname>, and see the query results.
! Alternatively, input can be from a file. In addition, it provides a
! number of meta-commands and various shell-like features to
! facilitate writing scripts and automating a wide variety of tasks.
</para>
</refsect1>
--- 38,47 ----
<productname>PostgreSQL</productname>. It enables you to type in
queries interactively, issue them to
<productname>PostgreSQL</productname>, and see the query results.
! Alternatively, input can be from a file or from command line
! arguments. In addition, it provides a number of meta-commands and various
! shell-like features to facilitate writing scripts and automating a wide
! variety of tasks.
</para>
</refsect1>
*************** PostgreSQL documentation
*** 89,126 ****
<term><option>--command=<replaceable class="parameter">command</replaceable></></term>
<listitem>
<para>
! Specifies that <application>psql</application> is to execute one
! command string, <replaceable class="parameter">command</replaceable>,
! and then exit. This is useful in shell scripts. Start-up files
! (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are
! ignored with this option.
</para>
<para>
! <replaceable class="parameter">command</replaceable> must be either
! a command string that is completely parsable by the server (i.e.,
! it contains no <application>psql</application>-specific features),
! or a single backslash command. Thus you cannot mix
! <acronym>SQL</acronym> and <application>psql</application>
! meta-commands with this option. To achieve that, you could
! pipe the string into <application>psql</application>, for example:
! <literal>echo '\x \\ SELECT * FROM foo;' | psql</literal>.
(<literal>\\</> is the separator meta-command.)
</para>
<para>
! If the command string contains multiple SQL commands, they are
! processed in a single transaction, unless there are explicit
! <command>BEGIN</>/<command>COMMIT</> commands included in the
! string to divide it into multiple transactions. This is
! different from the behavior when the same string is fed to
! <application>psql</application>'s standard input. Also, only
! the result of the last SQL command is returned.
</para>
<para>
! Because of these legacy behaviors, putting more than one command in
! the <option>-c</option> string often has unexpected results. It's
! better to feed multiple commands to <application>psql</application>'s
! standard input, either using <application>echo</application> as
! illustrated above, or via a shell here-document, for example:
<programlisting>
psql <<EOF
\x
--- 90,134 ----
<term><option>--command=<replaceable class="parameter">command</replaceable></></term>
<listitem>
<para>
! Specifies that <application>psql</application> is to execute the given
! command string, <replaceable class="parameter">command</replaceable>.
! This option can be repeated and combined in any order with
! the <option>-f</option> option.
</para>
<para>
! <replaceable class="parameter">command</replaceable> must be either a
! command string that is completely parsable by the server (i.e., it
! contains no <application>psql</application>-specific features), or a
! single backslash command. Thus you cannot mix
! <acronym>SQL</acronym> and <application>psql</application> meta-commands
! with this option. To achieve that, you could use
! repeated <option>-c</option> options or pipe the string
! into <application>psql</application>, for example:
! <literal>psql -c '\x' -c 'SELECT * FROM foo;'</literal> or
! <literal>echo '\x \\ SELECT * FROM foo;' | psql</literal>
(<literal>\\</> is the separator meta-command.)
</para>
<para>
! Each command string passed to <option>-c</option> is sent to the server
! as a single query. Because of this, the server executes it as a single
! transaction, even if a command string contains
! multiple <acronym>SQL</acronym> commands, unless there are
! explicit <command>BEGIN</>/<command>COMMIT</> commands included in the
! string to divide it into multiple transactions. Also, the server only
! returns the result of the last <acronym>SQL</acronym> command to the
! client. This is different from the behavior when the same string with
! multiple <acronym>SQL</acronym> commands is fed
! to <application>psql</application>'s standard input because
! then <application>psql</application> sends each <acronym>SQL</acronym>
! command separately.
</para>
<para>
! Because of the execution as a single query, putting more than one
! command in the <option>-c</option> string often has unexpected results.
! It's better to use repeated <option>-c</option> commands or feed
! multiple commands to <application>psql</application>'s standard input,
! either using <application>echo</application> as illustrated above, or
! via a shell here-document, for example:
<programlisting>
psql <<EOF
\x
*************** EOF
*** 183,193 ****
<term><option>--file=<replaceable class="parameter">filename</replaceable></></term>
<listitem>
<para>
! Use the file <replaceable class="parameter">filename</replaceable>
! as the source of commands instead of reading commands interactively.
! After the file is processed, <application>psql</application>
! terminates. This is in many ways equivalent to the meta-command
! <command>\i</command>.
</para>
<para>
--- 191,203 ----
<term><option>--file=<replaceable class="parameter">filename</replaceable></></term>
<listitem>
<para>
! Use the file <replaceable class="parameter">filename</replaceable> as
! the source of commands instead of reading commands interactively. This
! option can be repeated and combined in any order with
! the <option>-c</option> option. After the commands in
! every <option>-c</option> command string and <option>-f</option> file
! are processed, <application>psql</application> terminates. This option
! is in many ways equivalent to the meta-command <command>\i</command>.
</para>
<para>
*************** EOF
*** 539,558 ****
<term><option>--single-transaction</option></term>
<listitem>
<para>
! When <application>psql</application> executes a script, adding
! this option wraps <command>BEGIN</>/<command>COMMIT</> around the
! script to execute it as a single transaction. This ensures that
! either all the commands complete successfully, or no changes are
! applied.
</para>
<para>
! If the script itself uses <command>BEGIN</>, <command>COMMIT</>,
or <command>ROLLBACK</>, this option will not have the desired
! effects.
! Also, if the script contains any command that cannot be executed
! inside a transaction block, specifying this option will cause that
! command (and hence the whole transaction) to fail.
</para>
</listitem>
</varlistentry>
--- 549,569 ----
<term><option>--single-transaction</option></term>
<listitem>
<para>
! When <application>psql</application> executes commands from a script
! and/or a <option>-c</option> option, adding this option
! wraps <command>BEGIN</>/<command>COMMIT</> around all of those
! commands as a whole to execute them as a single transaction. This
! ensures that either all the commands complete successfully, or no
! changes are applied.
</para>
<para>
! If the commands themselves
! contain <command>BEGIN</>, <command>COMMIT</>,
or <command>ROLLBACK</>, this option will not have the desired
! effects. Also, if an individual command cannot be executed inside a
! transaction block, specifying this option will cause the whole
! transaction to fail.
</para>
</listitem>
</varlistentry>
*************** PSQL_EDITOR_LINENUMBER_ARG='--line '
*** 3725,3731 ****
<term><filename>psqlrc</filename> and <filename>~/.psqlrc</filename></term>
<listitem>
<para>
! Unless it is passed an <option>-X</option> or <option>-c</option> option,
<application>psql</application> attempts to read and execute commands
from the system-wide startup file (<filename>psqlrc</filename>) and then
the user's personal startup file (<filename>~/.psqlrc</filename>), after
--- 3736,3742 ----
<term><filename>psqlrc</filename> and <filename>~/.psqlrc</filename></term>
<listitem>
<para>
! Unless it is passed an <option>-X</option> option,
<application>psql</application> attempts to read and execute commands
from the system-wide startup file (<filename>psqlrc</filename>) and then
the user's personal startup file (<filename>~/.psqlrc</filename>), after
*************** PSQL_EDITOR_LINENUMBER_ARG='--line '
*** 3819,3824 ****
--- 3830,3842 ----
</para>
</listitem>
+ <listitem>
+ <para>
+ Before <productname>PostgreSQL</productname> 9.6, <option>-c</option>
+ used to imply <option>-X</option> and therefore it wouldn't
+ read <filename>psqlrc</filename> files, that is no longer the case.
+ </para>
+ </listitem>
</itemizedlist>
</refsect1>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
new file mode 100644
index 72c00c1..5e3b4ed
*** a/src/bin/psql/command.c
--- b/src/bin/psql/command.c
*************** exec_command(const char *cmd,
*** 918,924 ****
include_relative = (strcmp(cmd, "ir") == 0
|| strcmp(cmd, "include_relative") == 0);
expand_tilde(&fname);
! success = (process_file(fname, false, include_relative) == EXIT_SUCCESS);
free(fname);
}
}
--- 918,924 ----
include_relative = (strcmp(cmd, "ir") == 0
|| strcmp(cmd, "include_relative") == 0);
expand_tilde(&fname);
! success = (process_file(fname, include_relative) == EXIT_SUCCESS);
free(fname);
}
}
*************** do_edit(const char *filename_arg, PQExpB
*** 2287,2299 ****
* the file from where the currently processed file (if any) is located.
*/
int
! process_file(char *filename, bool single_txn, bool use_relative_path)
{
FILE *fd;
int result;
char *oldfilename;
char relpath[MAXPGPATH];
- PGresult *res;
if (!filename)
{
--- 2287,2298 ----
* the file from where the currently processed file (if any) is located.
*/
int
! process_file(char *filename, bool use_relative_path)
{
FILE *fd;
int result;
char *oldfilename;
char relpath[MAXPGPATH];
if (!filename)
{
*************** process_file(char *filename, bool single
*** 2338,2374 ****
oldfilename = pset.inputfile;
pset.inputfile = filename;
- if (single_txn)
- {
- if ((res = PSQLexec("BEGIN")) == NULL)
- {
- if (pset.on_error_stop)
- {
- result = EXIT_USER;
- goto error;
- }
- }
- else
- PQclear(res);
- }
-
result = MainLoop(fd);
- if (single_txn)
- {
- if ((res = PSQLexec("COMMIT")) == NULL)
- {
- if (pset.on_error_stop)
- {
- result = EXIT_USER;
- goto error;
- }
- }
- else
- PQclear(res);
- }
-
- error:
if (fd != stdin)
fclose(fd);
--- 2337,2344 ----
diff --git a/src/bin/psql/command.h b/src/bin/psql/command.h
new file mode 100644
index 54385e8..c817600
*** a/src/bin/psql/command.h
--- b/src/bin/psql/command.h
*************** typedef enum _backslashResult
*** 27,33 ****
extern backslashResult HandleSlashCmds(PsqlScanState scan_state,
PQExpBuffer query_buf);
! extern int process_file(char *filename, bool single_txn, bool use_relative_path);
extern bool do_pset(const char *param,
const char *value,
--- 27,33 ----
extern backslashResult HandleSlashCmds(PsqlScanState scan_state,
PQExpBuffer query_buf);
! extern int process_file(char *filename, bool use_relative_path);
extern bool do_pset(const char *param,
const char *value,
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
new file mode 100644
index 0e266a3..fff16c0
*** a/src/bin/psql/common.c
--- b/src/bin/psql/common.c
*************** recognized_connection_string(const char
*** 1886,1888 ****
--- 1886,1911 ----
{
return uri_prefix_length(connstr) != 0 || strchr(connstr, '=') != NULL;
}
+
+ /*
+ * Support for list of actions. The SimpleStringList cannot be used due possible
+ * combination different actions with the requirement to save the order.
+ */
+ void
+ simple_action_list_append(SimpleActionList *list, int atyp, const char *val)
+ {
+ SimpleActionListCell *cell;
+
+ cell = (SimpleActionListCell *)
+ pg_malloc(offsetof(SimpleActionListCell, val) + strlen(val) + 1);
+
+ cell->next = NULL;
+ cell->atyp = atyp;
+ strcpy(cell->val, val);
+
+ if (list->tail)
+ list->tail->next = cell;
+ else
+ list->head = cell;
+ list->tail = cell;
+ }
diff --git a/src/bin/psql/common.h b/src/bin/psql/common.h
new file mode 100644
index caf31d1..0965c35
*** a/src/bin/psql/common.h
--- b/src/bin/psql/common.h
***************
*** 14,21 ****
--- 14,43 ----
#include "print.h"
+ enum _atypes
+ {
+ ACT_SINGLE_QUERY,
+ ACT_SINGLE_SLASH,
+ ACT_FILE
+ };
+
+ typedef struct SimpleActionListCell
+ {
+ struct SimpleActionListCell *next;
+ int atyp;
+ char val[FLEXIBLE_ARRAY_MEMBER];
+ } SimpleActionListCell;
+
+ typedef struct SimpleActionList
+ {
+ SimpleActionListCell *head;
+ SimpleActionListCell *tail;
+ } SimpleActionList;
+
#define atooid(x) ((Oid) strtoul((x), NULL, 10))
+ extern void simple_action_list_append(SimpleActionList *list, int atyp, const char *val);
+
extern bool setQFout(const char *fname);
extern void psql_error(const char *fmt,...) pg_attribute_printf(1, 2);
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
new file mode 100644
index 7aa997d..eda779b
*** a/src/bin/psql/startup.c
--- b/src/bin/psql/startup.c
*************** PsqlSettings pset;
*** 51,60 ****
enum _actions
{
ACT_NOTHING = 0,
- ACT_SINGLE_SLASH,
ACT_LIST_DB,
! ACT_SINGLE_QUERY,
! ACT_FILE
};
struct adhoc_opts
--- 51,58 ----
enum _actions
{
ACT_NOTHING = 0,
ACT_LIST_DB,
! ACT_FILE_STDIN
};
struct adhoc_opts
*************** struct adhoc_opts
*** 69,74 ****
--- 67,73 ----
bool no_readline;
bool no_psqlrc;
bool single_txn;
+ SimpleActionList actions;
};
static void parse_psql_options(int argc, char *argv[],
*************** main(int argc, char *argv[])
*** 159,164 ****
--- 158,166 ----
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
+ options.actions.head = NULL;
+ options.actions.tail = NULL;
+
parse_psql_options(argc, argv, &options);
/*
*************** main(int argc, char *argv[])
*** 166,179 ****
* as if the user had specified "-f -". This lets single-transaction mode
* work in this case.
*/
! if (options.action == ACT_NOTHING && pset.notty)
{
! options.action = ACT_FILE;
options.action_string = NULL;
}
/* Bail out if -1 was specified but will be ignored. */
! if (options.single_txn && options.action != ACT_FILE && options.action == ACT_NOTHING)
{
fprintf(stderr, _("%s: -1 can only be used in non-interactive mode\n"), pset.progname);
exit(EXIT_FAILURE);
--- 168,182 ----
* as if the user had specified "-f -". This lets single-transaction mode
* work in this case.
*/
! if (options.action == ACT_NOTHING && options.actions.head == NULL && pset.notty)
{
! options.action = ACT_FILE_STDIN;
options.action_string = NULL;
}
/* Bail out if -1 was specified but will be ignored. */
! if (options.single_txn && options.action != ACT_FILE_STDIN && options.action == ACT_NOTHING
! && options.actions.head == NULL)
{
fprintf(stderr, _("%s: -1 can only be used in non-interactive mode\n"), pset.progname);
exit(EXIT_FAILURE);
*************** main(int argc, char *argv[])
*** 282,332 ****
/*
* Now find something to do
*/
!
! /*
! * process file given by -f
! */
! if (options.action == ACT_FILE)
{
if (!options.no_psqlrc)
process_psqlrc(argv[0]);
! successResult = process_file(options.action_string, options.single_txn, false);
! }
! /*
! * process slash command if one was given to -c
! */
! else if (options.action == ACT_SINGLE_SLASH)
! {
! PsqlScanState scan_state;
! if (pset.echo == PSQL_ECHO_ALL)
! puts(options.action_string);
! scan_state = psql_scan_create();
! psql_scan_setup(scan_state,
! options.action_string,
! strlen(options.action_string));
! successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
! ? EXIT_SUCCESS : EXIT_FAILURE;
! psql_scan_destroy(scan_state);
! }
! /*
! * If the query given to -c was a normal one, send it
! */
! else if (options.action == ACT_SINGLE_QUERY)
! {
! if (pset.echo == PSQL_ECHO_ALL)
! puts(options.action_string);
! successResult = SendQuery(options.action_string)
! ? EXIT_SUCCESS : EXIT_FAILURE;
! }
/*
* or otherwise enter interactive main loop
*/
--- 285,368 ----
/*
* Now find something to do
*/
! if (options.actions.head)
{
+ PGresult *res;
+ SimpleActionListCell *cell;
+
if (!options.no_psqlrc)
process_psqlrc(argv[0]);
! successResult = EXIT_SUCCESS; /* be compiler quiete */
! if (options.single_txn)
! {
! if ((res = PSQLexec("BEGIN")) == NULL)
! {
! if (pset.on_error_stop)
! {
! successResult = EXIT_USER;
! goto error;
! }
! }
! else
! PQclear(res);
! }
! for (cell = options.actions.head; cell; cell = cell->next)
! {
! if (cell->atyp == ACT_SINGLE_QUERY)
! {
! if (pset.echo == PSQL_ECHO_ALL)
! puts(cell->val);
! successResult = SendQuery(cell->val)
! ? EXIT_SUCCESS : EXIT_FAILURE;
! }
! else if (cell->atyp == ACT_SINGLE_SLASH)
! {
! PsqlScanState scan_state;
! if (pset.echo == PSQL_ECHO_ALL)
! puts(cell->val);
! scan_state = psql_scan_create();
! psql_scan_setup(scan_state,
! cell->val,
! strlen(cell->val));
! successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
! ? EXIT_SUCCESS : EXIT_FAILURE;
! psql_scan_destroy(scan_state);
! }
! else
! {
! /* ACT_FILE */
! successResult = process_file(cell->val, false);
! }
!
! if (successResult != EXIT_SUCCESS && pset.on_error_stop)
! break;
! }
!
! if (options.single_txn)
! {
! if ((res = PSQLexec("COMMIT")) == NULL)
! {
! if (pset.on_error_stop)
! {
! successResult = EXIT_USER;
! goto error;
! }
! }
! else
! PQclear(res);
! }
+ error:
+ ;
+ }
/*
* or otherwise enter interactive main loop
*/
*************** parse_psql_options(int argc, char *argv[
*** 419,432 ****
SetVariable(pset.vars, "ECHO", "errors");
break;
case 'c':
- options->action_string = pg_strdup(optarg);
if (optarg[0] == '\\')
! {
! options->action = ACT_SINGLE_SLASH;
! options->action_string++;
! }
else
! options->action = ACT_SINGLE_QUERY;
break;
case 'd':
options->dbname = pg_strdup(optarg);
--- 455,468 ----
SetVariable(pset.vars, "ECHO", "errors");
break;
case 'c':
if (optarg[0] == '\\')
! simple_action_list_append(&options->actions,
! ACT_SINGLE_SLASH,
! pstrdup(optarg + 1));
else
! simple_action_list_append(&options->actions,
! ACT_SINGLE_QUERY,
! pstrdup(optarg));
break;
case 'd':
options->dbname = pg_strdup(optarg);
*************** parse_psql_options(int argc, char *argv[
*** 438,445 ****
SetVariableBool(pset.vars, "ECHO_HIDDEN");
break;
case 'f':
! options->action = ACT_FILE;
! options->action_string = pg_strdup(optarg);
break;
case 'F':
pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
--- 474,482 ----
SetVariableBool(pset.vars, "ECHO_HIDDEN");
break;
case 'f':
! simple_action_list_append(&options->actions,
! ACT_FILE,
! pg_strdup(optarg));
break;
case 'F':
pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
*************** process_psqlrc_file(char *filename)
*** 674,684 ****
/* check for minor version first, then major, then no version */
if (access(psqlrc_minor, R_OK) == 0)
! (void) process_file(psqlrc_minor, false, false);
else if (access(psqlrc_major, R_OK) == 0)
! (void) process_file(psqlrc_major, false, false);
else if (access(filename, R_OK) == 0)
! (void) process_file(filename, false, false);
free(psqlrc_minor);
free(psqlrc_major);
--- 711,721 ----
/* check for minor version first, then major, then no version */
if (access(psqlrc_minor, R_OK) == 0)
! (void) process_file(psqlrc_minor, false);
else if (access(psqlrc_major, R_OK) == 0)
! (void) process_file(psqlrc_major, false);
else if (access(filename, R_OK) == 0)
! (void) process_file(filename, false);
free(psqlrc_minor);
free(psqlrc_major);
On Thu, Nov 26, 2015 at 4:21 AM, Pavel Stehule wrote:
Attached patch per Tom Lane proposal.
* multiple -c -f options are supported, the order of options is respected
* the statements for one -c options are executed in transactions
* Iacob's doc patch merged
enum _actions
{
ACT_NOTHING = 0,
- ACT_SINGLE_SLASH,
ACT_LIST_DB,
- ACT_SINGLE_QUERY,
- ACT_FILE
+ ACT_FILE_STDIN
};
Removing some items from the list of potential actions and creating a
new sublist listing action types is a bit weird. Why not grouping them
together and allow for example -l as well in the list of things that
is considered as a repeatable action? It seems to me that we could
simplify the code this way, and instead of ACT_NOTHING we could check
if the list of actions is empty or not.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2015-11-30 15:17 GMT+01:00 Michael Paquier <michael.paquier@gmail.com>:
On Thu, Nov 26, 2015 at 4:21 AM, Pavel Stehule wrote:
Attached patch per Tom Lane proposal.
* multiple -c -f options are supported, the order of options is respected
* the statements for one -c options are executed in transactions
* Iacob's doc patch mergedenum _actions
{
ACT_NOTHING = 0,
- ACT_SINGLE_SLASH,
ACT_LIST_DB,
- ACT_SINGLE_QUERY,
- ACT_FILE
+ ACT_FILE_STDIN
};Removing some items from the list of potential actions and creating a
new sublist listing action types is a bit weird. Why not grouping them
together and allow for example -l as well in the list of things that
is considered as a repeatable action? It seems to me that we could
simplify the code this way, and instead of ACT_NOTHING we could check
if the list of actions is empty or not.
fixed
Regards
Pavel
Show quoted text
--
Michael
Attachments:
psql-group-command-08.patchtext/x-patch; charset=US-ASCII; name=psql-group-command-08.patchDownload
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
new file mode 100644
index 5899bb4..2928c92
*** a/doc/src/sgml/ref/psql-ref.sgml
--- b/doc/src/sgml/ref/psql-ref.sgml
*************** PostgreSQL documentation
*** 38,46 ****
<productname>PostgreSQL</productname>. It enables you to type in
queries interactively, issue them to
<productname>PostgreSQL</productname>, and see the query results.
! Alternatively, input can be from a file. In addition, it provides a
! number of meta-commands and various shell-like features to
! facilitate writing scripts and automating a wide variety of tasks.
</para>
</refsect1>
--- 38,47 ----
<productname>PostgreSQL</productname>. It enables you to type in
queries interactively, issue them to
<productname>PostgreSQL</productname>, and see the query results.
! Alternatively, input can be from a file or from command line
! arguments. In addition, it provides a number of meta-commands and various
! shell-like features to facilitate writing scripts and automating a wide
! variety of tasks.
</para>
</refsect1>
*************** PostgreSQL documentation
*** 89,126 ****
<term><option>--command=<replaceable class="parameter">command</replaceable></></term>
<listitem>
<para>
! Specifies that <application>psql</application> is to execute one
! command string, <replaceable class="parameter">command</replaceable>,
! and then exit. This is useful in shell scripts. Start-up files
! (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are
! ignored with this option.
</para>
<para>
! <replaceable class="parameter">command</replaceable> must be either
! a command string that is completely parsable by the server (i.e.,
! it contains no <application>psql</application>-specific features),
! or a single backslash command. Thus you cannot mix
! <acronym>SQL</acronym> and <application>psql</application>
! meta-commands with this option. To achieve that, you could
! pipe the string into <application>psql</application>, for example:
! <literal>echo '\x \\ SELECT * FROM foo;' | psql</literal>.
(<literal>\\</> is the separator meta-command.)
</para>
<para>
! If the command string contains multiple SQL commands, they are
! processed in a single transaction, unless there are explicit
! <command>BEGIN</>/<command>COMMIT</> commands included in the
! string to divide it into multiple transactions. This is
! different from the behavior when the same string is fed to
! <application>psql</application>'s standard input. Also, only
! the result of the last SQL command is returned.
</para>
<para>
! Because of these legacy behaviors, putting more than one command in
! the <option>-c</option> string often has unexpected results. It's
! better to feed multiple commands to <application>psql</application>'s
! standard input, either using <application>echo</application> as
! illustrated above, or via a shell here-document, for example:
<programlisting>
psql <<EOF
\x
--- 90,134 ----
<term><option>--command=<replaceable class="parameter">command</replaceable></></term>
<listitem>
<para>
! Specifies that <application>psql</application> is to execute the given
! command string, <replaceable class="parameter">command</replaceable>.
! This option can be repeated and combined in any order with
! the <option>-f</option> option.
</para>
<para>
! <replaceable class="parameter">command</replaceable> must be either a
! command string that is completely parsable by the server (i.e., it
! contains no <application>psql</application>-specific features), or a
! single backslash command. Thus you cannot mix
! <acronym>SQL</acronym> and <application>psql</application> meta-commands
! with this option. To achieve that, you could use
! repeated <option>-c</option> options or pipe the string
! into <application>psql</application>, for example:
! <literal>psql -c '\x' -c 'SELECT * FROM foo;'</literal> or
! <literal>echo '\x \\ SELECT * FROM foo;' | psql</literal>
(<literal>\\</> is the separator meta-command.)
</para>
<para>
! Each command string passed to <option>-c</option> is sent to the server
! as a single query. Because of this, the server executes it as a single
! transaction, even if a command string contains
! multiple <acronym>SQL</acronym> commands, unless there are
! explicit <command>BEGIN</>/<command>COMMIT</> commands included in the
! string to divide it into multiple transactions. Also, the server only
! returns the result of the last <acronym>SQL</acronym> command to the
! client. This is different from the behavior when the same string with
! multiple <acronym>SQL</acronym> commands is fed
! to <application>psql</application>'s standard input because
! then <application>psql</application> sends each <acronym>SQL</acronym>
! command separately.
</para>
<para>
! Because of the execution as a single query, putting more than one
! command in the <option>-c</option> string often has unexpected results.
! It's better to use repeated <option>-c</option> commands or feed
! multiple commands to <application>psql</application>'s standard input,
! either using <application>echo</application> as illustrated above, or
! via a shell here-document, for example:
<programlisting>
psql <<EOF
\x
*************** EOF
*** 183,193 ****
<term><option>--file=<replaceable class="parameter">filename</replaceable></></term>
<listitem>
<para>
! Use the file <replaceable class="parameter">filename</replaceable>
! as the source of commands instead of reading commands interactively.
! After the file is processed, <application>psql</application>
! terminates. This is in many ways equivalent to the meta-command
! <command>\i</command>.
</para>
<para>
--- 191,203 ----
<term><option>--file=<replaceable class="parameter">filename</replaceable></></term>
<listitem>
<para>
! Use the file <replaceable class="parameter">filename</replaceable> as
! the source of commands instead of reading commands interactively. This
! option can be repeated and combined in any order with
! the <option>-c</option> option. After the commands in
! every <option>-c</option> command string and <option>-f</option> file
! are processed, <application>psql</application> terminates. This option
! is in many ways equivalent to the meta-command <command>\i</command>.
</para>
<para>
*************** EOF
*** 539,558 ****
<term><option>--single-transaction</option></term>
<listitem>
<para>
! When <application>psql</application> executes a script, adding
! this option wraps <command>BEGIN</>/<command>COMMIT</> around the
! script to execute it as a single transaction. This ensures that
! either all the commands complete successfully, or no changes are
! applied.
</para>
<para>
! If the script itself uses <command>BEGIN</>, <command>COMMIT</>,
or <command>ROLLBACK</>, this option will not have the desired
! effects.
! Also, if the script contains any command that cannot be executed
! inside a transaction block, specifying this option will cause that
! command (and hence the whole transaction) to fail.
</para>
</listitem>
</varlistentry>
--- 549,569 ----
<term><option>--single-transaction</option></term>
<listitem>
<para>
! When <application>psql</application> executes commands from a script
! and/or a <option>-c</option> option, adding this option
! wraps <command>BEGIN</>/<command>COMMIT</> around all of those
! commands as a whole to execute them as a single transaction. This
! ensures that either all the commands complete successfully, or no
! changes are applied.
</para>
<para>
! If the commands themselves
! contain <command>BEGIN</>, <command>COMMIT</>,
or <command>ROLLBACK</>, this option will not have the desired
! effects. Also, if an individual command cannot be executed inside a
! transaction block, specifying this option will cause the whole
! transaction to fail.
</para>
</listitem>
</varlistentry>
*************** PSQL_EDITOR_LINENUMBER_ARG='--line '
*** 3725,3731 ****
<term><filename>psqlrc</filename> and <filename>~/.psqlrc</filename></term>
<listitem>
<para>
! Unless it is passed an <option>-X</option> or <option>-c</option> option,
<application>psql</application> attempts to read and execute commands
from the system-wide startup file (<filename>psqlrc</filename>) and then
the user's personal startup file (<filename>~/.psqlrc</filename>), after
--- 3736,3742 ----
<term><filename>psqlrc</filename> and <filename>~/.psqlrc</filename></term>
<listitem>
<para>
! Unless it is passed an <option>-X</option> option,
<application>psql</application> attempts to read and execute commands
from the system-wide startup file (<filename>psqlrc</filename>) and then
the user's personal startup file (<filename>~/.psqlrc</filename>), after
*************** PSQL_EDITOR_LINENUMBER_ARG='--line '
*** 3819,3824 ****
--- 3830,3842 ----
</para>
</listitem>
+ <listitem>
+ <para>
+ Before <productname>PostgreSQL</productname> 9.6, <option>-c</option>
+ used to imply <option>-X</option> and therefore it wouldn't
+ read <filename>psqlrc</filename> files, that is no longer the case.
+ </para>
+ </listitem>
</itemizedlist>
</refsect1>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
new file mode 100644
index 438a4ec..d642803
*** a/src/bin/psql/command.c
--- b/src/bin/psql/command.c
*************** exec_command(const char *cmd,
*** 916,922 ****
include_relative = (strcmp(cmd, "ir") == 0
|| strcmp(cmd, "include_relative") == 0);
expand_tilde(&fname);
! success = (process_file(fname, false, include_relative) == EXIT_SUCCESS);
free(fname);
}
}
--- 916,922 ----
include_relative = (strcmp(cmd, "ir") == 0
|| strcmp(cmd, "include_relative") == 0);
expand_tilde(&fname);
! success = (process_file(fname, include_relative) == EXIT_SUCCESS);
free(fname);
}
}
*************** do_edit(const char *filename_arg, PQExpB
*** 2284,2296 ****
* the file from where the currently processed file (if any) is located.
*/
int
! process_file(char *filename, bool single_txn, bool use_relative_path)
{
FILE *fd;
int result;
char *oldfilename;
char relpath[MAXPGPATH];
- PGresult *res;
if (!filename)
{
--- 2284,2295 ----
* the file from where the currently processed file (if any) is located.
*/
int
! process_file(char *filename, bool use_relative_path)
{
FILE *fd;
int result;
char *oldfilename;
char relpath[MAXPGPATH];
if (!filename)
{
*************** process_file(char *filename, bool single
*** 2335,2371 ****
oldfilename = pset.inputfile;
pset.inputfile = filename;
- if (single_txn)
- {
- if ((res = PSQLexec("BEGIN")) == NULL)
- {
- if (pset.on_error_stop)
- {
- result = EXIT_USER;
- goto error;
- }
- }
- else
- PQclear(res);
- }
-
result = MainLoop(fd);
- if (single_txn)
- {
- if ((res = PSQLexec("COMMIT")) == NULL)
- {
- if (pset.on_error_stop)
- {
- result = EXIT_USER;
- goto error;
- }
- }
- else
- PQclear(res);
- }
-
- error:
if (fd != stdin)
fclose(fd);
--- 2334,2341 ----
diff --git a/src/bin/psql/command.h b/src/bin/psql/command.h
new file mode 100644
index 54385e8..c817600
*** a/src/bin/psql/command.h
--- b/src/bin/psql/command.h
*************** typedef enum _backslashResult
*** 27,33 ****
extern backslashResult HandleSlashCmds(PsqlScanState scan_state,
PQExpBuffer query_buf);
! extern int process_file(char *filename, bool single_txn, bool use_relative_path);
extern bool do_pset(const char *param,
const char *value,
--- 27,33 ----
extern backslashResult HandleSlashCmds(PsqlScanState scan_state,
PQExpBuffer query_buf);
! extern int process_file(char *filename, bool use_relative_path);
extern bool do_pset(const char *param,
const char *value,
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
new file mode 100644
index 0e266a3..96e5225
*** a/src/bin/psql/common.c
--- b/src/bin/psql/common.c
*************** recognized_connection_string(const char
*** 1886,1888 ****
--- 1886,1911 ----
{
return uri_prefix_length(connstr) != 0 || strchr(connstr, '=') != NULL;
}
+
+ /*
+ * Support for list of actions. The SimpleStringList cannot be used due possible
+ * combination different actions with the requirement to save the order.
+ */
+ void
+ simple_action_list_append(SimpleActionList *list, int action, const char *val)
+ {
+ SimpleActionListCell *cell;
+
+ cell = (SimpleActionListCell *)
+ pg_malloc(offsetof(SimpleActionListCell, val) + strlen(val) + 1);
+
+ cell->next = NULL;
+ cell->action = action;
+ strcpy(cell->val, val);
+
+ if (list->tail)
+ list->tail->next = cell;
+ else
+ list->head = cell;
+ list->tail = cell;
+ }
diff --git a/src/bin/psql/common.h b/src/bin/psql/common.h
new file mode 100644
index caf31d1..6bdee98
*** a/src/bin/psql/common.h
--- b/src/bin/psql/common.h
***************
*** 14,21 ****
--- 14,44 ----
#include "print.h"
+ enum _actions
+ {
+ ACT_LIST_DB,
+ ACT_SINGLE_QUERY,
+ ACT_SINGLE_SLASH,
+ ACT_FILE
+ };
+
+ typedef struct SimpleActionListCell
+ {
+ struct SimpleActionListCell *next;
+ int action;
+ char val[FLEXIBLE_ARRAY_MEMBER];
+ } SimpleActionListCell;
+
+ typedef struct SimpleActionList
+ {
+ SimpleActionListCell *head;
+ SimpleActionListCell *tail;
+ } SimpleActionList;
+
#define atooid(x) ((Oid) strtoul((x), NULL, 10))
+ extern void simple_action_list_append(SimpleActionList *list, int action, const char *val);
+
extern bool setQFout(const char *fname);
extern void psql_error(const char *fmt,...) pg_attribute_printf(1, 2);
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
new file mode 100644
index 7aa997d..3f909df
*** a/src/bin/psql/startup.c
--- b/src/bin/psql/startup.c
*************** PsqlSettings pset;
*** 44,62 ****
#define PSQLRC "psqlrc.conf"
#endif
- /*
- * Structures to pass information between the option parsing routine
- * and the main function
- */
- enum _actions
- {
- ACT_NOTHING = 0,
- ACT_SINGLE_SLASH,
- ACT_LIST_DB,
- ACT_SINGLE_QUERY,
- ACT_FILE
- };
-
struct adhoc_opts
{
char *dbname;
--- 44,49 ----
*************** struct adhoc_opts
*** 64,76 ****
char *port;
char *username;
char *logfilename;
- enum _actions action;
char *action_string;
bool no_readline;
bool no_psqlrc;
bool single_txn;
};
static void parse_psql_options(int argc, char *argv[],
struct adhoc_opts * options);
static void process_psqlrc(char *argv0);
--- 51,65 ----
char *port;
char *username;
char *logfilename;
char *action_string;
bool no_readline;
bool no_psqlrc;
bool single_txn;
+ bool use_stdin;
+ SimpleActionList actions;
};
+ static bool use_default_dbname(struct adhoc_opts *options);
static void parse_psql_options(int argc, char *argv[],
struct adhoc_opts * options);
static void process_psqlrc(char *argv0);
*************** main(int argc, char *argv[])
*** 159,164 ****
--- 148,157 ----
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
+ options.actions.head = NULL;
+ options.actions.tail = NULL;
+ options.use_stdin = false;
+
parse_psql_options(argc, argv, &options);
/*
*************** main(int argc, char *argv[])
*** 166,179 ****
* as if the user had specified "-f -". This lets single-transaction mode
* work in this case.
*/
! if (options.action == ACT_NOTHING && pset.notty)
! {
! options.action = ACT_FILE;
! options.action_string = NULL;
! }
/* Bail out if -1 was specified but will be ignored. */
! if (options.single_txn && options.action != ACT_FILE && options.action == ACT_NOTHING)
{
fprintf(stderr, _("%s: -1 can only be used in non-interactive mode\n"), pset.progname);
exit(EXIT_FAILURE);
--- 159,168 ----
* as if the user had specified "-f -". This lets single-transaction mode
* work in this case.
*/
! options.use_stdin = options.actions.head == NULL && pset.notty;
/* Bail out if -1 was specified but will be ignored. */
! if (options.single_txn && !options.use_stdin && options.actions.head == NULL)
{
fprintf(stderr, _("%s: -1 can only be used in non-interactive mode\n"), pset.progname);
exit(EXIT_FAILURE);
*************** main(int argc, char *argv[])
*** 217,224 ****
keywords[3] = "password";
values[3] = password;
keywords[4] = "dbname";
! values[4] = (options.action == ACT_LIST_DB &&
! options.dbname == NULL) ?
"postgres" : options.dbname;
keywords[5] = "fallback_application_name";
values[5] = pset.progname;
--- 206,212 ----
keywords[3] = "password";
values[3] = password;
keywords[4] = "dbname";
! values[4] = use_default_dbname(&options) ?
"postgres" : options.dbname;
keywords[5] = "fallback_application_name";
values[5] = pset.progname;
*************** main(int argc, char *argv[])
*** 259,276 ****
SyncVariables();
- if (options.action == ACT_LIST_DB)
- {
- int success;
-
- if (!options.no_psqlrc)
- process_psqlrc(argv[0]);
-
- success = listAllDbs(NULL, false);
- PQfinish(pset.db);
- exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
- }
-
if (options.logfilename)
{
pset.logfile = fopen(options.logfilename, "a");
--- 247,252 ----
*************** main(int argc, char *argv[])
*** 279,332 ****
pset.progname, options.logfilename, strerror(errno));
}
! /*
! * Now find something to do
! */
/*
! * process file given by -f
*/
! if (options.action == ACT_FILE)
{
! if (!options.no_psqlrc)
! process_psqlrc(argv[0]);
! successResult = process_file(options.action_string, options.single_txn, false);
! }
! /*
! * process slash command if one was given to -c
! */
! else if (options.action == ACT_SINGLE_SLASH)
! {
! PsqlScanState scan_state;
! if (pset.echo == PSQL_ECHO_ALL)
! puts(options.action_string);
! scan_state = psql_scan_create();
! psql_scan_setup(scan_state,
! options.action_string,
! strlen(options.action_string));
! successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
! ? EXIT_SUCCESS : EXIT_FAILURE;
! psql_scan_destroy(scan_state);
! }
! /*
! * If the query given to -c was a normal one, send it
! */
! else if (options.action == ACT_SINGLE_QUERY)
! {
! if (pset.echo == PSQL_ECHO_ALL)
! puts(options.action_string);
! successResult = SendQuery(options.action_string)
! ? EXIT_SUCCESS : EXIT_FAILURE;
! }
/*
* or otherwise enter interactive main loop
*/
--- 255,348 ----
pset.progname, options.logfilename, strerror(errno));
}
! if (!options.no_psqlrc)
! process_psqlrc(argv[0]);
/*
! * Now find something to do
*/
! if (options.actions.head)
{
! PGresult *res;
! SimpleActionListCell *cell;
! successResult = EXIT_SUCCESS; /* be compiler quiete */
! if (options.single_txn)
! {
! if ((res = PSQLexec("BEGIN")) == NULL)
! {
! if (pset.on_error_stop)
! {
! successResult = EXIT_USER;
! goto error;
! }
! }
! else
! PQclear(res);
! }
! for (cell = options.actions.head; cell; cell = cell->next)
! {
! if (cell->action == ACT_LIST_DB)
! {
! successResult = listAllDbs(NULL, false);
! }
! else if (cell->action == ACT_SINGLE_QUERY)
! {
! if (pset.echo == PSQL_ECHO_ALL)
! puts(cell->val);
! successResult = SendQuery(cell->val)
! ? EXIT_SUCCESS : EXIT_FAILURE;
! }
! else if (cell->action == ACT_SINGLE_SLASH)
! {
! PsqlScanState scan_state;
! if (pset.echo == PSQL_ECHO_ALL)
! puts(cell->val);
! scan_state = psql_scan_create();
! psql_scan_setup(scan_state,
! cell->val,
! strlen(cell->val));
! successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
! ? EXIT_SUCCESS : EXIT_FAILURE;
! psql_scan_destroy(scan_state);
! }
! else
! {
! /* ACT_FILE */
! successResult = process_file(cell->val, false);
! }
!
! if (successResult != EXIT_SUCCESS && pset.on_error_stop)
! break;
! }
!
! if (options.use_stdin)
! successResult = process_file(NULL, false);
!
! if (options.single_txn)
! {
! if ((res = PSQLexec("COMMIT")) == NULL)
! {
! if (pset.on_error_stop)
! {
! successResult = EXIT_USER;
! goto error;
! }
! }
! else
! PQclear(res);
! }
+ error:
+ ;
+ }
/*
* or otherwise enter interactive main loop
*/
*************** main(int argc, char *argv[])
*** 351,356 ****
--- 367,392 ----
return successResult;
}
+ /*
+ * Default dbname "postgres" can be used when no other dbname
+ * is entered and when only action ACT_LIST_DB is used
+ */
+ static bool
+ use_default_dbname(struct adhoc_opts *options)
+ {
+ SimpleActionListCell *cell;
+
+ if (options->dbname != NULL)
+ return false;
+
+ for (cell = options->actions.head; cell; cell = cell->next)
+ {
+ if (cell->action != ACT_LIST_DB)
+ return false;
+ }
+
+ return true;
+ }
/*
* Parse command line options
*************** parse_psql_options(int argc, char *argv[
*** 419,432 ****
SetVariable(pset.vars, "ECHO", "errors");
break;
case 'c':
- options->action_string = pg_strdup(optarg);
if (optarg[0] == '\\')
! {
! options->action = ACT_SINGLE_SLASH;
! options->action_string++;
! }
else
! options->action = ACT_SINGLE_QUERY;
break;
case 'd':
options->dbname = pg_strdup(optarg);
--- 455,468 ----
SetVariable(pset.vars, "ECHO", "errors");
break;
case 'c':
if (optarg[0] == '\\')
! simple_action_list_append(&options->actions,
! ACT_SINGLE_SLASH,
! pstrdup(optarg + 1));
else
! simple_action_list_append(&options->actions,
! ACT_SINGLE_QUERY,
! pstrdup(optarg));
break;
case 'd':
options->dbname = pg_strdup(optarg);
*************** parse_psql_options(int argc, char *argv[
*** 438,445 ****
SetVariableBool(pset.vars, "ECHO_HIDDEN");
break;
case 'f':
! options->action = ACT_FILE;
! options->action_string = pg_strdup(optarg);
break;
case 'F':
pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
--- 474,482 ----
SetVariableBool(pset.vars, "ECHO_HIDDEN");
break;
case 'f':
! simple_action_list_append(&options->actions,
! ACT_FILE,
! pg_strdup(optarg));
break;
case 'F':
pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
*************** parse_psql_options(int argc, char *argv[
*** 452,458 ****
pset.popt.topt.format = PRINT_HTML;
break;
case 'l':
! options->action = ACT_LIST_DB;
break;
case 'L':
options->logfilename = pg_strdup(optarg);
--- 489,497 ----
pset.popt.topt.format = PRINT_HTML;
break;
case 'l':
! simple_action_list_append(&options->actions,
! ACT_LIST_DB,
! pg_strdup(""));
break;
case 'L':
options->logfilename = pg_strdup(optarg);
*************** process_psqlrc_file(char *filename)
*** 674,684 ****
/* check for minor version first, then major, then no version */
if (access(psqlrc_minor, R_OK) == 0)
! (void) process_file(psqlrc_minor, false, false);
else if (access(psqlrc_major, R_OK) == 0)
! (void) process_file(psqlrc_major, false, false);
else if (access(filename, R_OK) == 0)
! (void) process_file(filename, false, false);
free(psqlrc_minor);
free(psqlrc_major);
--- 713,723 ----
/* check for minor version first, then major, then no version */
if (access(psqlrc_minor, R_OK) == 0)
! (void) process_file(psqlrc_minor, false);
else if (access(psqlrc_major, R_OK) == 0)
! (void) process_file(psqlrc_major, false);
else if (access(filename, R_OK) == 0)
! (void) process_file(filename, false);
free(psqlrc_minor);
free(psqlrc_major);
On Tue, Dec 1, 2015 at 11:46 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
2015-11-30 15:17 GMT+01:00 Michael Paquier <michael.paquier@gmail.com>:
Removing some items from the list of potential actions and creating a
new sublist listing action types is a bit weird. Why not grouping them
together and allow for example -l as well in the list of things that
is considered as a repeatable action? It seems to me that we could
simplify the code this way, and instead of ACT_NOTHING we could check
if the list of actions is empty or not.fixed
Thanks for the patch. I have to admit that adding ACT_LIST_DB in the
list of actions was not actually a good idea. It makes the patch
uglier.
Except that, I just had an in-depth look at this patch, and there are
a couple of things that looked strange:
- ACT_LIST_DB would live better if removed from the list of actions
and be used as a separate, independent option. My previous suggestion
was unadapted. Sorry.
- There is not much meaning to have simple_action_list_append and all
its structures in common.c and common.h. Its use is limited in
startup.c (this code is basically a duplicate of dumputils.c still
things are rather different, justifying the duplication) and
centralized around parse_psql_options.
- use_stdin is not necessary. It is sufficient to rely on actions.head
== NULL instead.
- The documentation is pretty clear. That's nice.
Attached is a patch implementing those suggestions. This simplifies
the code without changing its usefulness. If you are fine with those
changes I will switch this patch as ready for committer.
Regards,
--
Michael
Attachments:
20151201_psql_commands.patchtext/x-patch; charset=US-ASCII; name=20151201_psql_commands.patchDownload
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 5899bb4..2928c92 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -38,9 +38,10 @@ PostgreSQL documentation
<productname>PostgreSQL</productname>. It enables you to type in
queries interactively, issue them to
<productname>PostgreSQL</productname>, and see the query results.
- Alternatively, input can be from a file. In addition, it provides a
- number of meta-commands and various shell-like features to
- facilitate writing scripts and automating a wide variety of tasks.
+ Alternatively, input can be from a file or from command line
+ arguments. In addition, it provides a number of meta-commands and various
+ shell-like features to facilitate writing scripts and automating a wide
+ variety of tasks.
</para>
</refsect1>
@@ -89,38 +90,45 @@ PostgreSQL documentation
<term><option>--command=<replaceable class="parameter">command</replaceable></></term>
<listitem>
<para>
- Specifies that <application>psql</application> is to execute one
- command string, <replaceable class="parameter">command</replaceable>,
- and then exit. This is useful in shell scripts. Start-up files
- (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are
- ignored with this option.
+ Specifies that <application>psql</application> is to execute the given
+ command string, <replaceable class="parameter">command</replaceable>.
+ This option can be repeated and combined in any order with
+ the <option>-f</option> option.
</para>
<para>
- <replaceable class="parameter">command</replaceable> must be either
- a command string that is completely parsable by the server (i.e.,
- it contains no <application>psql</application>-specific features),
- or a single backslash command. Thus you cannot mix
- <acronym>SQL</acronym> and <application>psql</application>
- meta-commands with this option. To achieve that, you could
- pipe the string into <application>psql</application>, for example:
- <literal>echo '\x \\ SELECT * FROM foo;' | psql</literal>.
+ <replaceable class="parameter">command</replaceable> must be either a
+ command string that is completely parsable by the server (i.e., it
+ contains no <application>psql</application>-specific features), or a
+ single backslash command. Thus you cannot mix
+ <acronym>SQL</acronym> and <application>psql</application> meta-commands
+ with this option. To achieve that, you could use
+ repeated <option>-c</option> options or pipe the string
+ into <application>psql</application>, for example:
+ <literal>psql -c '\x' -c 'SELECT * FROM foo;'</literal> or
+ <literal>echo '\x \\ SELECT * FROM foo;' | psql</literal>
(<literal>\\</> is the separator meta-command.)
</para>
<para>
- If the command string contains multiple SQL commands, they are
- processed in a single transaction, unless there are explicit
- <command>BEGIN</>/<command>COMMIT</> commands included in the
- string to divide it into multiple transactions. This is
- different from the behavior when the same string is fed to
- <application>psql</application>'s standard input. Also, only
- the result of the last SQL command is returned.
+ Each command string passed to <option>-c</option> is sent to the server
+ as a single query. Because of this, the server executes it as a single
+ transaction, even if a command string contains
+ multiple <acronym>SQL</acronym> commands, unless there are
+ explicit <command>BEGIN</>/<command>COMMIT</> commands included in the
+ string to divide it into multiple transactions. Also, the server only
+ returns the result of the last <acronym>SQL</acronym> command to the
+ client. This is different from the behavior when the same string with
+ multiple <acronym>SQL</acronym> commands is fed
+ to <application>psql</application>'s standard input because
+ then <application>psql</application> sends each <acronym>SQL</acronym>
+ command separately.
</para>
<para>
- Because of these legacy behaviors, putting more than one command in
- the <option>-c</option> string often has unexpected results. It's
- better to feed multiple commands to <application>psql</application>'s
- standard input, either using <application>echo</application> as
- illustrated above, or via a shell here-document, for example:
+ Because of the execution as a single query, putting more than one
+ command in the <option>-c</option> string often has unexpected results.
+ It's better to use repeated <option>-c</option> commands or feed
+ multiple commands to <application>psql</application>'s standard input,
+ either using <application>echo</application> as illustrated above, or
+ via a shell here-document, for example:
<programlisting>
psql <<EOF
\x
@@ -183,11 +191,13 @@ EOF
<term><option>--file=<replaceable class="parameter">filename</replaceable></></term>
<listitem>
<para>
- Use the file <replaceable class="parameter">filename</replaceable>
- as the source of commands instead of reading commands interactively.
- After the file is processed, <application>psql</application>
- terminates. This is in many ways equivalent to the meta-command
- <command>\i</command>.
+ Use the file <replaceable class="parameter">filename</replaceable> as
+ the source of commands instead of reading commands interactively. This
+ option can be repeated and combined in any order with
+ the <option>-c</option> option. After the commands in
+ every <option>-c</option> command string and <option>-f</option> file
+ are processed, <application>psql</application> terminates. This option
+ is in many ways equivalent to the meta-command <command>\i</command>.
</para>
<para>
@@ -539,20 +549,21 @@ EOF
<term><option>--single-transaction</option></term>
<listitem>
<para>
- When <application>psql</application> executes a script, adding
- this option wraps <command>BEGIN</>/<command>COMMIT</> around the
- script to execute it as a single transaction. This ensures that
- either all the commands complete successfully, or no changes are
- applied.
+ When <application>psql</application> executes commands from a script
+ and/or a <option>-c</option> option, adding this option
+ wraps <command>BEGIN</>/<command>COMMIT</> around all of those
+ commands as a whole to execute them as a single transaction. This
+ ensures that either all the commands complete successfully, or no
+ changes are applied.
</para>
<para>
- If the script itself uses <command>BEGIN</>, <command>COMMIT</>,
+ If the commands themselves
+ contain <command>BEGIN</>, <command>COMMIT</>,
or <command>ROLLBACK</>, this option will not have the desired
- effects.
- Also, if the script contains any command that cannot be executed
- inside a transaction block, specifying this option will cause that
- command (and hence the whole transaction) to fail.
+ effects. Also, if an individual command cannot be executed inside a
+ transaction block, specifying this option will cause the whole
+ transaction to fail.
</para>
</listitem>
</varlistentry>
@@ -3725,7 +3736,7 @@ PSQL_EDITOR_LINENUMBER_ARG='--line '
<term><filename>psqlrc</filename> and <filename>~/.psqlrc</filename></term>
<listitem>
<para>
- Unless it is passed an <option>-X</option> or <option>-c</option> option,
+ Unless it is passed an <option>-X</option> option,
<application>psql</application> attempts to read and execute commands
from the system-wide startup file (<filename>psqlrc</filename>) and then
the user's personal startup file (<filename>~/.psqlrc</filename>), after
@@ -3819,6 +3830,13 @@ PSQL_EDITOR_LINENUMBER_ARG='--line '
</para>
</listitem>
+ <listitem>
+ <para>
+ Before <productname>PostgreSQL</productname> 9.6, <option>-c</option>
+ used to imply <option>-X</option> and therefore it wouldn't
+ read <filename>psqlrc</filename> files, that is no longer the case.
+ </para>
+ </listitem>
</itemizedlist>
</refsect1>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 438a4ec..d642803 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -916,7 +916,7 @@ exec_command(const char *cmd,
include_relative = (strcmp(cmd, "ir") == 0
|| strcmp(cmd, "include_relative") == 0);
expand_tilde(&fname);
- success = (process_file(fname, false, include_relative) == EXIT_SUCCESS);
+ success = (process_file(fname, include_relative) == EXIT_SUCCESS);
free(fname);
}
}
@@ -2284,13 +2284,12 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
* the file from where the currently processed file (if any) is located.
*/
int
-process_file(char *filename, bool single_txn, bool use_relative_path)
+process_file(char *filename, bool use_relative_path)
{
FILE *fd;
int result;
char *oldfilename;
char relpath[MAXPGPATH];
- PGresult *res;
if (!filename)
{
@@ -2335,37 +2334,8 @@ process_file(char *filename, bool single_txn, bool use_relative_path)
oldfilename = pset.inputfile;
pset.inputfile = filename;
- if (single_txn)
- {
- if ((res = PSQLexec("BEGIN")) == NULL)
- {
- if (pset.on_error_stop)
- {
- result = EXIT_USER;
- goto error;
- }
- }
- else
- PQclear(res);
- }
-
result = MainLoop(fd);
- if (single_txn)
- {
- if ((res = PSQLexec("COMMIT")) == NULL)
- {
- if (pset.on_error_stop)
- {
- result = EXIT_USER;
- goto error;
- }
- }
- else
- PQclear(res);
- }
-
-error:
if (fd != stdin)
fclose(fd);
diff --git a/src/bin/psql/command.h b/src/bin/psql/command.h
index 54385e8..c817600 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, bool use_relative_path);
+extern int process_file(char *filename, bool use_relative_path);
extern bool do_pset(const char *param,
const char *value,
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 7aa997d..5869eef 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -50,13 +50,24 @@ PsqlSettings pset;
*/
enum _actions
{
- ACT_NOTHING = 0,
- ACT_SINGLE_SLASH,
- ACT_LIST_DB,
ACT_SINGLE_QUERY,
+ ACT_SINGLE_SLASH,
ACT_FILE
};
+typedef struct SimpleActionListCell
+{
+ struct SimpleActionListCell *next;
+ int action;
+ char val[FLEXIBLE_ARRAY_MEMBER];
+} SimpleActionListCell;
+
+typedef struct SimpleActionList
+{
+ SimpleActionListCell *head;
+ SimpleActionListCell *tail;
+} SimpleActionList;
+
struct adhoc_opts
{
char *dbname;
@@ -64,11 +75,11 @@ struct adhoc_opts
char *port;
char *username;
char *logfilename;
- enum _actions action;
- char *action_string;
bool no_readline;
bool no_psqlrc;
bool single_txn;
+ bool list_dbs;
+ SimpleActionList actions;
};
static void parse_psql_options(int argc, char *argv[],
@@ -76,6 +87,8 @@ static void parse_psql_options(int argc, char *argv[],
static void process_psqlrc(char *argv0);
static void process_psqlrc_file(char *filename);
static void showVersion(void);
+static void simple_action_list_append(SimpleActionList *list,
+ int action, const char *val);
static void EstablishVariableSpace(void);
#define NOPAGER 0
@@ -159,6 +172,9 @@ main(int argc, char *argv[])
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
+ options.actions.head = NULL;
+ options.actions.tail = NULL;
+
parse_psql_options(argc, argv, &options);
/*
@@ -166,14 +182,11 @@ main(int argc, char *argv[])
* as if the user had specified "-f -". This lets single-transaction mode
* work in this case.
*/
- if (options.action == ACT_NOTHING && pset.notty)
- {
- options.action = ACT_FILE;
- options.action_string = NULL;
- }
+ if (options.actions.head == NULL && pset.notty)
+ simple_action_list_append(&options.actions, ACT_FILE, "-");
/* Bail out if -1 was specified but will be ignored. */
- if (options.single_txn && options.action != ACT_FILE && options.action == ACT_NOTHING)
+ if (options.single_txn && options.actions.head == NULL)
{
fprintf(stderr, _("%s: -1 can only be used in non-interactive mode\n"), pset.progname);
exit(EXIT_FAILURE);
@@ -217,8 +230,7 @@ main(int argc, char *argv[])
keywords[3] = "password";
values[3] = password;
keywords[4] = "dbname";
- values[4] = (options.action == ACT_LIST_DB &&
- options.dbname == NULL) ?
+ values[4] = (options.list_dbs && options.dbname == NULL) ?
"postgres" : options.dbname;
keywords[5] = "fallback_application_name";
values[5] = pset.progname;
@@ -259,7 +271,7 @@ main(int argc, char *argv[])
SyncVariables();
- if (options.action == ACT_LIST_DB)
+ if (options.list_dbs)
{
int success;
@@ -280,51 +292,90 @@ main(int argc, char *argv[])
}
/*
- * Now find something to do
- */
-
- /*
- * process file given by -f
+ * Now find something to do, process any actions given by caller,
+ * respecting their order of reception.
*/
- if (options.action == ACT_FILE)
+ if (options.actions.head != NULL)
{
- if (!options.no_psqlrc)
- process_psqlrc(argv[0]);
-
- successResult = process_file(options.action_string, options.single_txn, false);
- }
-
- /*
- * process slash command if one was given to -c
- */
- else if (options.action == ACT_SINGLE_SLASH)
- {
- PsqlScanState scan_state;
+ PGresult *res;
+ SimpleActionListCell *cell;
- if (pset.echo == PSQL_ECHO_ALL)
- puts(options.action_string);
+ successResult = EXIT_SUCCESS; /* be compiler quiete */
- scan_state = psql_scan_create();
- psql_scan_setup(scan_state,
- options.action_string,
- strlen(options.action_string));
+ if (!options.no_psqlrc)
+ process_psqlrc(argv[0]);
- successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
- ? EXIT_SUCCESS : EXIT_FAILURE;
+ if (options.single_txn)
+ {
+ if ((res = PSQLexec("BEGIN")) == NULL)
+ {
+ if (pset.on_error_stop)
+ {
+ successResult = EXIT_USER;
+ goto error;
+ }
+ }
+ else
+ PQclear(res);
+ }
- psql_scan_destroy(scan_state);
- }
+ for (cell = options.actions.head; cell; cell = cell->next)
+ {
+ if (cell->action == ACT_SINGLE_QUERY)
+ {
+ if (pset.echo == PSQL_ECHO_ALL)
+ puts(cell->val);
+
+ successResult = SendQuery(cell->val)
+ ? EXIT_SUCCESS : EXIT_FAILURE;
+ }
+ else if (cell->action == ACT_SINGLE_SLASH)
+ {
+ PsqlScanState scan_state;
+
+ if (pset.echo == PSQL_ECHO_ALL)
+ puts(cell->val);
+
+ scan_state = psql_scan_create();
+ psql_scan_setup(scan_state,
+ cell->val,
+ strlen(cell->val));
+
+ successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
+ ? EXIT_SUCCESS : EXIT_FAILURE;
+
+ psql_scan_destroy(scan_state);
+ }
+ else if (cell->action == ACT_FILE)
+ {
+ successResult = process_file(cell->val, false);
+ }
+ else
+ {
+ /* should never come here */
+ Assert(0);
+ }
+
+ if (successResult != EXIT_SUCCESS && pset.on_error_stop)
+ break;
+ }
- /*
- * If the query given to -c was a normal one, send it
- */
- else if (options.action == ACT_SINGLE_QUERY)
- {
- if (pset.echo == PSQL_ECHO_ALL)
- puts(options.action_string);
+ if (options.single_txn)
+ {
+ if ((res = PSQLexec("COMMIT")) == NULL)
+ {
+ if (pset.on_error_stop)
+ {
+ successResult = EXIT_USER;
+ goto error;
+ }
+ }
+ else
+ PQclear(res);
+ }
- successResult = SendQuery(options.action_string)
- ? EXIT_SUCCESS : EXIT_FAILURE;
+error:
+ ;
}
/*
@@ -419,14 +470,14 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
SetVariable(pset.vars, "ECHO", "errors");
break;
case 'c':
- options->action_string = pg_strdup(optarg);
if (optarg[0] == '\\')
- {
- options->action = ACT_SINGLE_SLASH;
- options->action_string++;
- }
+ simple_action_list_append(&options->actions,
+ ACT_SINGLE_SLASH,
+ pstrdup(optarg + 1));
else
- options->action = ACT_SINGLE_QUERY;
+ simple_action_list_append(&options->actions,
+ ACT_SINGLE_QUERY,
+ pstrdup(optarg));
break;
case 'd':
options->dbname = pg_strdup(optarg);
@@ -438,8 +489,9 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
SetVariableBool(pset.vars, "ECHO_HIDDEN");
break;
case 'f':
- options->action = ACT_FILE;
- options->action_string = pg_strdup(optarg);
+ simple_action_list_append(&options->actions,
+ ACT_FILE,
+ pg_strdup(optarg));
break;
case 'F':
pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
@@ -452,7 +504,7 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
pset.popt.topt.format = PRINT_HTML;
break;
case 'l':
- options->action = ACT_LIST_DB;
+ options->list_dbs = true;
break;
case 'L':
options->logfilename = pg_strdup(optarg);
@@ -674,11 +726,11 @@ process_psqlrc_file(char *filename)
/* check for minor version first, then major, then no version */
if (access(psqlrc_minor, R_OK) == 0)
- (void) process_file(psqlrc_minor, false, false);
+ (void) process_file(psqlrc_minor, false);
else if (access(psqlrc_major, R_OK) == 0)
- (void) process_file(psqlrc_major, false, false);
+ (void) process_file(psqlrc_major, false);
else if (access(filename, R_OK) == 0)
- (void) process_file(filename, false, false);
+ (void) process_file(filename, false);
free(psqlrc_minor);
free(psqlrc_major);
@@ -892,6 +944,29 @@ show_context_hook(const char *newval)
}
+/*
+ * Support for list of actions. SimpleStringList cannot be used due possible
+ * combination different actions with the requirement to save the order.
+ */
+static void
+simple_action_list_append(SimpleActionList *list, int action, const char *val)
+{
+ SimpleActionListCell *cell;
+
+ cell = (SimpleActionListCell *)
+ pg_malloc(offsetof(SimpleActionListCell, val) + strlen(val) + 1);
+
+ cell->next = NULL;
+ cell->action = action;
+ strcpy(cell->val, val);
+
+ if (list->tail)
+ list->tail->next = cell;
+ else
+ list->head = cell;
+ list->tail = cell;
+}
+
static void
EstablishVariableSpace(void)
{
On Tue, Dec 1, 2015 at 1:53 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:
Attached is a patch implementing those suggestions. This simplifies
the code without changing its usefulness. If you are fine with those
changes I will switch this patch as ready for committer.
I tested the v07 patch (so not Michael's version) a few days ago but
didn't send this email earlier.
I combined various -c and -f with --echo-all, --single-transaction,
\set ON_ERROR_STOP=1, separate -c "VACUUM", "SELECT + VACUUM" in a
single and in two -c, inserting -f - somewhere in the middle of the
other -c and -f. They all behave as I would expect.
One maybe slightly surprising behaviour is that -f - can be specified
multiple times and only the first one has an effect since the others
act on an exhausted stdin. But I don't think forbidding multiple -f -
is better.
As for the code (these still apply to Michael's latest patch):
1. the be compiler quiete comment is not good English, /* silence the
compiler */ would be better or remove it completely
2. shouldn't atyp in SimpleActionListCell be of type enum _atypes?
Otherwise why an enum if it's casted to int when actually used? If
it's an enum the repeated ifs on cell->atyp should be a switch, either
with a default Assert(0) or no default which makes gcc give a warning
if an enum value is ever added without having a corresponding case.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2015-12-01 13:53 GMT+01:00 Michael Paquier <michael.paquier@gmail.com>:
On Tue, Dec 1, 2015 at 11:46 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:2015-11-30 15:17 GMT+01:00 Michael Paquier <michael.paquier@gmail.com>:
Removing some items from the list of potential actions and creating a
new sublist listing action types is a bit weird. Why not grouping them
together and allow for example -l as well in the list of things that
is considered as a repeatable action? It seems to me that we could
simplify the code this way, and instead of ACT_NOTHING we could check
if the list of actions is empty or not.fixed
Thanks for the patch. I have to admit that adding ACT_LIST_DB in the
list of actions was not actually a good idea. It makes the patch
uglier.Except that, I just had an in-depth look at this patch, and there are
a couple of things that looked strange:
- ACT_LIST_DB would live better if removed from the list of actions
and be used as a separate, independent option. My previous suggestion
was unadapted. Sorry.
- There is not much meaning to have simple_action_list_append and all
its structures in common.c and common.h. Its use is limited in
startup.c (this code is basically a duplicate of dumputils.c still
things are rather different, justifying the duplication) and
centralized around parse_psql_options.
- use_stdin is not necessary. It is sufficient to rely on actions.head
== NULL instead.
- The documentation is pretty clear. That's nice.
Attached is a patch implementing those suggestions. This simplifies
the code without changing its usefulness. If you are fine with those
changes I will switch this patch as ready for committer.
Regards,
yes, it is looking well
Thank you
Pavel
Show quoted text
--
Michael
2015-12-01 17:52 GMT+01:00 Catalin Iacob <iacobcatalin@gmail.com>:
On Tue, Dec 1, 2015 at 1:53 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:Attached is a patch implementing those suggestions. This simplifies
the code without changing its usefulness. If you are fine with those
changes I will switch this patch as ready for committer.I tested the v07 patch (so not Michael's version) a few days ago but
didn't send this email earlier.I combined various -c and -f with --echo-all, --single-transaction,
\set ON_ERROR_STOP=1, separate -c "VACUUM", "SELECT + VACUUM" in a
single and in two -c, inserting -f - somewhere in the middle of the
other -c and -f. They all behave as I would expect.One maybe slightly surprising behaviour is that -f - can be specified
multiple times and only the first one has an effect since the others
act on an exhausted stdin. But I don't think forbidding multiple -f -
is better.As for the code (these still apply to Michael's latest patch):
1. the be compiler quiete comment is not good English, /* silence the
compiler */ would be better or remove it completely2. shouldn't atyp in SimpleActionListCell be of type enum _atypes?
Otherwise why an enum if it's casted to int when actually used? If
it's an enum the repeated ifs on cell->atyp should be a switch, either
with a default Assert(0) or no default which makes gcc give a warning
if an enum value is ever added without having a corresponding case.
It is maybe different topic - the psql uses enums and ints very freely. So
I wrote code consistent with current code.
The code there uses some older patterns and the cleaning should be bigger
patch.
I have not strong option about this.
Regards
Pavel
On Wed, Dec 2, 2015 at 2:56 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
2015-12-01 17:52 GMT+01:00 Catalin Iacob <iacobcatalin@gmail.com>:
One maybe slightly surprising behaviour is that -f - can be specified
multiple times and only the first one has an effect since the others
act on an exhausted stdin. But I don't think forbidding multiple -f -
is better.
I don't see any good reason to forbid it actually. This simplifies the
code and it's not like this would break psql.
As for the code (these still apply to Michael's latest patch):
1. the be compiler quiete comment is not good English, /* silence the
compiler */ would be better or remove it completely
Fixed. Indeed I didn't notice that.
2. shouldn't atyp in SimpleActionListCell be of type enum _atypes?
Otherwise why an enum if it's casted to int when actually used? If
it's an enum the repeated ifs on cell->atyp should be a switch, either
with a default Assert(0) or no default which makes gcc give a warning
if an enum value is ever added without having a corresponding case.It is maybe different topic - the psql uses enums and ints very freely. So I
wrote code consistent with current code.
Yeah, I don't think that's a big issue either to be honest. The code
is kept consistent a maximum with what is there previously.
Patch is switched to ready for committer.
--
Michael
Attachments:
20151202_psql_commands_v2.patchapplication/x-patch; name=20151202_psql_commands_v2.patchDownload
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 5899bb4..2928c92 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -38,9 +38,10 @@ PostgreSQL documentation
<productname>PostgreSQL</productname>. It enables you to type in
queries interactively, issue them to
<productname>PostgreSQL</productname>, and see the query results.
- Alternatively, input can be from a file. In addition, it provides a
- number of meta-commands and various shell-like features to
- facilitate writing scripts and automating a wide variety of tasks.
+ Alternatively, input can be from a file or from command line
+ arguments. In addition, it provides a number of meta-commands and various
+ shell-like features to facilitate writing scripts and automating a wide
+ variety of tasks.
</para>
</refsect1>
@@ -89,38 +90,45 @@ PostgreSQL documentation
<term><option>--command=<replaceable class="parameter">command</replaceable></></term>
<listitem>
<para>
- Specifies that <application>psql</application> is to execute one
- command string, <replaceable class="parameter">command</replaceable>,
- and then exit. This is useful in shell scripts. Start-up files
- (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are
- ignored with this option.
+ Specifies that <application>psql</application> is to execute the given
+ command string, <replaceable class="parameter">command</replaceable>.
+ This option can be repeated and combined in any order with
+ the <option>-f</option> option.
</para>
<para>
- <replaceable class="parameter">command</replaceable> must be either
- a command string that is completely parsable by the server (i.e.,
- it contains no <application>psql</application>-specific features),
- or a single backslash command. Thus you cannot mix
- <acronym>SQL</acronym> and <application>psql</application>
- meta-commands with this option. To achieve that, you could
- pipe the string into <application>psql</application>, for example:
- <literal>echo '\x \\ SELECT * FROM foo;' | psql</literal>.
+ <replaceable class="parameter">command</replaceable> must be either a
+ command string that is completely parsable by the server (i.e., it
+ contains no <application>psql</application>-specific features), or a
+ single backslash command. Thus you cannot mix
+ <acronym>SQL</acronym> and <application>psql</application> meta-commands
+ with this option. To achieve that, you could use
+ repeated <option>-c</option> options or pipe the string
+ into <application>psql</application>, for example:
+ <literal>psql -c '\x' -c 'SELECT * FROM foo;'</literal> or
+ <literal>echo '\x \\ SELECT * FROM foo;' | psql</literal>
(<literal>\\</> is the separator meta-command.)
</para>
<para>
- If the command string contains multiple SQL commands, they are
- processed in a single transaction, unless there are explicit
- <command>BEGIN</>/<command>COMMIT</> commands included in the
- string to divide it into multiple transactions. This is
- different from the behavior when the same string is fed to
- <application>psql</application>'s standard input. Also, only
- the result of the last SQL command is returned.
+ Each command string passed to <option>-c</option> is sent to the server
+ as a single query. Because of this, the server executes it as a single
+ transaction, even if a command string contains
+ multiple <acronym>SQL</acronym> commands, unless there are
+ explicit <command>BEGIN</>/<command>COMMIT</> commands included in the
+ string to divide it into multiple transactions. Also, the server only
+ returns the result of the last <acronym>SQL</acronym> command to the
+ client. This is different from the behavior when the same string with
+ multiple <acronym>SQL</acronym> commands is fed
+ to <application>psql</application>'s standard input because
+ then <application>psql</application> sends each <acronym>SQL</acronym>
+ command separately.
</para>
<para>
- Because of these legacy behaviors, putting more than one command in
- the <option>-c</option> string often has unexpected results. It's
- better to feed multiple commands to <application>psql</application>'s
- standard input, either using <application>echo</application> as
- illustrated above, or via a shell here-document, for example:
+ Because of the execution as a single query, putting more than one
+ command in the <option>-c</option> string often has unexpected results.
+ It's better to use repeated <option>-c</option> commands or feed
+ multiple commands to <application>psql</application>'s standard input,
+ either using <application>echo</application> as illustrated above, or
+ via a shell here-document, for example:
<programlisting>
psql <<EOF
\x
@@ -183,11 +191,13 @@ EOF
<term><option>--file=<replaceable class="parameter">filename</replaceable></></term>
<listitem>
<para>
- Use the file <replaceable class="parameter">filename</replaceable>
- as the source of commands instead of reading commands interactively.
- After the file is processed, <application>psql</application>
- terminates. This is in many ways equivalent to the meta-command
- <command>\i</command>.
+ Use the file <replaceable class="parameter">filename</replaceable> as
+ the source of commands instead of reading commands interactively. This
+ option can be repeated and combined in any order with
+ the <option>-c</option> option. After the commands in
+ every <option>-c</option> command string and <option>-f</option> file
+ are processed, <application>psql</application> terminates. This option
+ is in many ways equivalent to the meta-command <command>\i</command>.
</para>
<para>
@@ -539,20 +549,21 @@ EOF
<term><option>--single-transaction</option></term>
<listitem>
<para>
- When <application>psql</application> executes a script, adding
- this option wraps <command>BEGIN</>/<command>COMMIT</> around the
- script to execute it as a single transaction. This ensures that
- either all the commands complete successfully, or no changes are
- applied.
+ When <application>psql</application> executes commands from a script
+ and/or a <option>-c</option> option, adding this option
+ wraps <command>BEGIN</>/<command>COMMIT</> around all of those
+ commands as a whole to execute them as a single transaction. This
+ ensures that either all the commands complete successfully, or no
+ changes are applied.
</para>
<para>
- If the script itself uses <command>BEGIN</>, <command>COMMIT</>,
+ If the commands themselves
+ contain <command>BEGIN</>, <command>COMMIT</>,
or <command>ROLLBACK</>, this option will not have the desired
- effects.
- Also, if the script contains any command that cannot be executed
- inside a transaction block, specifying this option will cause that
- command (and hence the whole transaction) to fail.
+ effects. Also, if an individual command cannot be executed inside a
+ transaction block, specifying this option will cause the whole
+ transaction to fail.
</para>
</listitem>
</varlistentry>
@@ -3725,7 +3736,7 @@ PSQL_EDITOR_LINENUMBER_ARG='--line '
<term><filename>psqlrc</filename> and <filename>~/.psqlrc</filename></term>
<listitem>
<para>
- Unless it is passed an <option>-X</option> or <option>-c</option> option,
+ Unless it is passed an <option>-X</option> option,
<application>psql</application> attempts to read and execute commands
from the system-wide startup file (<filename>psqlrc</filename>) and then
the user's personal startup file (<filename>~/.psqlrc</filename>), after
@@ -3819,6 +3830,13 @@ PSQL_EDITOR_LINENUMBER_ARG='--line '
</para>
</listitem>
+ <listitem>
+ <para>
+ Before <productname>PostgreSQL</productname> 9.6, <option>-c</option>
+ used to imply <option>-X</option> and therefore it wouldn't
+ read <filename>psqlrc</filename> files, that is no longer the case.
+ </para>
+ </listitem>
</itemizedlist>
</refsect1>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 72c00c1..5e3b4ed 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -918,7 +918,7 @@ exec_command(const char *cmd,
include_relative = (strcmp(cmd, "ir") == 0
|| strcmp(cmd, "include_relative") == 0);
expand_tilde(&fname);
- success = (process_file(fname, false, include_relative) == EXIT_SUCCESS);
+ success = (process_file(fname, include_relative) == EXIT_SUCCESS);
free(fname);
}
}
@@ -2287,13 +2287,12 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
* the file from where the currently processed file (if any) is located.
*/
int
-process_file(char *filename, bool single_txn, bool use_relative_path)
+process_file(char *filename, bool use_relative_path)
{
FILE *fd;
int result;
char *oldfilename;
char relpath[MAXPGPATH];
- PGresult *res;
if (!filename)
{
@@ -2338,37 +2337,8 @@ process_file(char *filename, bool single_txn, bool use_relative_path)
oldfilename = pset.inputfile;
pset.inputfile = filename;
- if (single_txn)
- {
- if ((res = PSQLexec("BEGIN")) == NULL)
- {
- if (pset.on_error_stop)
- {
- result = EXIT_USER;
- goto error;
- }
- }
- else
- PQclear(res);
- }
-
result = MainLoop(fd);
- if (single_txn)
- {
- if ((res = PSQLexec("COMMIT")) == NULL)
- {
- if (pset.on_error_stop)
- {
- result = EXIT_USER;
- goto error;
- }
- }
- else
- PQclear(res);
- }
-
-error:
if (fd != stdin)
fclose(fd);
diff --git a/src/bin/psql/command.h b/src/bin/psql/command.h
index 54385e8..c817600 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, bool use_relative_path);
+extern int process_file(char *filename, bool use_relative_path);
extern bool do_pset(const char *param,
const char *value,
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 7aa997d..c3585c0 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -50,13 +50,24 @@ PsqlSettings pset;
*/
enum _actions
{
- ACT_NOTHING = 0,
- ACT_SINGLE_SLASH,
- ACT_LIST_DB,
ACT_SINGLE_QUERY,
+ ACT_SINGLE_SLASH,
ACT_FILE
};
+typedef struct SimpleActionListCell
+{
+ struct SimpleActionListCell *next;
+ int action;
+ char val[FLEXIBLE_ARRAY_MEMBER];
+} SimpleActionListCell;
+
+typedef struct SimpleActionList
+{
+ SimpleActionListCell *head;
+ SimpleActionListCell *tail;
+} SimpleActionList;
+
struct adhoc_opts
{
char *dbname;
@@ -64,11 +75,11 @@ struct adhoc_opts
char *port;
char *username;
char *logfilename;
- enum _actions action;
- char *action_string;
bool no_readline;
bool no_psqlrc;
bool single_txn;
+ bool list_dbs;
+ SimpleActionList actions;
};
static void parse_psql_options(int argc, char *argv[],
@@ -76,6 +87,8 @@ static void parse_psql_options(int argc, char *argv[],
static void process_psqlrc(char *argv0);
static void process_psqlrc_file(char *filename);
static void showVersion(void);
+static void simple_action_list_append(SimpleActionList *list,
+ int action, const char *val);
static void EstablishVariableSpace(void);
#define NOPAGER 0
@@ -159,6 +172,9 @@ main(int argc, char *argv[])
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
+ options.actions.head = NULL;
+ options.actions.tail = NULL;
+
parse_psql_options(argc, argv, &options);
/*
@@ -166,14 +182,11 @@ main(int argc, char *argv[])
* as if the user had specified "-f -". This lets single-transaction mode
* work in this case.
*/
- if (options.action == ACT_NOTHING && pset.notty)
- {
- options.action = ACT_FILE;
- options.action_string = NULL;
- }
+ if (options.actions.head == NULL && pset.notty)
+ simple_action_list_append(&options.actions, ACT_FILE, "-");
/* Bail out if -1 was specified but will be ignored. */
- if (options.single_txn && options.action != ACT_FILE && options.action == ACT_NOTHING)
+ if (options.single_txn && options.actions.head == NULL)
{
fprintf(stderr, _("%s: -1 can only be used in non-interactive mode\n"), pset.progname);
exit(EXIT_FAILURE);
@@ -217,8 +230,7 @@ main(int argc, char *argv[])
keywords[3] = "password";
values[3] = password;
keywords[4] = "dbname";
- values[4] = (options.action == ACT_LIST_DB &&
- options.dbname == NULL) ?
+ values[4] = (options.list_dbs && options.dbname == NULL) ?
"postgres" : options.dbname;
keywords[5] = "fallback_application_name";
values[5] = pset.progname;
@@ -259,7 +271,7 @@ main(int argc, char *argv[])
SyncVariables();
- if (options.action == ACT_LIST_DB)
+ if (options.list_dbs)
{
int success;
@@ -280,51 +292,90 @@ main(int argc, char *argv[])
}
/*
- * Now find something to do
- */
-
- /*
- * process file given by -f
+ * Now find something to do, process any actions given by caller,
+ * respecting their order of reception.
*/
- if (options.action == ACT_FILE)
+ if (options.actions.head != NULL)
{
- if (!options.no_psqlrc)
- process_psqlrc(argv[0]);
-
- successResult = process_file(options.action_string, options.single_txn, false);
- }
-
- /*
- * process slash command if one was given to -c
- */
- else if (options.action == ACT_SINGLE_SLASH)
- {
- PsqlScanState scan_state;
+ PGresult *res;
+ SimpleActionListCell *cell;
- if (pset.echo == PSQL_ECHO_ALL)
- puts(options.action_string);
+ successResult = EXIT_SUCCESS; /* silence compiler */
- scan_state = psql_scan_create();
- psql_scan_setup(scan_state,
- options.action_string,
- strlen(options.action_string));
+ if (!options.no_psqlrc)
+ process_psqlrc(argv[0]);
- successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
- ? EXIT_SUCCESS : EXIT_FAILURE;
+ if (options.single_txn)
+ {
+ if ((res = PSQLexec("BEGIN")) == NULL)
+ {
+ if (pset.on_error_stop)
+ {
+ successResult = EXIT_USER;
+ goto error;
+ }
+ }
+ else
+ PQclear(res);
+ }
- psql_scan_destroy(scan_state);
- }
+ for (cell = options.actions.head; cell; cell = cell->next)
+ {
+ if (cell->action == ACT_SINGLE_QUERY)
+ {
+ if (pset.echo == PSQL_ECHO_ALL)
+ puts(cell->val);
+
+ successResult = SendQuery(cell->val)
+ ? EXIT_SUCCESS : EXIT_FAILURE;
+ }
+ else if (cell->action == ACT_SINGLE_SLASH)
+ {
+ PsqlScanState scan_state;
+
+ if (pset.echo == PSQL_ECHO_ALL)
+ puts(cell->val);
+
+ scan_state = psql_scan_create();
+ psql_scan_setup(scan_state,
+ cell->val,
+ strlen(cell->val));
+
+ successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
+ ? EXIT_SUCCESS : EXIT_FAILURE;
+
+ psql_scan_destroy(scan_state);
+ }
+ else if (cell->action == ACT_FILE)
+ {
+ successResult = process_file(cell->val, false);
+ }
+ else
+ {
+ /* should never come here */
+ Assert(0);
+ }
+
+ if (successResult != EXIT_SUCCESS && pset.on_error_stop)
+ break;
+ }
- /*
- * If the query given to -c was a normal one, send it
- */
- else if (options.action == ACT_SINGLE_QUERY)
- {
- if (pset.echo == PSQL_ECHO_ALL)
- puts(options.action_string);
+ if (options.single_txn)
+ {
+ if ((res = PSQLexec("COMMIT")) == NULL)
+ {
+ if (pset.on_error_stop)
+ {
+ successResult = EXIT_USER;
+ goto error;
+ }
+ }
+ else
+ PQclear(res);
+ }
- successResult = SendQuery(options.action_string)
- ? EXIT_SUCCESS : EXIT_FAILURE;
+error:
+ ;
}
/*
@@ -419,14 +470,14 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
SetVariable(pset.vars, "ECHO", "errors");
break;
case 'c':
- options->action_string = pg_strdup(optarg);
if (optarg[0] == '\\')
- {
- options->action = ACT_SINGLE_SLASH;
- options->action_string++;
- }
+ simple_action_list_append(&options->actions,
+ ACT_SINGLE_SLASH,
+ pstrdup(optarg + 1));
else
- options->action = ACT_SINGLE_QUERY;
+ simple_action_list_append(&options->actions,
+ ACT_SINGLE_QUERY,
+ pstrdup(optarg));
break;
case 'd':
options->dbname = pg_strdup(optarg);
@@ -438,8 +489,9 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
SetVariableBool(pset.vars, "ECHO_HIDDEN");
break;
case 'f':
- options->action = ACT_FILE;
- options->action_string = pg_strdup(optarg);
+ simple_action_list_append(&options->actions,
+ ACT_FILE,
+ pg_strdup(optarg));
break;
case 'F':
pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
@@ -452,7 +504,7 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
pset.popt.topt.format = PRINT_HTML;
break;
case 'l':
- options->action = ACT_LIST_DB;
+ options->list_dbs = true;
break;
case 'L':
options->logfilename = pg_strdup(optarg);
@@ -674,11 +726,11 @@ process_psqlrc_file(char *filename)
/* check for minor version first, then major, then no version */
if (access(psqlrc_minor, R_OK) == 0)
- (void) process_file(psqlrc_minor, false, false);
+ (void) process_file(psqlrc_minor, false);
else if (access(psqlrc_major, R_OK) == 0)
- (void) process_file(psqlrc_major, false, false);
+ (void) process_file(psqlrc_major, false);
else if (access(filename, R_OK) == 0)
- (void) process_file(filename, false, false);
+ (void) process_file(filename, false);
free(psqlrc_minor);
free(psqlrc_major);
@@ -892,6 +944,29 @@ show_context_hook(const char *newval)
}
+/*
+ * Support for list of actions. SimpleStringList cannot be used due possible
+ * combination different actions with the requirement to save the order.
+ */
+static void
+simple_action_list_append(SimpleActionList *list, int action, const char *val)
+{
+ SimpleActionListCell *cell;
+
+ cell = (SimpleActionListCell *)
+ pg_malloc(offsetof(SimpleActionListCell, val) + strlen(val) + 1);
+
+ cell->next = NULL;
+ cell->action = action;
+ strcpy(cell->val, val);
+
+ if (list->tail)
+ list->tail->next = cell;
+ else
+ list->head = cell;
+ list->tail = cell;
+}
+
static void
EstablishVariableSpace(void)
{
Hi
Yeah, I don't think that's a big issue either to be honest. The code
is kept consistent a maximum with what is there previously.Patch is switched to ready for committer.
perfect
Thank you very much to all
Regards
Pavel
Show quoted text
--
Michael
On Wed, Dec 2, 2015 at 12:33 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
Yeah, I don't think that's a big issue either to be honest. The code
is kept consistent a maximum with what is there previously.Patch is switched to ready for committer.
perfect
Thank you very much to all
I did some edits on this patch and was all set to commit it when I ran
the regression tests and discovered that this breaks 130 out of the
160 regression tests. Allow me to suggest that before submitting a
patch, or marking it ready for commiter, you test that 'make check'
passes.
The problem seems to be the result of this code:
+ if (options.actions.head == NULL && pset.notty)
+ simple_action_list_append(&options.actions, ACT_FILE, "-");
The problem with this is that process_file() gets called with "-"
where it previously got called with NULL, which changes the way error
reports are printed. This would be trivial to fix were it not for the
fact that SimpleActionListCell uses char val[FLEXIBLE_ARRAY_MEMBER]
rather than char *val. I think you should change it so that it does
the latter, and then change the above line to pass NULL for the third
argument. I think that will fix it, but it's more work than I want to
do on somebody else's patch, so I'm attaching my edited version here
for further work.
For the most part, the cleanups in this version are just cosmetic: I
fixed some whitespace damage, and reverted some needless changes to
the psql references page that were whitespace-only adjustments. In a
few places, I tweaked documentation or comment language. I also
hoisted the psqlrc handling out of an if statement where it was the
same in both branches. Other than that, this version is, I believe,
the same as Pavel's last version.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Attachments:
psql-commands-rmh.patchapplication/x-patch; name=psql-commands-rmh.patchDownload
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index e4f72a8..47e9da2 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -38,9 +38,10 @@ PostgreSQL documentation
<productname>PostgreSQL</productname>. It enables you to type in
queries interactively, issue them to
<productname>PostgreSQL</productname>, and see the query results.
- Alternatively, input can be from a file. In addition, it provides a
- number of meta-commands and various shell-like features to
- facilitate writing scripts and automating a wide variety of tasks.
+ Alternatively, input can be from a file or from command line
+ arguments. In addition, it provides a number of meta-commands and various
+ shell-like features to facilitate writing scripts and automating a wide
+ variety of tasks.
</para>
</refsect1>
@@ -89,11 +90,10 @@ PostgreSQL documentation
<term><option>--command=<replaceable class="parameter">command</replaceable></></term>
<listitem>
<para>
- Specifies that <application>psql</application> is to execute one
- command string, <replaceable class="parameter">command</replaceable>,
- and then exit. This is useful in shell scripts. Start-up files
- (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are
- ignored with this option.
+ Specifies that <application>psql</application> is to execute the given
+ command string, <replaceable class="parameter">command</replaceable>.
+ This option can be repeated and combined in any order with
+ the <option>-f</option> option.
</para>
<para>
<replaceable class="parameter">command</replaceable> must be either
@@ -102,25 +102,34 @@ PostgreSQL documentation
or a single backslash command. Thus you cannot mix
<acronym>SQL</acronym> and <application>psql</application>
meta-commands with this option. To achieve that, you could
- pipe the string into <application>psql</application>, for example:
+ use repeated <option>-c</option> options or pipe the string
+ into <application>psql</application>, for example:
+ <literal>psql -c '\x' -c 'SELECT * FROM foo;'</literal> or
<literal>echo '\x \\ SELECT * FROM foo;' | psql</literal>.
(<literal>\\</> is the separator meta-command.)
</para>
<para>
- If the command string contains multiple SQL commands, they are
- processed in a single transaction, unless there are explicit
- <command>BEGIN</>/<command>COMMIT</> commands included in the
- string to divide it into multiple transactions. This is
- different from the behavior when the same string is fed to
- <application>psql</application>'s standard input. Also, only
- the result of the last SQL command is returned.
+ Each command string passed to <option>-c</option> is sent to the server
+ as a single query. Because of this, the server executes it as a single
+ transaction, even if a command string contains
+ multiple <acronym>SQL</acronym> commands, unless there are
+ explicit <command>BEGIN</>/<command>COMMIT</> commands included in the
+ string to divide it into multiple transactions. Also, the server only
+ returns the result of the last <acronym>SQL</acronym> command to the
+ client. This is different from the behavior when the same string with
+ multiple <acronym>SQL</acronym> commands is fed
+ to <application>psql</application>'s standard input because
+ then <application>psql</application> sends each <acronym>SQL</acronym>
+ command separately.
</para>
<para>
- Because of these legacy behaviors, putting more than one command in
- the <option>-c</option> string often has unexpected results. It's
- better to feed multiple commands to <application>psql</application>'s
- standard input, either using <application>echo</application> as
- illustrated above, or via a shell here-document, for example:
+ Putting more than one command in the <option>-c</option> string often
+ has unexpected results. This is a result of the fact that the whole
+ string is sent to the server as a single query.
+ It's better to use repeated <option>-c</option> commands or feed
+ multiple commands to <application>psql</application>'s standard input,
+ either using <application>echo</application> as illustrated above, or
+ via a shell here-document, for example:
<programlisting>
psql <<EOF
\x
@@ -185,9 +194,11 @@ EOF
<para>
Use the file <replaceable class="parameter">filename</replaceable>
as the source of commands instead of reading commands interactively.
- After the file is processed, <application>psql</application>
- terminates. This is in many ways equivalent to the meta-command
- <command>\i</command>.
+ This option can be repeated and combined in any order with
+ the <option>-c</option> option. After the commands in
+ every <option>-c</option> command string and <option>-f</option> file
+ are processed, <application>psql</application> terminates. This option
+ is in many ways equivalent to the meta-command <command>\i</command>.
</para>
<para>
@@ -539,20 +550,21 @@ EOF
<term><option>--single-transaction</option></term>
<listitem>
<para>
- When <application>psql</application> executes a script, adding
- this option wraps <command>BEGIN</>/<command>COMMIT</> around the
- script to execute it as a single transaction. This ensures that
- either all the commands complete successfully, or no changes are
- applied.
+ When <application>psql</application> executes commands from a script
+ and/or a <option>-c</option> option, adding this option
+ wraps <command>BEGIN</>/<command>COMMIT</> around all of those
+ commands as a whole to execute them as a single transaction. This
+ ensures that either all the commands complete successfully, or no
+ changes are applied.
</para>
<para>
- If the script itself uses <command>BEGIN</>, <command>COMMIT</>,
+ If the commands themselves
+ contain <command>BEGIN</>, <command>COMMIT</>,
or <command>ROLLBACK</>, this option will not have the desired
- effects.
- Also, if the script contains any command that cannot be executed
- inside a transaction block, specifying this option will cause that
- command (and hence the whole transaction) to fail.
+ effects. Also, if an individual command cannot be executed inside a
+ transaction block, specifying this option will cause the whole
+ transaction to fail.
</para>
</listitem>
</varlistentry>
@@ -3725,7 +3737,7 @@ PSQL_EDITOR_LINENUMBER_ARG='--line '
<term><filename>psqlrc</filename> and <filename>~/.psqlrc</filename></term>
<listitem>
<para>
- Unless it is passed an <option>-X</option> or <option>-c</option> option,
+ Unless it is passed an <option>-X</option> option,
<application>psql</application> attempts to read and execute commands
from the system-wide startup file (<filename>psqlrc</filename>) and then
the user's personal startup file (<filename>~/.psqlrc</filename>), after
@@ -3819,6 +3831,12 @@ PSQL_EDITOR_LINENUMBER_ARG='--line '
</para>
</listitem>
+ <listitem>
+ <para>
+ Before <productname>PostgreSQL</productname> 9.6, <option>-c</option>
+ implied <option>-X</option>; this is no longer the case.
+ </para>
+ </listitem>
</itemizedlist>
</refsect1>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 6e8c623..cf6876b 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -916,7 +916,7 @@ exec_command(const char *cmd,
include_relative = (strcmp(cmd, "ir") == 0
|| strcmp(cmd, "include_relative") == 0);
expand_tilde(&fname);
- success = (process_file(fname, false, include_relative) == EXIT_SUCCESS);
+ success = (process_file(fname, include_relative) == EXIT_SUCCESS);
free(fname);
}
}
@@ -2288,13 +2288,12 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
* the file from where the currently processed file (if any) is located.
*/
int
-process_file(char *filename, bool single_txn, bool use_relative_path)
+process_file(char *filename, bool use_relative_path)
{
FILE *fd;
int result;
char *oldfilename;
char relpath[MAXPGPATH];
- PGresult *res;
if (!filename)
{
@@ -2339,37 +2338,8 @@ process_file(char *filename, bool single_txn, bool use_relative_path)
oldfilename = pset.inputfile;
pset.inputfile = filename;
- if (single_txn)
- {
- if ((res = PSQLexec("BEGIN")) == NULL)
- {
- if (pset.on_error_stop)
- {
- result = EXIT_USER;
- goto error;
- }
- }
- else
- PQclear(res);
- }
-
result = MainLoop(fd);
- if (single_txn)
- {
- if ((res = PSQLexec("COMMIT")) == NULL)
- {
- if (pset.on_error_stop)
- {
- result = EXIT_USER;
- goto error;
- }
- }
- else
- PQclear(res);
- }
-
-error:
if (fd != stdin)
fclose(fd);
diff --git a/src/bin/psql/command.h b/src/bin/psql/command.h
index 54385e8..c817600 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, bool use_relative_path);
+extern int process_file(char *filename, bool use_relative_path);
extern bool do_pset(const char *param,
const char *value,
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 4e5021a..dbfd20f 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -50,13 +50,24 @@ PsqlSettings pset;
*/
enum _actions
{
- ACT_NOTHING = 0,
- ACT_SINGLE_SLASH,
- ACT_LIST_DB,
ACT_SINGLE_QUERY,
+ ACT_SINGLE_SLASH,
ACT_FILE
};
+typedef struct SimpleActionListCell
+{
+ struct SimpleActionListCell *next;
+ int action;
+ char val[FLEXIBLE_ARRAY_MEMBER];
+} SimpleActionListCell;
+
+typedef struct SimpleActionList
+{
+ SimpleActionListCell *head;
+ SimpleActionListCell *tail;
+} SimpleActionList;
+
struct adhoc_opts
{
char *dbname;
@@ -64,11 +75,11 @@ struct adhoc_opts
char *port;
char *username;
char *logfilename;
- enum _actions action;
- char *action_string;
bool no_readline;
bool no_psqlrc;
bool single_txn;
+ bool list_dbs;
+ SimpleActionList actions;
};
static void parse_psql_options(int argc, char *argv[],
@@ -76,6 +87,8 @@ static void parse_psql_options(int argc, char *argv[],
static void process_psqlrc(char *argv0);
static void process_psqlrc_file(char *filename);
static void showVersion(void);
+static void simple_action_list_append(SimpleActionList *list,
+ int action, const char *val);
static void EstablishVariableSpace(void);
#define NOPAGER 0
@@ -159,6 +172,9 @@ main(int argc, char *argv[])
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
+ options.actions.head = NULL;
+ options.actions.tail = NULL;
+
parse_psql_options(argc, argv, &options);
/*
@@ -166,14 +182,11 @@ main(int argc, char *argv[])
* as if the user had specified "-f -". This lets single-transaction mode
* work in this case.
*/
- if (options.action == ACT_NOTHING && pset.notty)
- {
- options.action = ACT_FILE;
- options.action_string = NULL;
- }
+ if (options.actions.head == NULL && pset.notty)
+ simple_action_list_append(&options.actions, ACT_FILE, "-");
/* Bail out if -1 was specified but will be ignored. */
- if (options.single_txn && options.action != ACT_FILE && options.action == ACT_NOTHING)
+ if (options.single_txn && options.actions.head == NULL)
{
fprintf(stderr, _("%s: -1 can only be used in non-interactive mode\n"), pset.progname);
exit(EXIT_FAILURE);
@@ -217,8 +230,7 @@ main(int argc, char *argv[])
keywords[3] = "password";
values[3] = password;
keywords[4] = "dbname";
- values[4] = (options.action == ACT_LIST_DB &&
- options.dbname == NULL) ?
+ values[4] = (options.list_dbs && options.dbname == NULL) ?
"postgres" : options.dbname;
keywords[5] = "fallback_application_name";
values[5] = pset.progname;
@@ -259,7 +271,7 @@ main(int argc, char *argv[])
SyncVariables();
- if (options.action == ACT_LIST_DB)
+ if (options.list_dbs)
{
int success;
@@ -279,52 +291,91 @@ main(int argc, char *argv[])
pset.progname, options.logfilename, strerror(errno));
}
- /*
- * Now find something to do
- */
+ if (!options.no_psqlrc)
+ process_psqlrc(argv[0]);
/*
- * process file given by -f
+ * If any actions were given by caller, process them in the order in
+ * which they were specified.
*/
- if (options.action == ACT_FILE)
+ if (options.actions.head != NULL)
{
- if (!options.no_psqlrc)
- process_psqlrc(argv[0]);
+ PGresult *res;
+ SimpleActionListCell *cell;
- successResult = process_file(options.action_string, options.single_txn, false);
- }
-
- /*
- * process slash command if one was given to -c
- */
- else if (options.action == ACT_SINGLE_SLASH)
- {
- PsqlScanState scan_state;
-
- if (pset.echo == PSQL_ECHO_ALL)
- puts(options.action_string);
+ successResult = EXIT_SUCCESS; /* silence compiler */
- scan_state = psql_scan_create();
- psql_scan_setup(scan_state,
- options.action_string,
- strlen(options.action_string));
-
- successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
- ? EXIT_SUCCESS : EXIT_FAILURE;
+ if (options.single_txn)
+ {
+ if ((res = PSQLexec("BEGIN")) == NULL)
+ {
+ if (pset.on_error_stop)
+ {
+ successResult = EXIT_USER;
+ goto error;
+ }
+ }
+ else
+ PQclear(res);
+ }
- psql_scan_destroy(scan_state);
- }
+ for (cell = options.actions.head; cell; cell = cell->next)
+ {
+ if (cell->action == ACT_SINGLE_QUERY)
+ {
+ if (pset.echo == PSQL_ECHO_ALL)
+ puts(cell->val);
+
+ successResult = SendQuery(cell->val)
+ ? EXIT_SUCCESS : EXIT_FAILURE;
+ }
+ else if (cell->action == ACT_SINGLE_SLASH)
+ {
+ PsqlScanState scan_state;
+
+ if (pset.echo == PSQL_ECHO_ALL)
+ puts(cell->val);
+
+ scan_state = psql_scan_create();
+ psql_scan_setup(scan_state,
+ cell->val,
+ strlen(cell->val));
+
+ successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
+ ? EXIT_SUCCESS : EXIT_FAILURE;
+
+ psql_scan_destroy(scan_state);
+ }
+ else if (cell->action == ACT_FILE)
+ {
+ successResult = process_file(cell->val, false);
+ }
+ else
+ {
+ /* should never come here */
+ Assert(0);
+ }
+
+ if (successResult != EXIT_SUCCESS && pset.on_error_stop)
+ break;
+ }
- /*
- * If the query given to -c was a normal one, send it
- */
- else if (options.action == ACT_SINGLE_QUERY)
- {
- if (pset.echo == PSQL_ECHO_ALL)
- puts(options.action_string);
+ if (options.single_txn)
+ {
+ if ((res = PSQLexec("COMMIT")) == NULL)
+ {
+ if (pset.on_error_stop)
+ {
+ successResult = EXIT_USER;
+ goto error;
+ }
+ }
+ else
+ PQclear(res);
+ }
- successResult = SendQuery(options.action_string)
- ? EXIT_SUCCESS : EXIT_FAILURE;
+error:
+ ;
}
/*
@@ -332,9 +383,6 @@ main(int argc, char *argv[])
*/
else
{
- if (!options.no_psqlrc)
- process_psqlrc(argv[0]);
-
connection_warnings(true);
if (!pset.quiet)
printf(_("Type \"help\" for help.\n\n"));
@@ -419,14 +467,14 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
SetVariable(pset.vars, "ECHO", "errors");
break;
case 'c':
- options->action_string = pg_strdup(optarg);
if (optarg[0] == '\\')
- {
- options->action = ACT_SINGLE_SLASH;
- options->action_string++;
- }
+ simple_action_list_append(&options->actions,
+ ACT_SINGLE_SLASH,
+ pstrdup(optarg + 1));
else
- options->action = ACT_SINGLE_QUERY;
+ simple_action_list_append(&options->actions,
+ ACT_SINGLE_QUERY,
+ pstrdup(optarg));
break;
case 'd':
options->dbname = pg_strdup(optarg);
@@ -438,8 +486,9 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
SetVariableBool(pset.vars, "ECHO_HIDDEN");
break;
case 'f':
- options->action = ACT_FILE;
- options->action_string = pg_strdup(optarg);
+ simple_action_list_append(&options->actions,
+ ACT_FILE,
+ pg_strdup(optarg));
break;
case 'F':
pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
@@ -452,7 +501,7 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
pset.popt.topt.format = PRINT_HTML;
break;
case 'l':
- options->action = ACT_LIST_DB;
+ options->list_dbs = true;
break;
case 'L':
options->logfilename = pg_strdup(optarg);
@@ -675,11 +724,11 @@ process_psqlrc_file(char *filename)
/* check for minor version first, then major, then no version */
if (access(psqlrc_minor, R_OK) == 0)
- (void) process_file(psqlrc_minor, false, false);
+ (void) process_file(psqlrc_minor, false);
else if (access(psqlrc_major, R_OK) == 0)
- (void) process_file(psqlrc_major, false, false);
+ (void) process_file(psqlrc_major, false);
else if (access(filename, R_OK) == 0)
- (void) process_file(filename, false, false);
+ (void) process_file(filename, false);
free(psqlrc_minor);
free(psqlrc_major);
@@ -893,6 +942,29 @@ show_context_hook(const char *newval)
}
+/*
+ * Support for list of actions. SimpleStringList cannot be used due possible
+ * combination different actions with the requirement to save the order.
+ */
+static void
+simple_action_list_append(SimpleActionList *list, int action, const char *val)
+{
+ SimpleActionListCell *cell;
+
+ cell = (SimpleActionListCell *)
+ pg_malloc(offsetof(SimpleActionListCell, val) + strlen(val) + 1);
+
+ cell->next = NULL;
+ cell->action = action;
+ strcpy(cell->val, val);
+
+ if (list->tail)
+ list->tail->next = cell;
+ else
+ list->head = cell;
+ list->tail = cell;
+}
+
static void
EstablishVariableSpace(void)
{
On Fri, Dec 4, 2015 at 3:47 PM, Robert Haas <robertmhaas@gmail.com> wrote:
For the most part, the cleanups in this version are just cosmetic: I
fixed some whitespace damage, and reverted some needless changes to
the psql references page that were whitespace-only adjustments. In a
few places, I tweaked documentation or comment language.
Sorry for the docs whitespace-only changes, I did that.
I realized before the submission I made the diff bigger than it needed
to be, but that's because I used M-q in Emacs to break the lines I did
change and that reformatted the whole paragraph including some
unchanged lines. Breaking all the lines by hand would be quite a job,
and any time you go back and tweak the wording or so you need to do it
again. So I just used M-q and sent the result of that.
Do you happen to know of a better way to do this? I do load
src/tools/editors/emacs.samples in my ~/.emacs but it seems the width
my Emacs chooses doesn't match the one already in the file.
The doc tweaks are good, they make the text more clear. I'm happy
that's all you found to improve: writing good docs is hard and the
Postgres docs are already good so it's not easy to change them, I had
the feeling I'll only make them worse and spent quite some time trying
not to do that.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Dec 4, 2015 at 11:47 PM, Robert Haas <robertmhaas@gmail.com> wrote:
On Wed, Dec 2, 2015 at 12:33 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
Yeah, I don't think that's a big issue either to be honest. The code
is kept consistent a maximum with what is there previously.Patch is switched to ready for committer.
perfect
Thank you very much to all
I did some edits on this patch and was all set to commit it when I ran
the regression tests and discovered that this breaks 130 out of the
160 regression tests. Allow me to suggest that before submitting a
patch, or marking it ready for commiter, you test that 'make check'
passes.
Mea culpa. I thought I did a check-world run... But well...
For the most part, the cleanups in this version are just cosmetic: I
fixed some whitespace damage, and reverted some needless changes to
the psql references page that were whitespace-only adjustments. In a
few places, I tweaked documentation or comment language. I also
hoisted the psqlrc handling out of an if statement where it was the
same in both branches. Other than that, this version is, I believe,
the same as Pavel's last version.
Thanks, I looked at that again and problem is fixed as attached.
--
Michael
Attachments:
20151206_psql_commands_v3.patchbinary/octet-stream; name=20151206_psql_commands_v3.patchDownload
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index e4f72a8..47e9da2 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -38,9 +38,10 @@ PostgreSQL documentation
<productname>PostgreSQL</productname>. It enables you to type in
queries interactively, issue them to
<productname>PostgreSQL</productname>, and see the query results.
- Alternatively, input can be from a file. In addition, it provides a
- number of meta-commands and various shell-like features to
- facilitate writing scripts and automating a wide variety of tasks.
+ Alternatively, input can be from a file or from command line
+ arguments. In addition, it provides a number of meta-commands and various
+ shell-like features to facilitate writing scripts and automating a wide
+ variety of tasks.
</para>
</refsect1>
@@ -89,11 +90,10 @@ PostgreSQL documentation
<term><option>--command=<replaceable class="parameter">command</replaceable></></term>
<listitem>
<para>
- Specifies that <application>psql</application> is to execute one
- command string, <replaceable class="parameter">command</replaceable>,
- and then exit. This is useful in shell scripts. Start-up files
- (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are
- ignored with this option.
+ Specifies that <application>psql</application> is to execute the given
+ command string, <replaceable class="parameter">command</replaceable>.
+ This option can be repeated and combined in any order with
+ the <option>-f</option> option.
</para>
<para>
<replaceable class="parameter">command</replaceable> must be either
@@ -102,25 +102,34 @@ PostgreSQL documentation
or a single backslash command. Thus you cannot mix
<acronym>SQL</acronym> and <application>psql</application>
meta-commands with this option. To achieve that, you could
- pipe the string into <application>psql</application>, for example:
+ use repeated <option>-c</option> options or pipe the string
+ into <application>psql</application>, for example:
+ <literal>psql -c '\x' -c 'SELECT * FROM foo;'</literal> or
<literal>echo '\x \\ SELECT * FROM foo;' | psql</literal>.
(<literal>\\</> is the separator meta-command.)
</para>
<para>
- If the command string contains multiple SQL commands, they are
- processed in a single transaction, unless there are explicit
- <command>BEGIN</>/<command>COMMIT</> commands included in the
- string to divide it into multiple transactions. This is
- different from the behavior when the same string is fed to
- <application>psql</application>'s standard input. Also, only
- the result of the last SQL command is returned.
+ Each command string passed to <option>-c</option> is sent to the server
+ as a single query. Because of this, the server executes it as a single
+ transaction, even if a command string contains
+ multiple <acronym>SQL</acronym> commands, unless there are
+ explicit <command>BEGIN</>/<command>COMMIT</> commands included in the
+ string to divide it into multiple transactions. Also, the server only
+ returns the result of the last <acronym>SQL</acronym> command to the
+ client. This is different from the behavior when the same string with
+ multiple <acronym>SQL</acronym> commands is fed
+ to <application>psql</application>'s standard input because
+ then <application>psql</application> sends each <acronym>SQL</acronym>
+ command separately.
</para>
<para>
- Because of these legacy behaviors, putting more than one command in
- the <option>-c</option> string often has unexpected results. It's
- better to feed multiple commands to <application>psql</application>'s
- standard input, either using <application>echo</application> as
- illustrated above, or via a shell here-document, for example:
+ Putting more than one command in the <option>-c</option> string often
+ has unexpected results. This is a result of the fact that the whole
+ string is sent to the server as a single query.
+ It's better to use repeated <option>-c</option> commands or feed
+ multiple commands to <application>psql</application>'s standard input,
+ either using <application>echo</application> as illustrated above, or
+ via a shell here-document, for example:
<programlisting>
psql <<EOF
\x
@@ -185,9 +194,11 @@ EOF
<para>
Use the file <replaceable class="parameter">filename</replaceable>
as the source of commands instead of reading commands interactively.
- After the file is processed, <application>psql</application>
- terminates. This is in many ways equivalent to the meta-command
- <command>\i</command>.
+ This option can be repeated and combined in any order with
+ the <option>-c</option> option. After the commands in
+ every <option>-c</option> command string and <option>-f</option> file
+ are processed, <application>psql</application> terminates. This option
+ is in many ways equivalent to the meta-command <command>\i</command>.
</para>
<para>
@@ -539,20 +550,21 @@ EOF
<term><option>--single-transaction</option></term>
<listitem>
<para>
- When <application>psql</application> executes a script, adding
- this option wraps <command>BEGIN</>/<command>COMMIT</> around the
- script to execute it as a single transaction. This ensures that
- either all the commands complete successfully, or no changes are
- applied.
+ When <application>psql</application> executes commands from a script
+ and/or a <option>-c</option> option, adding this option
+ wraps <command>BEGIN</>/<command>COMMIT</> around all of those
+ commands as a whole to execute them as a single transaction. This
+ ensures that either all the commands complete successfully, or no
+ changes are applied.
</para>
<para>
- If the script itself uses <command>BEGIN</>, <command>COMMIT</>,
+ If the commands themselves
+ contain <command>BEGIN</>, <command>COMMIT</>,
or <command>ROLLBACK</>, this option will not have the desired
- effects.
- Also, if the script contains any command that cannot be executed
- inside a transaction block, specifying this option will cause that
- command (and hence the whole transaction) to fail.
+ effects. Also, if an individual command cannot be executed inside a
+ transaction block, specifying this option will cause the whole
+ transaction to fail.
</para>
</listitem>
</varlistentry>
@@ -3725,7 +3737,7 @@ PSQL_EDITOR_LINENUMBER_ARG='--line '
<term><filename>psqlrc</filename> and <filename>~/.psqlrc</filename></term>
<listitem>
<para>
- Unless it is passed an <option>-X</option> or <option>-c</option> option,
+ Unless it is passed an <option>-X</option> option,
<application>psql</application> attempts to read and execute commands
from the system-wide startup file (<filename>psqlrc</filename>) and then
the user's personal startup file (<filename>~/.psqlrc</filename>), after
@@ -3819,6 +3831,12 @@ PSQL_EDITOR_LINENUMBER_ARG='--line '
</para>
</listitem>
+ <listitem>
+ <para>
+ Before <productname>PostgreSQL</productname> 9.6, <option>-c</option>
+ implied <option>-X</option>; this is no longer the case.
+ </para>
+ </listitem>
</itemizedlist>
</refsect1>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 6e8c623..cf6876b 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -916,7 +916,7 @@ exec_command(const char *cmd,
include_relative = (strcmp(cmd, "ir") == 0
|| strcmp(cmd, "include_relative") == 0);
expand_tilde(&fname);
- success = (process_file(fname, false, include_relative) == EXIT_SUCCESS);
+ success = (process_file(fname, include_relative) == EXIT_SUCCESS);
free(fname);
}
}
@@ -2288,13 +2288,12 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
* the file from where the currently processed file (if any) is located.
*/
int
-process_file(char *filename, bool single_txn, bool use_relative_path)
+process_file(char *filename, bool use_relative_path)
{
FILE *fd;
int result;
char *oldfilename;
char relpath[MAXPGPATH];
- PGresult *res;
if (!filename)
{
@@ -2339,37 +2338,8 @@ process_file(char *filename, bool single_txn, bool use_relative_path)
oldfilename = pset.inputfile;
pset.inputfile = filename;
- if (single_txn)
- {
- if ((res = PSQLexec("BEGIN")) == NULL)
- {
- if (pset.on_error_stop)
- {
- result = EXIT_USER;
- goto error;
- }
- }
- else
- PQclear(res);
- }
-
result = MainLoop(fd);
- if (single_txn)
- {
- if ((res = PSQLexec("COMMIT")) == NULL)
- {
- if (pset.on_error_stop)
- {
- result = EXIT_USER;
- goto error;
- }
- }
- else
- PQclear(res);
- }
-
-error:
if (fd != stdin)
fclose(fd);
diff --git a/src/bin/psql/command.h b/src/bin/psql/command.h
index 54385e8..c817600 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, bool use_relative_path);
+extern int process_file(char *filename, bool use_relative_path);
extern bool do_pset(const char *param,
const char *value,
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 4e5021a..7af38fb 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -50,13 +50,24 @@ PsqlSettings pset;
*/
enum _actions
{
- ACT_NOTHING = 0,
- ACT_SINGLE_SLASH,
- ACT_LIST_DB,
ACT_SINGLE_QUERY,
+ ACT_SINGLE_SLASH,
ACT_FILE
};
+typedef struct SimpleActionListCell
+{
+ struct SimpleActionListCell *next;
+ int action;
+ char *val;
+} SimpleActionListCell;
+
+typedef struct SimpleActionList
+{
+ SimpleActionListCell *head;
+ SimpleActionListCell *tail;
+} SimpleActionList;
+
struct adhoc_opts
{
char *dbname;
@@ -64,11 +75,11 @@ struct adhoc_opts
char *port;
char *username;
char *logfilename;
- enum _actions action;
- char *action_string;
bool no_readline;
bool no_psqlrc;
bool single_txn;
+ bool list_dbs;
+ SimpleActionList actions;
};
static void parse_psql_options(int argc, char *argv[],
@@ -76,6 +87,8 @@ static void parse_psql_options(int argc, char *argv[],
static void process_psqlrc(char *argv0);
static void process_psqlrc_file(char *filename);
static void showVersion(void);
+static void simple_action_list_append(SimpleActionList *list,
+ int action, const char *val);
static void EstablishVariableSpace(void);
#define NOPAGER 0
@@ -159,6 +172,9 @@ main(int argc, char *argv[])
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
+ options.actions.head = NULL;
+ options.actions.tail = NULL;
+
parse_psql_options(argc, argv, &options);
/*
@@ -166,14 +182,11 @@ main(int argc, char *argv[])
* as if the user had specified "-f -". This lets single-transaction mode
* work in this case.
*/
- if (options.action == ACT_NOTHING && pset.notty)
- {
- options.action = ACT_FILE;
- options.action_string = NULL;
- }
+ if (options.actions.head == NULL && pset.notty)
+ simple_action_list_append(&options.actions, ACT_FILE, NULL);
/* Bail out if -1 was specified but will be ignored. */
- if (options.single_txn && options.action != ACT_FILE && options.action == ACT_NOTHING)
+ if (options.single_txn && options.actions.head == NULL)
{
fprintf(stderr, _("%s: -1 can only be used in non-interactive mode\n"), pset.progname);
exit(EXIT_FAILURE);
@@ -217,8 +230,7 @@ main(int argc, char *argv[])
keywords[3] = "password";
values[3] = password;
keywords[4] = "dbname";
- values[4] = (options.action == ACT_LIST_DB &&
- options.dbname == NULL) ?
+ values[4] = (options.list_dbs && options.dbname == NULL) ?
"postgres" : options.dbname;
keywords[5] = "fallback_application_name";
values[5] = pset.progname;
@@ -259,7 +271,7 @@ main(int argc, char *argv[])
SyncVariables();
- if (options.action == ACT_LIST_DB)
+ if (options.list_dbs)
{
int success;
@@ -279,52 +291,91 @@ main(int argc, char *argv[])
pset.progname, options.logfilename, strerror(errno));
}
- /*
- * Now find something to do
- */
+ if (!options.no_psqlrc)
+ process_psqlrc(argv[0]);
/*
- * process file given by -f
+ * If any actions were given by caller, process them in the order in
+ * which they were specified.
*/
- if (options.action == ACT_FILE)
+ if (options.actions.head != NULL)
{
- if (!options.no_psqlrc)
- process_psqlrc(argv[0]);
+ PGresult *res;
+ SimpleActionListCell *cell;
- successResult = process_file(options.action_string, options.single_txn, false);
- }
+ successResult = EXIT_SUCCESS; /* silence compiler */
- /*
- * process slash command if one was given to -c
- */
- else if (options.action == ACT_SINGLE_SLASH)
- {
- PsqlScanState scan_state;
-
- if (pset.echo == PSQL_ECHO_ALL)
- puts(options.action_string);
-
- scan_state = psql_scan_create();
- psql_scan_setup(scan_state,
- options.action_string,
- strlen(options.action_string));
-
- successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
- ? EXIT_SUCCESS : EXIT_FAILURE;
+ if (options.single_txn)
+ {
+ if ((res = PSQLexec("BEGIN")) == NULL)
+ {
+ if (pset.on_error_stop)
+ {
+ successResult = EXIT_USER;
+ goto error;
+ }
+ }
+ else
+ PQclear(res);
+ }
- psql_scan_destroy(scan_state);
- }
+ for (cell = options.actions.head; cell; cell = cell->next)
+ {
+ if (cell->action == ACT_SINGLE_QUERY)
+ {
+ if (pset.echo == PSQL_ECHO_ALL)
+ puts(cell->val);
+
+ successResult = SendQuery(cell->val)
+ ? EXIT_SUCCESS : EXIT_FAILURE;
+ }
+ else if (cell->action == ACT_SINGLE_SLASH)
+ {
+ PsqlScanState scan_state;
+
+ if (pset.echo == PSQL_ECHO_ALL)
+ puts(cell->val);
+
+ scan_state = psql_scan_create();
+ psql_scan_setup(scan_state,
+ cell->val,
+ strlen(cell->val));
+
+ successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
+ ? EXIT_SUCCESS : EXIT_FAILURE;
+
+ psql_scan_destroy(scan_state);
+ }
+ else if (cell->action == ACT_FILE)
+ {
+ successResult = process_file(cell->val, false);
+ }
+ else
+ {
+ /* should never come here */
+ Assert(0);
+ }
+
+ if (successResult != EXIT_SUCCESS && pset.on_error_stop)
+ break;
+ }
- /*
- * If the query given to -c was a normal one, send it
- */
- else if (options.action == ACT_SINGLE_QUERY)
- {
- if (pset.echo == PSQL_ECHO_ALL)
- puts(options.action_string);
+ if (options.single_txn)
+ {
+ if ((res = PSQLexec("COMMIT")) == NULL)
+ {
+ if (pset.on_error_stop)
+ {
+ successResult = EXIT_USER;
+ goto error;
+ }
+ }
+ else
+ PQclear(res);
+ }
- successResult = SendQuery(options.action_string)
- ? EXIT_SUCCESS : EXIT_FAILURE;
+error:
+ ;
}
/*
@@ -332,9 +383,6 @@ main(int argc, char *argv[])
*/
else
{
- if (!options.no_psqlrc)
- process_psqlrc(argv[0]);
-
connection_warnings(true);
if (!pset.quiet)
printf(_("Type \"help\" for help.\n\n"));
@@ -419,14 +467,14 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
SetVariable(pset.vars, "ECHO", "errors");
break;
case 'c':
- options->action_string = pg_strdup(optarg);
if (optarg[0] == '\\')
- {
- options->action = ACT_SINGLE_SLASH;
- options->action_string++;
- }
+ simple_action_list_append(&options->actions,
+ ACT_SINGLE_SLASH,
+ pstrdup(optarg + 1));
else
- options->action = ACT_SINGLE_QUERY;
+ simple_action_list_append(&options->actions,
+ ACT_SINGLE_QUERY,
+ pstrdup(optarg));
break;
case 'd':
options->dbname = pg_strdup(optarg);
@@ -438,8 +486,9 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
SetVariableBool(pset.vars, "ECHO_HIDDEN");
break;
case 'f':
- options->action = ACT_FILE;
- options->action_string = pg_strdup(optarg);
+ simple_action_list_append(&options->actions,
+ ACT_FILE,
+ pg_strdup(optarg));
break;
case 'F':
pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
@@ -452,7 +501,7 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
pset.popt.topt.format = PRINT_HTML;
break;
case 'l':
- options->action = ACT_LIST_DB;
+ options->list_dbs = true;
break;
case 'L':
options->logfilename = pg_strdup(optarg);
@@ -675,11 +724,11 @@ process_psqlrc_file(char *filename)
/* check for minor version first, then major, then no version */
if (access(psqlrc_minor, R_OK) == 0)
- (void) process_file(psqlrc_minor, false, false);
+ (void) process_file(psqlrc_minor, false);
else if (access(psqlrc_major, R_OK) == 0)
- (void) process_file(psqlrc_major, false, false);
+ (void) process_file(psqlrc_major, false);
else if (access(filename, R_OK) == 0)
- (void) process_file(filename, false, false);
+ (void) process_file(filename, false);
free(psqlrc_minor);
free(psqlrc_major);
@@ -893,6 +942,39 @@ show_context_hook(const char *newval)
}
+/*
+ * Support for list of actions. SimpleStringList cannot be used due possible
+ * combination different actions with the requirement to save the order.
+ */
+static void
+simple_action_list_append(SimpleActionList *list, int action, const char *val)
+{
+ SimpleActionListCell *cell;
+ size_t vallen = 0;
+
+ if (val)
+ vallen = strlen(val);
+
+ cell = (SimpleActionListCell *)
+ pg_malloc(offsetof(SimpleActionListCell, val) + vallen + 1);
+
+ cell->next = NULL;
+ cell->action = action;
+ if (val)
+ {
+ cell->val = pg_malloc(vallen + 1);
+ strcpy(cell->val, val);
+ }
+ else
+ cell->val = NULL;
+
+ if (list->tail)
+ list->tail->next = cell;
+ else
+ list->head = cell;
+ list->tail = cell;
+}
+
static void
EstablishVariableSpace(void)
{
On Sun, Dec 6, 2015 at 10:56 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:
Thanks, I looked at that again and problem is fixed as attached.
Er, not exactly... poll_query_until in PostgresNode.pm is using psql
-c without the --no-psqlrc switch so this patch causes the regression
tests of pg_rewind to fail. Fixed as attached.
--
Michael
Attachments:
20151206_psql_commands_v4.patchbinary/octet-stream; name=20151206_psql_commands_v4.patchDownload
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index e4f72a8..47e9da2 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -38,9 +38,10 @@ PostgreSQL documentation
<productname>PostgreSQL</productname>. It enables you to type in
queries interactively, issue them to
<productname>PostgreSQL</productname>, and see the query results.
- Alternatively, input can be from a file. In addition, it provides a
- number of meta-commands and various shell-like features to
- facilitate writing scripts and automating a wide variety of tasks.
+ Alternatively, input can be from a file or from command line
+ arguments. In addition, it provides a number of meta-commands and various
+ shell-like features to facilitate writing scripts and automating a wide
+ variety of tasks.
</para>
</refsect1>
@@ -89,11 +90,10 @@ PostgreSQL documentation
<term><option>--command=<replaceable class="parameter">command</replaceable></></term>
<listitem>
<para>
- Specifies that <application>psql</application> is to execute one
- command string, <replaceable class="parameter">command</replaceable>,
- and then exit. This is useful in shell scripts. Start-up files
- (<filename>psqlrc</filename> and <filename>~/.psqlrc</filename>) are
- ignored with this option.
+ Specifies that <application>psql</application> is to execute the given
+ command string, <replaceable class="parameter">command</replaceable>.
+ This option can be repeated and combined in any order with
+ the <option>-f</option> option.
</para>
<para>
<replaceable class="parameter">command</replaceable> must be either
@@ -102,25 +102,34 @@ PostgreSQL documentation
or a single backslash command. Thus you cannot mix
<acronym>SQL</acronym> and <application>psql</application>
meta-commands with this option. To achieve that, you could
- pipe the string into <application>psql</application>, for example:
+ use repeated <option>-c</option> options or pipe the string
+ into <application>psql</application>, for example:
+ <literal>psql -c '\x' -c 'SELECT * FROM foo;'</literal> or
<literal>echo '\x \\ SELECT * FROM foo;' | psql</literal>.
(<literal>\\</> is the separator meta-command.)
</para>
<para>
- If the command string contains multiple SQL commands, they are
- processed in a single transaction, unless there are explicit
- <command>BEGIN</>/<command>COMMIT</> commands included in the
- string to divide it into multiple transactions. This is
- different from the behavior when the same string is fed to
- <application>psql</application>'s standard input. Also, only
- the result of the last SQL command is returned.
+ Each command string passed to <option>-c</option> is sent to the server
+ as a single query. Because of this, the server executes it as a single
+ transaction, even if a command string contains
+ multiple <acronym>SQL</acronym> commands, unless there are
+ explicit <command>BEGIN</>/<command>COMMIT</> commands included in the
+ string to divide it into multiple transactions. Also, the server only
+ returns the result of the last <acronym>SQL</acronym> command to the
+ client. This is different from the behavior when the same string with
+ multiple <acronym>SQL</acronym> commands is fed
+ to <application>psql</application>'s standard input because
+ then <application>psql</application> sends each <acronym>SQL</acronym>
+ command separately.
</para>
<para>
- Because of these legacy behaviors, putting more than one command in
- the <option>-c</option> string often has unexpected results. It's
- better to feed multiple commands to <application>psql</application>'s
- standard input, either using <application>echo</application> as
- illustrated above, or via a shell here-document, for example:
+ Putting more than one command in the <option>-c</option> string often
+ has unexpected results. This is a result of the fact that the whole
+ string is sent to the server as a single query.
+ It's better to use repeated <option>-c</option> commands or feed
+ multiple commands to <application>psql</application>'s standard input,
+ either using <application>echo</application> as illustrated above, or
+ via a shell here-document, for example:
<programlisting>
psql <<EOF
\x
@@ -185,9 +194,11 @@ EOF
<para>
Use the file <replaceable class="parameter">filename</replaceable>
as the source of commands instead of reading commands interactively.
- After the file is processed, <application>psql</application>
- terminates. This is in many ways equivalent to the meta-command
- <command>\i</command>.
+ This option can be repeated and combined in any order with
+ the <option>-c</option> option. After the commands in
+ every <option>-c</option> command string and <option>-f</option> file
+ are processed, <application>psql</application> terminates. This option
+ is in many ways equivalent to the meta-command <command>\i</command>.
</para>
<para>
@@ -539,20 +550,21 @@ EOF
<term><option>--single-transaction</option></term>
<listitem>
<para>
- When <application>psql</application> executes a script, adding
- this option wraps <command>BEGIN</>/<command>COMMIT</> around the
- script to execute it as a single transaction. This ensures that
- either all the commands complete successfully, or no changes are
- applied.
+ When <application>psql</application> executes commands from a script
+ and/or a <option>-c</option> option, adding this option
+ wraps <command>BEGIN</>/<command>COMMIT</> around all of those
+ commands as a whole to execute them as a single transaction. This
+ ensures that either all the commands complete successfully, or no
+ changes are applied.
</para>
<para>
- If the script itself uses <command>BEGIN</>, <command>COMMIT</>,
+ If the commands themselves
+ contain <command>BEGIN</>, <command>COMMIT</>,
or <command>ROLLBACK</>, this option will not have the desired
- effects.
- Also, if the script contains any command that cannot be executed
- inside a transaction block, specifying this option will cause that
- command (and hence the whole transaction) to fail.
+ effects. Also, if an individual command cannot be executed inside a
+ transaction block, specifying this option will cause the whole
+ transaction to fail.
</para>
</listitem>
</varlistentry>
@@ -3725,7 +3737,7 @@ PSQL_EDITOR_LINENUMBER_ARG='--line '
<term><filename>psqlrc</filename> and <filename>~/.psqlrc</filename></term>
<listitem>
<para>
- Unless it is passed an <option>-X</option> or <option>-c</option> option,
+ Unless it is passed an <option>-X</option> option,
<application>psql</application> attempts to read and execute commands
from the system-wide startup file (<filename>psqlrc</filename>) and then
the user's personal startup file (<filename>~/.psqlrc</filename>), after
@@ -3819,6 +3831,12 @@ PSQL_EDITOR_LINENUMBER_ARG='--line '
</para>
</listitem>
+ <listitem>
+ <para>
+ Before <productname>PostgreSQL</productname> 9.6, <option>-c</option>
+ implied <option>-X</option>; this is no longer the case.
+ </para>
+ </listitem>
</itemizedlist>
</refsect1>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 6e8c623..cf6876b 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -916,7 +916,7 @@ exec_command(const char *cmd,
include_relative = (strcmp(cmd, "ir") == 0
|| strcmp(cmd, "include_relative") == 0);
expand_tilde(&fname);
- success = (process_file(fname, false, include_relative) == EXIT_SUCCESS);
+ success = (process_file(fname, include_relative) == EXIT_SUCCESS);
free(fname);
}
}
@@ -2288,13 +2288,12 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
* the file from where the currently processed file (if any) is located.
*/
int
-process_file(char *filename, bool single_txn, bool use_relative_path)
+process_file(char *filename, bool use_relative_path)
{
FILE *fd;
int result;
char *oldfilename;
char relpath[MAXPGPATH];
- PGresult *res;
if (!filename)
{
@@ -2339,37 +2338,8 @@ process_file(char *filename, bool single_txn, bool use_relative_path)
oldfilename = pset.inputfile;
pset.inputfile = filename;
- if (single_txn)
- {
- if ((res = PSQLexec("BEGIN")) == NULL)
- {
- if (pset.on_error_stop)
- {
- result = EXIT_USER;
- goto error;
- }
- }
- else
- PQclear(res);
- }
-
result = MainLoop(fd);
- if (single_txn)
- {
- if ((res = PSQLexec("COMMIT")) == NULL)
- {
- if (pset.on_error_stop)
- {
- result = EXIT_USER;
- goto error;
- }
- }
- else
- PQclear(res);
- }
-
-error:
if (fd != stdin)
fclose(fd);
diff --git a/src/bin/psql/command.h b/src/bin/psql/command.h
index 54385e8..c817600 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, bool use_relative_path);
+extern int process_file(char *filename, bool use_relative_path);
extern bool do_pset(const char *param,
const char *value,
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 4e5021a..7af38fb 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -50,13 +50,24 @@ PsqlSettings pset;
*/
enum _actions
{
- ACT_NOTHING = 0,
- ACT_SINGLE_SLASH,
- ACT_LIST_DB,
ACT_SINGLE_QUERY,
+ ACT_SINGLE_SLASH,
ACT_FILE
};
+typedef struct SimpleActionListCell
+{
+ struct SimpleActionListCell *next;
+ int action;
+ char *val;
+} SimpleActionListCell;
+
+typedef struct SimpleActionList
+{
+ SimpleActionListCell *head;
+ SimpleActionListCell *tail;
+} SimpleActionList;
+
struct adhoc_opts
{
char *dbname;
@@ -64,11 +75,11 @@ struct adhoc_opts
char *port;
char *username;
char *logfilename;
- enum _actions action;
- char *action_string;
bool no_readline;
bool no_psqlrc;
bool single_txn;
+ bool list_dbs;
+ SimpleActionList actions;
};
static void parse_psql_options(int argc, char *argv[],
@@ -76,6 +87,8 @@ static void parse_psql_options(int argc, char *argv[],
static void process_psqlrc(char *argv0);
static void process_psqlrc_file(char *filename);
static void showVersion(void);
+static void simple_action_list_append(SimpleActionList *list,
+ int action, const char *val);
static void EstablishVariableSpace(void);
#define NOPAGER 0
@@ -159,6 +172,9 @@ main(int argc, char *argv[])
SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
+ options.actions.head = NULL;
+ options.actions.tail = NULL;
+
parse_psql_options(argc, argv, &options);
/*
@@ -166,14 +182,11 @@ main(int argc, char *argv[])
* as if the user had specified "-f -". This lets single-transaction mode
* work in this case.
*/
- if (options.action == ACT_NOTHING && pset.notty)
- {
- options.action = ACT_FILE;
- options.action_string = NULL;
- }
+ if (options.actions.head == NULL && pset.notty)
+ simple_action_list_append(&options.actions, ACT_FILE, NULL);
/* Bail out if -1 was specified but will be ignored. */
- if (options.single_txn && options.action != ACT_FILE && options.action == ACT_NOTHING)
+ if (options.single_txn && options.actions.head == NULL)
{
fprintf(stderr, _("%s: -1 can only be used in non-interactive mode\n"), pset.progname);
exit(EXIT_FAILURE);
@@ -217,8 +230,7 @@ main(int argc, char *argv[])
keywords[3] = "password";
values[3] = password;
keywords[4] = "dbname";
- values[4] = (options.action == ACT_LIST_DB &&
- options.dbname == NULL) ?
+ values[4] = (options.list_dbs && options.dbname == NULL) ?
"postgres" : options.dbname;
keywords[5] = "fallback_application_name";
values[5] = pset.progname;
@@ -259,7 +271,7 @@ main(int argc, char *argv[])
SyncVariables();
- if (options.action == ACT_LIST_DB)
+ if (options.list_dbs)
{
int success;
@@ -279,52 +291,91 @@ main(int argc, char *argv[])
pset.progname, options.logfilename, strerror(errno));
}
- /*
- * Now find something to do
- */
+ if (!options.no_psqlrc)
+ process_psqlrc(argv[0]);
/*
- * process file given by -f
+ * If any actions were given by caller, process them in the order in
+ * which they were specified.
*/
- if (options.action == ACT_FILE)
+ if (options.actions.head != NULL)
{
- if (!options.no_psqlrc)
- process_psqlrc(argv[0]);
+ PGresult *res;
+ SimpleActionListCell *cell;
- successResult = process_file(options.action_string, options.single_txn, false);
- }
+ successResult = EXIT_SUCCESS; /* silence compiler */
- /*
- * process slash command if one was given to -c
- */
- else if (options.action == ACT_SINGLE_SLASH)
- {
- PsqlScanState scan_state;
-
- if (pset.echo == PSQL_ECHO_ALL)
- puts(options.action_string);
-
- scan_state = psql_scan_create();
- psql_scan_setup(scan_state,
- options.action_string,
- strlen(options.action_string));
-
- successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
- ? EXIT_SUCCESS : EXIT_FAILURE;
+ if (options.single_txn)
+ {
+ if ((res = PSQLexec("BEGIN")) == NULL)
+ {
+ if (pset.on_error_stop)
+ {
+ successResult = EXIT_USER;
+ goto error;
+ }
+ }
+ else
+ PQclear(res);
+ }
- psql_scan_destroy(scan_state);
- }
+ for (cell = options.actions.head; cell; cell = cell->next)
+ {
+ if (cell->action == ACT_SINGLE_QUERY)
+ {
+ if (pset.echo == PSQL_ECHO_ALL)
+ puts(cell->val);
+
+ successResult = SendQuery(cell->val)
+ ? EXIT_SUCCESS : EXIT_FAILURE;
+ }
+ else if (cell->action == ACT_SINGLE_SLASH)
+ {
+ PsqlScanState scan_state;
+
+ if (pset.echo == PSQL_ECHO_ALL)
+ puts(cell->val);
+
+ scan_state = psql_scan_create();
+ psql_scan_setup(scan_state,
+ cell->val,
+ strlen(cell->val));
+
+ successResult = HandleSlashCmds(scan_state, NULL) != PSQL_CMD_ERROR
+ ? EXIT_SUCCESS : EXIT_FAILURE;
+
+ psql_scan_destroy(scan_state);
+ }
+ else if (cell->action == ACT_FILE)
+ {
+ successResult = process_file(cell->val, false);
+ }
+ else
+ {
+ /* should never come here */
+ Assert(0);
+ }
+
+ if (successResult != EXIT_SUCCESS && pset.on_error_stop)
+ break;
+ }
- /*
- * If the query given to -c was a normal one, send it
- */
- else if (options.action == ACT_SINGLE_QUERY)
- {
- if (pset.echo == PSQL_ECHO_ALL)
- puts(options.action_string);
+ if (options.single_txn)
+ {
+ if ((res = PSQLexec("COMMIT")) == NULL)
+ {
+ if (pset.on_error_stop)
+ {
+ successResult = EXIT_USER;
+ goto error;
+ }
+ }
+ else
+ PQclear(res);
+ }
- successResult = SendQuery(options.action_string)
- ? EXIT_SUCCESS : EXIT_FAILURE;
+error:
+ ;
}
/*
@@ -332,9 +383,6 @@ main(int argc, char *argv[])
*/
else
{
- if (!options.no_psqlrc)
- process_psqlrc(argv[0]);
-
connection_warnings(true);
if (!pset.quiet)
printf(_("Type \"help\" for help.\n\n"));
@@ -419,14 +467,14 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
SetVariable(pset.vars, "ECHO", "errors");
break;
case 'c':
- options->action_string = pg_strdup(optarg);
if (optarg[0] == '\\')
- {
- options->action = ACT_SINGLE_SLASH;
- options->action_string++;
- }
+ simple_action_list_append(&options->actions,
+ ACT_SINGLE_SLASH,
+ pstrdup(optarg + 1));
else
- options->action = ACT_SINGLE_QUERY;
+ simple_action_list_append(&options->actions,
+ ACT_SINGLE_QUERY,
+ pstrdup(optarg));
break;
case 'd':
options->dbname = pg_strdup(optarg);
@@ -438,8 +486,9 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
SetVariableBool(pset.vars, "ECHO_HIDDEN");
break;
case 'f':
- options->action = ACT_FILE;
- options->action_string = pg_strdup(optarg);
+ simple_action_list_append(&options->actions,
+ ACT_FILE,
+ pg_strdup(optarg));
break;
case 'F':
pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
@@ -452,7 +501,7 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
pset.popt.topt.format = PRINT_HTML;
break;
case 'l':
- options->action = ACT_LIST_DB;
+ options->list_dbs = true;
break;
case 'L':
options->logfilename = pg_strdup(optarg);
@@ -675,11 +724,11 @@ process_psqlrc_file(char *filename)
/* check for minor version first, then major, then no version */
if (access(psqlrc_minor, R_OK) == 0)
- (void) process_file(psqlrc_minor, false, false);
+ (void) process_file(psqlrc_minor, false);
else if (access(psqlrc_major, R_OK) == 0)
- (void) process_file(psqlrc_major, false, false);
+ (void) process_file(psqlrc_major, false);
else if (access(filename, R_OK) == 0)
- (void) process_file(filename, false, false);
+ (void) process_file(filename, false);
free(psqlrc_minor);
free(psqlrc_major);
@@ -893,6 +942,39 @@ show_context_hook(const char *newval)
}
+/*
+ * Support for list of actions. SimpleStringList cannot be used due possible
+ * combination different actions with the requirement to save the order.
+ */
+static void
+simple_action_list_append(SimpleActionList *list, int action, const char *val)
+{
+ SimpleActionListCell *cell;
+ size_t vallen = 0;
+
+ if (val)
+ vallen = strlen(val);
+
+ cell = (SimpleActionListCell *)
+ pg_malloc(offsetof(SimpleActionListCell, val) + vallen + 1);
+
+ cell->next = NULL;
+ cell->action = action;
+ if (val)
+ {
+ cell->val = pg_malloc(vallen + 1);
+ strcpy(cell->val, val);
+ }
+ else
+ cell->val = NULL;
+
+ if (list->tail)
+ list->tail->next = cell;
+ else
+ list->head = cell;
+ list->tail = cell;
+}
+
static void
EstablishVariableSpace(void)
{
diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm
index aa7a00c..0ac1846 100644
--- a/src/test/perl/PostgresNode.pm
+++ b/src/test/perl/PostgresNode.pm
@@ -404,7 +404,7 @@ sub poll_query_until
while ($attempts < $max_attempts)
{
my $cmd =
- [ 'psql', '-At', '-c', $query, '-d', $self->connstr($dbname) ];
+ [ 'psql', '-XAt', '-c', $query, '-d', $self->connstr($dbname) ];
my $result = IPC::Run::run $cmd, '>', \$stdout, '2>', \$stderr;
chomp($stdout);
On Fri, Dec 4, 2015 at 11:08 AM, Catalin Iacob <iacobcatalin@gmail.com> wrote:
On Fri, Dec 4, 2015 at 3:47 PM, Robert Haas <robertmhaas@gmail.com> wrote:
For the most part, the cleanups in this version are just cosmetic: I
fixed some whitespace damage, and reverted some needless changes to
the psql references page that were whitespace-only adjustments. In a
few places, I tweaked documentation or comment language.Sorry for the docs whitespace-only changes, I did that.
I realized before the submission I made the diff bigger than it needed
to be, but that's because I used M-q in Emacs to break the lines I did
change and that reformatted the whole paragraph including some
unchanged lines. Breaking all the lines by hand would be quite a job,
and any time you go back and tweak the wording or so you need to do it
again. So I just used M-q and sent the result of that.
Do you happen to know of a better way to do this?
No. I always redo the indentation by hand and then look at the diff
afterwards to see if there's anything I can strip out.
I also use vim rather than emacs, except when my hand is steady enough
for the magnetized needle approach.[1]https://xkcd.com/378/
--
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
On Tue, Dec 08, 2015 at 01:51:57PM -0500, Robert Haas wrote:
On Fri, Dec 4, 2015 at 11:08 AM, Catalin Iacob <iacobcatalin@gmail.com> wrote:
On Fri, Dec 4, 2015 at 3:47 PM, Robert Haas <robertmhaas@gmail.com> wrote:
For the most part, the cleanups in this version are just cosmetic: I
fixed some whitespace damage, and reverted some needless changes to
the psql references page that were whitespace-only adjustments. In a
few places, I tweaked documentation or comment language.Sorry for the docs whitespace-only changes, I did that.
I realized before the submission I made the diff bigger than it needed
to be, but that's because I used M-q in Emacs to break the lines I did
change and that reformatted the whole paragraph including some
unchanged lines. Breaking all the lines by hand would be quite a job,
and any time you go back and tweak the wording or so you need to do it
again. So I just used M-q and sent the result of that.
Do you happen to know of a better way to do this?No. I always redo the indentation by hand and then look at the diff
afterwards to see if there's anything I can strip out.
There's also an excellent git check-whitepace thing Peter Eisentraut
put together:
http://peter.eisentraut.org/blog/2014/11/04/checking-whitespace-with-git/
I also use vim rather than emacs, except when my hand is steady enough
for the magnetized needle approach.[1]
I figured you for more the butterfly type.
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
Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sun, Dec 6, 2015 at 9:27 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:
On Sun, Dec 6, 2015 at 10:56 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:Thanks, I looked at that again and problem is fixed as attached.
Er, not exactly... poll_query_until in PostgresNode.pm is using psql
-c without the --no-psqlrc switch so this patch causes the regression
tests of pg_rewind to fail. Fixed as attached.
Committed. Go, team.
This has been a long time coming.
--
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
2015-12-08 20:09 GMT+01:00 Robert Haas <robertmhaas@gmail.com>:
On Sun, Dec 6, 2015 at 9:27 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:On Sun, Dec 6, 2015 at 10:56 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:Thanks, I looked at that again and problem is fixed as attached.
Er, not exactly... poll_query_until in PostgresNode.pm is using psql
-c without the --no-psqlrc switch so this patch causes the regression
tests of pg_rewind to fail. Fixed as attached.Committed. Go, team.
This has been a long time coming.
great, thank you very much you and all
Regards
Pavel
Show quoted text
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Wed, Dec 9, 2015 at 5:08 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
2015-12-08 20:09 GMT+01:00 Robert Haas <robertmhaas@gmail.com>:
On Sun, Dec 6, 2015 at 9:27 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:On Sun, Dec 6, 2015 at 10:56 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:Thanks, I looked at that again and problem is fixed as attached.
Er, not exactly... poll_query_until in PostgresNode.pm is using psql
-c without the --no-psqlrc switch so this patch causes the regression
tests of pg_rewind to fail. Fixed as attached.Committed. Go, team.
This has been a long time coming.
great, thank you very much you and all
Thanks! This is now marked as committed in the CF app...
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2015-12-09 1:27 GMT+01:00 Michael Paquier <michael.paquier@gmail.com>:
On Wed, Dec 9, 2015 at 5:08 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:2015-12-08 20:09 GMT+01:00 Robert Haas <robertmhaas@gmail.com>:
On Sun, Dec 6, 2015 at 9:27 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:On Sun, Dec 6, 2015 at 10:56 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:Thanks, I looked at that again and problem is fixed as attached.
Er, not exactly... poll_query_until in PostgresNode.pm is using psql
-c without the --no-psqlrc switch so this patch causes the regression
tests of pg_rewind to fail. Fixed as attached.Committed. Go, team.
This has been a long time coming.
great, thank you very much you and all
Thanks! This is now marked as committed in the CF app...
should be noted, recorded somewhere so this introduce possible
compatibility issue - due default processing .psqlrc.
Regards
Pavel
Show quoted text
--
Michael
On Wed, Dec 9, 2015 at 2:07 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
should be noted, recorded somewhere so this introduce possible compatibility
issue - due default processing .psqlrc.
That's written in the commit log, so I guess that's fine.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2015-12-09 6:10 GMT+01:00 Michael Paquier <michael.paquier@gmail.com>:
On Wed, Dec 9, 2015 at 2:07 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:should be noted, recorded somewhere so this introduce possible
compatibility
issue - due default processing .psqlrc.
That's written in the commit log, so I guess that's fine.
ook
Show quoted text
--
Michael
On Wed, Dec 9, 2015 at 12:15 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
On Wed, Dec 9, 2015 at 2:07 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:should be noted, recorded somewhere so this introduce possible
compatibility
issue - due default processing .psqlrc.That's written in the commit log, so I guess that's fine.
ook
Bruce uses the commit log to prepare the release notes, so I guess
he'll make mention of this.
--
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
On Thu, Dec 10, 2015 at 11:10:55AM -0500, Robert Haas wrote:
On Wed, Dec 9, 2015 at 12:15 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
On Wed, Dec 9, 2015 at 2:07 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:should be noted, recorded somewhere so this introduce possible
compatibility
issue - due default processing .psqlrc.That's written in the commit log, so I guess that's fine.
ook
Bruce uses the commit log to prepare the release notes, so I guess
he'll make mention of this.
Yes, I will certainly see it.
--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com
+ As you are, so once was I. As I am, so you will be. +
+ Roman grave inscription +
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 12/29/15 10:38 AM, Bruce Momjian wrote:
On Thu, Dec 10, 2015 at 11:10:55AM -0500, Robert Haas wrote:
On Wed, Dec 9, 2015 at 12:15 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:
On Wed, Dec 9, 2015 at 2:07 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:should be noted, recorded somewhere so this introduce possible
compatibility
issue - due default processing .psqlrc.That's written in the commit log, so I guess that's fine.
ook
Bruce uses the commit log to prepare the release notes, so I guess
he'll make mention of this.Yes, I will certainly see it.
I generally use the master branch psql for normal work, and this change
has caused massive breakage for me. It's straightforward to fix, but in
some cases the breakage is silent, for example if you do
something=$(psql -c ...) and the .psqlrc processing causes additional
output. I'm not sure what to make of it yet, but I want to mention it,
because I fear there will be heartache.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2016-02-05 2:35 GMT+01:00 Peter Eisentraut <peter_e@gmx.net>:
On 12/29/15 10:38 AM, Bruce Momjian wrote:
On Thu, Dec 10, 2015 at 11:10:55AM -0500, Robert Haas wrote:
On Wed, Dec 9, 2015 at 12:15 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:
On Wed, Dec 9, 2015 at 2:07 PM, Pavel Stehule <
pavel.stehule@gmail.com>
wrote:
should be noted, recorded somewhere so this introduce possible
compatibility
issue - due default processing .psqlrc.That's written in the commit log, so I guess that's fine.
ook
Bruce uses the commit log to prepare the release notes, so I guess
he'll make mention of this.Yes, I will certainly see it.
I generally use the master branch psql for normal work, and this change
has caused massive breakage for me. It's straightforward to fix, but in
some cases the breakage is silent, for example if you do
something=$(psql -c ...) and the .psqlrc processing causes additional
output. I'm not sure what to make of it yet, but I want to mention it,
because I fear there will be heartache.
We can still introduce some system environment, that disable psqlrc globally
PGNOPSQLRC=1 psql ...
Regards
Pavel
On Thu, Feb 4, 2016 at 8:35 PM, Peter Eisentraut <peter_e@gmx.net> wrote:
I generally use the master branch psql for normal work, and this change
has caused massive breakage for me. It's straightforward to fix, but in
some cases the breakage is silent, for example if you do
something=$(psql -c ...) and the .psqlrc processing causes additional
output. I'm not sure what to make of it yet, but I want to mention it,
because I fear there will be heartache.
I think this is a good thing to be concerned about, but I'm not sure
what to make of it either. We could of course decide that -c implies
--no-psqlrc after all, for backward compatibility reasons. That would
be sort of strange because then psql -c A -f B will imply --no-psqlrc
but psql -f B will not. And that doesn't seem great either. I'm
inclined toward thinking we should just accept that some people will
need to update their scripts, but if that turns out to make enough
people unhappy then I may regret thinking that.
--
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