mirror of
https://git.savannah.gnu.org/git/parallel.git
synced 2024-12-22 20:57:53 +00:00
Added: sql - a small script to access sql bases from the command line
This commit is contained in:
parent
b26dbadcc0
commit
6ad5f9f693
|
@ -64,8 +64,8 @@
|
|||
'AM_SET_LEADING_DOT' => 1,
|
||||
'AM_SET_DEPDIR' => 1,
|
||||
'_AM_DEPENDENCIES' => 1,
|
||||
'AM_PROG_INSTALL_SH' => 1,
|
||||
'm4_include' => 1,
|
||||
'AM_PROG_INSTALL_SH' => 1,
|
||||
'_AC_AM_CONFIG_HEADER_HOOK' => 1,
|
||||
'AU_DEFUN' => 1,
|
||||
'AM_MAKE_INCLUDE' => 1
|
||||
|
@ -83,25 +83,25 @@
|
|||
'configure.ac'
|
||||
],
|
||||
{
|
||||
'_LT_AC_TAGCONFIG' => 1,
|
||||
'AM_PROG_F77_C_O' => 1,
|
||||
'm4_pattern_forbid' => 1,
|
||||
'_LT_AC_TAGCONFIG' => 1,
|
||||
'AC_INIT' => 1,
|
||||
'_AM_COND_IF' => 1,
|
||||
'm4_pattern_forbid' => 1,
|
||||
'AC_CANONICAL_TARGET' => 1,
|
||||
'AC_SUBST' => 1,
|
||||
'_AM_COND_IF' => 1,
|
||||
'AC_CONFIG_LIBOBJ_DIR' => 1,
|
||||
'AC_FC_SRCEXT' => 1,
|
||||
'AC_SUBST' => 1,
|
||||
'AC_CANONICAL_HOST' => 1,
|
||||
'AC_FC_SRCEXT' => 1,
|
||||
'AC_PROG_LIBTOOL' => 1,
|
||||
'AM_INIT_AUTOMAKE' => 1,
|
||||
'AC_CONFIG_SUBDIRS' => 1,
|
||||
'AM_AUTOMAKE_VERSION' => 1,
|
||||
'LT_CONFIG_LTDL_DIR' => 1,
|
||||
'AC_REQUIRE_AUX_FILE' => 1,
|
||||
'AC_CONFIG_LINKS' => 1,
|
||||
'm4_sinclude' => 1,
|
||||
'AC_REQUIRE_AUX_FILE' => 1,
|
||||
'LT_SUPPORTED_TAG' => 1,
|
||||
'm4_sinclude' => 1,
|
||||
'AM_MAINTAINER_MODE' => 1,
|
||||
'AM_GNU_GETTEXT_INTL_SUBDIR' => 1,
|
||||
'_m4_warn' => 1,
|
||||
|
@ -114,17 +114,17 @@
|
|||
'include' => 1,
|
||||
'AM_GNU_GETTEXT' => 1,
|
||||
'AC_LIBSOURCE' => 1,
|
||||
'AM_PROG_FC_C_O' => 1,
|
||||
'AC_CANONICAL_BUILD' => 1,
|
||||
'AM_PROG_FC_C_O' => 1,
|
||||
'AC_FC_FREEFORM' => 1,
|
||||
'AH_OUTPUT' => 1,
|
||||
'_AM_SUBST_NOTMAKE' => 1,
|
||||
'AC_CONFIG_AUX_DIR' => 1,
|
||||
'sinclude' => 1,
|
||||
'm4_pattern_allow' => 1,
|
||||
'_AM_SUBST_NOTMAKE' => 1,
|
||||
'AM_PROG_CC_C_O' => 1,
|
||||
'AC_CANONICAL_SYSTEM' => 1,
|
||||
'm4_pattern_allow' => 1,
|
||||
'sinclude' => 1,
|
||||
'AM_CONDITIONAL' => 1,
|
||||
'AC_CANONICAL_SYSTEM' => 1,
|
||||
'AC_CONFIG_HEADERS' => 1,
|
||||
'AC_DEFINE_TRACE_LITERAL' => 1,
|
||||
'm4_include' => 1,
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
Bugfix: --eta/--progress with 0 jobs gave division by zero.
|
||||
Bugfix in Makefile by Piotr Jaroszyński <p dot jaroszynski at gmail dot com>
|
||||
|
||||
fex syntax for splitting fields
|
||||
http://www.semicomplete.com/projects/fex/
|
||||
sql :foo 'select * from bar' | parallel --fex '|{1,2}' do_stuff {2} {1}
|
||||
|
||||
Import sql
|
||||
|
||||
inputfile tabel, Split colonner til {n}
|
||||
sql :foo 'select * from bar' | parallel --colsep '\|' do_stuff {4} {1}
|
||||
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ to:parallel@gnu.org, bug-parallel@gnu.org, info-gnu@gnu.org, bug-directory@gnu.o
|
|||
cc:Peter Simons <simons@cryp.to>, Sandro Cazzaniga <kharec@mandriva.org>,
|
||||
Tim Cuthbertson <tim3d.junk@gmail.com>, Ludovic Courtès <ludo@gnu.org>,
|
||||
Markus Ammer <mkmm@gmx-topmail.de>, Pavel Nuzhdin <pnzhdin@gmail.com>,
|
||||
Phil Sung <psung@alum.mit.edu>
|
||||
Phil Sung <psung@alum.mit.edu>, Michael Shigorin <mike@altlinux.org>
|
||||
|
||||
Subject: GNU Parallel 20100822 released
|
||||
|
||||
|
@ -99,7 +99,9 @@ download at: http://ftp.gnu.org/gnu/parallel/
|
|||
New in this release:
|
||||
|
||||
* First community generated bugfixes
|
||||
Piotr Jaroszyński <p.jaroszynski@gmail.com>
|
||||
|
||||
* Alt Linux package of GNU Parallel. Thanks to Michael Shigorin <mike
|
||||
at altlinux dot org>
|
||||
|
||||
= About GNU Parallel =
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
bin_SCRIPTS = parallel sem
|
||||
man_MANS = parallel.1 sem.1
|
||||
doc_DATA = parallel.html sem.html
|
||||
bin_SCRIPTS = parallel sem sql
|
||||
man_MANS = parallel.1 sem.1 sql.1
|
||||
doc_DATA = parallel.html sem.html sql.html
|
||||
|
||||
parallel.1: parallel Makefile
|
||||
pod2man --release='$(PACKAGE_VERSION)' --center='$(PACKAGE_NAME)' \
|
||||
|
@ -10,6 +10,10 @@ sem.1: sem.pod Makefile
|
|||
pod2man --release='$(PACKAGE_VERSION)' --center='$(PACKAGE_NAME)' \
|
||||
--section=1 $(srcdir)/sem.pod > $(srcdir)/sem.1
|
||||
|
||||
sql.1: sql Makefile
|
||||
pod2man --release='$(PACKAGE_VERSION)' --center='$(PACKAGE_NAME)' \
|
||||
--section=1 $(srcdir)/sql > $(srcdir)/sql.1
|
||||
|
||||
parallel.html: parallel Makefile
|
||||
pod2html $(srcdir)/parallel > $(srcdir)/parallel.html
|
||||
rm -f $(srcdir)/pod2htm*
|
||||
|
@ -18,8 +22,12 @@ sem.html: sem.pod Makefile
|
|||
pod2html $(srcdir)/sem.pod > $(srcdir)/sem.html
|
||||
rm -f $(srcdir)/pod2htm*
|
||||
|
||||
sql.html: sql Makefile
|
||||
pod2html $(srcdir)/sql > $(srcdir)/sql.html
|
||||
rm -f $(srcdir)/pod2htm*
|
||||
|
||||
sem: parallel
|
||||
ln -fs parallel sem
|
||||
|
||||
DISTCLEANFILES = parallel.1 sem.1 parallel.html sem.html
|
||||
EXTRA_DIST = parallel sem parallel.1 sem.1 parallel.html sem.html sem.pod
|
||||
DISTCLEANFILES = parallel.1 sem.1 sql.1 parallel.html sem.html sql.html
|
||||
EXTRA_DIST = parallel sem sql parallel.1 sem.1 sql.1 parallel.html sem.html sem.pod sql.html
|
||||
|
|
|
@ -146,11 +146,11 @@ target_alias = @target_alias@
|
|||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
bin_SCRIPTS = parallel sem
|
||||
man_MANS = parallel.1 sem.1
|
||||
doc_DATA = parallel.html sem.html
|
||||
DISTCLEANFILES = parallel.1 sem.1 parallel.html sem.html
|
||||
EXTRA_DIST = parallel sem parallel.1 sem.1 parallel.html sem.html sem.pod
|
||||
bin_SCRIPTS = parallel sem sql
|
||||
man_MANS = parallel.1 sem.1 sql.1
|
||||
doc_DATA = parallel.html sem.html sql.html
|
||||
DISTCLEANFILES = parallel.1 sem.1 sql.1 parallel.html sem.html sql.html
|
||||
EXTRA_DIST = parallel sem sql parallel.1 sem.1 sql.1 parallel.html sem.html sem.pod sql.html
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
|
@ -451,6 +451,10 @@ sem.1: sem.pod Makefile
|
|||
pod2man --release='$(PACKAGE_VERSION)' --center='$(PACKAGE_NAME)' \
|
||||
--section=1 $(srcdir)/sem.pod > $(srcdir)/sem.1
|
||||
|
||||
sql.1: sql Makefile
|
||||
pod2man --release='$(PACKAGE_VERSION)' --center='$(PACKAGE_NAME)' \
|
||||
--section=1 $(srcdir)/sql > $(srcdir)/sql.1
|
||||
|
||||
parallel.html: parallel Makefile
|
||||
pod2html $(srcdir)/parallel > $(srcdir)/parallel.html
|
||||
rm -f $(srcdir)/pod2htm*
|
||||
|
@ -459,6 +463,10 @@ sem.html: sem.pod Makefile
|
|||
pod2html $(srcdir)/sem.pod > $(srcdir)/sem.html
|
||||
rm -f $(srcdir)/pod2htm*
|
||||
|
||||
sql.html: sql Makefile
|
||||
pod2html $(srcdir)/sql > $(srcdir)/sql.html
|
||||
rm -f $(srcdir)/pod2htm*
|
||||
|
||||
sem: parallel
|
||||
ln -fs parallel sem
|
||||
|
||||
|
|
697
src/sql
Executable file
697
src/sql
Executable file
|
@ -0,0 +1,697 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
=head1 NAME
|
||||
|
||||
sql - execute a command on a database determined by a dburl
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<sql> [B<-hnr>] [B<--table-size>] [B<--db-size>] [B<-p> I<pass-through>] [B<-s> I<string>] I<dburl> [I<command>]
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
GNU B<sql> aims to give a simple, unified interface for accessing
|
||||
databases through all the different databases' command line
|
||||
clients. So far the focus has been on giving a common way to specify
|
||||
login information (protocol, username, password, hostname, and port
|
||||
number), size (database and table size), and running queries.
|
||||
|
||||
The database is addressed using a dburl. If I<command> is left out you
|
||||
will get that database's interactive shell.
|
||||
|
||||
GNU B<sql> is often used in combination with GNU B<parallel>.
|
||||
|
||||
=over 9
|
||||
|
||||
=item I<dburl>
|
||||
|
||||
A DBURL has the following syntax:
|
||||
vendor://[user[:password]@][host][:port]/[database]
|
||||
|
||||
See the section DBURL below.
|
||||
|
||||
=item I<command>
|
||||
|
||||
The SQL command to run.
|
||||
|
||||
Example: select 1+2
|
||||
|
||||
If you use * or ? remember to quote them, as the shell may otherwise
|
||||
expand them.
|
||||
|
||||
If no command is given SQL is read from the keyboard or STDIN.
|
||||
|
||||
Example: echo 'select 1+2' | sql mysql:///
|
||||
|
||||
|
||||
=item B<--db-size>
|
||||
|
||||
=item B<--dbsize>
|
||||
|
||||
Size of database. Show the size of the database on disk.
|
||||
|
||||
|
||||
=item B<--help>
|
||||
|
||||
=item B<-h>
|
||||
|
||||
Print a summary of the options to GNU B<sql> and exit.
|
||||
|
||||
|
||||
=item B<--html>
|
||||
|
||||
HTML output. Turn on HTML tabular output.
|
||||
|
||||
|
||||
=item B<--show-processlist>
|
||||
|
||||
=item B<--proclist>
|
||||
|
||||
=item B<--listproc>
|
||||
|
||||
Show the list of running queries.
|
||||
|
||||
|
||||
=item B<--noheaders>
|
||||
|
||||
=item B<--no-headers>
|
||||
|
||||
=item B<-n>
|
||||
|
||||
Remove headers and footers and print only tuples. Bug in Oracle: it
|
||||
still prints number of rows found.
|
||||
|
||||
|
||||
=item B<-p> I<pass-through>
|
||||
|
||||
The string following -p will be given to the database connection
|
||||
program as arguments. Multiple -p's will be joined with
|
||||
space. Example:
|
||||
|
||||
I<-p "-U username"> can also be written I<-p -U -p username>.
|
||||
|
||||
|
||||
=item B<-r>
|
||||
|
||||
Try 3 times. Short version of I<--retries 3>.
|
||||
|
||||
|
||||
=item B<--retries> I<ntimes>
|
||||
|
||||
Try I<ntimes> times. If the client program returns with an error,
|
||||
retry the command. Default is I<--retries 1>.
|
||||
|
||||
|
||||
=item B<--sep> I<string>
|
||||
|
||||
=item B<-s> I<string>
|
||||
|
||||
Field separator. Use I<string> as seperator between columns.
|
||||
|
||||
|
||||
=item B<--table-size>
|
||||
|
||||
=item B<--tablesize>
|
||||
|
||||
Size of tables. Show the size of the tables in the database.
|
||||
|
||||
|
||||
=item B<--version>
|
||||
|
||||
=item B<-V>
|
||||
|
||||
Print the version GNU B<sql> and exit.
|
||||
|
||||
|
||||
=back
|
||||
|
||||
=head1 DBURL
|
||||
|
||||
A DBURL has the following syntax:
|
||||
vendor://[user[:password]@][host][:port]/[database]
|
||||
|
||||
Examples:
|
||||
mysql://user:pa55w0rd@mysqlserver/database
|
||||
oracle://scott:tiger@oracleserver/xe
|
||||
postgresql://user:pa55w0rd@pg.example.com/db
|
||||
pg:///
|
||||
|
||||
Currently supported vendors: MySQL (mysql), MySQL with SSL (mysqls,
|
||||
mysqlssl), Oracle (oracle, ora), PostgreSQL (postgresql, pg, pgsql,
|
||||
postgres), PostgreSQL with SSL (postgresqlssl, pgs, pgsqlssl,
|
||||
postgresssl, pgssl, postgresqls, pgsqls, postgress)
|
||||
|
||||
Aliases must start with ':' and is read from
|
||||
dburl.aliases.dist, dburl.aliases and ~/.dburl.aliases. The user's own
|
||||
~/.dburl.aliases should only be readable by the user.
|
||||
|
||||
Example of dburl.aliases:
|
||||
|
||||
:myalias1 pg://user:pa55w0rd@pg.example.com/db
|
||||
:myalias2 ora://scott:tiger@ora1.example.com/xe
|
||||
# Short form of mysql://`whoami`:nopassword@localhost:3306/`whoami`
|
||||
:myalias3 mysql:///
|
||||
# Short form of mysql://`whoami`:nopassword@localhost:33333/mydb
|
||||
:myalias4 mysql://:33333/mydb
|
||||
# Alias for an alias
|
||||
:m :myalias4
|
||||
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
=head2 Copy a PostgreSQL database
|
||||
|
||||
pg_dump my_database | sql pg://user:pass@pgserver/my_new_db
|
||||
|
||||
=head2 Empty all tables in a MySQL database
|
||||
|
||||
sql -n mysql:/// 'show tables' | parallel sql mysql:/// delete from {};
|
||||
|
||||
=head2 Drop all tables in a PostgreSQL database
|
||||
|
||||
sql -n pg:/// '\dt' | awk '{print $3}' | parallel -r sql pg:/// drop table {};
|
||||
|
||||
=head1 REPORTING BUGS
|
||||
|
||||
GNU B<sql> is part of GNU B<parallel>. Report bugs to <bug-parallel@gnu.org>.
|
||||
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright (C) 2008,2009,2010 Ole Tange, Ange Optimization http://ange.dk
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
Copyright (C) 2007,2008,2009,2010 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
at your option any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
=head2 Documentation license I
|
||||
|
||||
Permission is granted to copy, distribute and/or modify this documentation
|
||||
under the terms of the GNU Free Documentation License, Version 1.3 or
|
||||
any later version published by the Free Software Foundation; with no
|
||||
Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
|
||||
Texts. A copy of the license is included in the file fdl.txt.
|
||||
|
||||
=head2 Documentation license II
|
||||
|
||||
You are free:
|
||||
|
||||
=over 9
|
||||
|
||||
=item B<to Share>
|
||||
|
||||
to copy, distribute and transmit the work
|
||||
|
||||
=item B<to Remix>
|
||||
|
||||
to adapt the work
|
||||
|
||||
=back
|
||||
|
||||
Under the following conditions:
|
||||
|
||||
=over 9
|
||||
|
||||
=item B<Attribution>
|
||||
|
||||
You must attribute the work in the manner specified by the author or
|
||||
licensor (but not in any way that suggests that they endorse you or
|
||||
your use of the work).
|
||||
|
||||
=item B<Share Alike>
|
||||
|
||||
If you alter, transform, or build upon this work, you may distribute
|
||||
the resulting work only under the same, similar or a compatible
|
||||
license.
|
||||
|
||||
=back
|
||||
|
||||
With the understanding that:
|
||||
|
||||
=over 9
|
||||
|
||||
=item B<Waiver>
|
||||
|
||||
Any of the above conditions can be waived if you get permission from
|
||||
the copyright holder.
|
||||
|
||||
=item B<Public Domain>
|
||||
|
||||
Where the work or any of its elements is in the public domain under
|
||||
applicable law, that status is in no way affected by the license.
|
||||
|
||||
=item B<Other Rights>
|
||||
|
||||
In no way are any of the following rights affected by the license:
|
||||
|
||||
=over 9
|
||||
|
||||
=item *
|
||||
|
||||
Your fair dealing or fair use rights, or other applicable
|
||||
copyright exceptions and limitations;
|
||||
|
||||
=item *
|
||||
|
||||
The author's moral rights;
|
||||
|
||||
=item *
|
||||
|
||||
Rights other persons may have either in the work itself or in
|
||||
how the work is used, such as publicity or privacy rights.
|
||||
|
||||
=back
|
||||
|
||||
=item B<Notice>
|
||||
|
||||
For any reuse or distribution, you must make clear to others the
|
||||
license terms of this work.
|
||||
|
||||
=back
|
||||
|
||||
A copy of the full license is included in the file as cc-by-sa.txt.
|
||||
|
||||
=head1 DEPENDENCIES
|
||||
|
||||
GNU B<sql> uses Perl. If B<mysql> is installed, MySQL dburls will
|
||||
work. If B<psql> is installed, PostgreSQL dburls will work. If
|
||||
B<sqlplus> is installed, Oracle dburls will work. If B<rlwrap> is
|
||||
installed, GNU B<sql> will have a command history for Oracle.
|
||||
|
||||
|
||||
=head1 FILES
|
||||
|
||||
~/.dburl.aliases - user's own aliases with DBURLs
|
||||
|
||||
dburl.aliases - user's own aliases with DBURLs
|
||||
|
||||
dburl.aliases.dist - common aliases with DBURLs
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
B<mysql>(1), B<psql>(1), B<sqlplus>(1), B<rlwrap>(1)
|
||||
|
||||
=cut
|
||||
|
||||
use Getopt::Long;
|
||||
use strict;
|
||||
Getopt::Long::Configure ("bundling","require_order");
|
||||
GetOptions("passthrough|p=s@" => \$::opt_p,
|
||||
"sep|s=s" => \$::opt_s,
|
||||
"html" => \$::opt_html,
|
||||
"show-processlist|proclist|listproc" => \$::opt_processlist,
|
||||
"db-size|dbsize" => \$::opt_dbsize,
|
||||
"table-size|tablesize" => \$::opt_tablesize,
|
||||
"noheaders|no-headers|n" => \$::opt_n,
|
||||
"r" => \$::opt_retry,
|
||||
"retries=s" => \$::opt_retries,
|
||||
"debug" => \$::opt_debug);
|
||||
|
||||
my $pass_through_options = (defined $::opt_p) ? join(" ",@{$::opt_p}) : "";
|
||||
|
||||
my %dburl = parse_dburl(get_alias(shift));
|
||||
|
||||
my $interactive_command;
|
||||
my $batch_command;
|
||||
|
||||
my $database_driver = database_driver_alias($dburl{'databasedriver'});
|
||||
if($database_driver eq "mysql" or
|
||||
$database_driver eq "mysqlssl") {
|
||||
($batch_command,$interactive_command) = mysql_commands($database_driver,%dburl);
|
||||
} elsif($database_driver eq "postgresql" or
|
||||
$database_driver eq "postgresqlssl") {
|
||||
($batch_command,$interactive_command) = postgresql_commands($database_driver,%dburl);
|
||||
} elsif($database_driver eq "oracle") {
|
||||
($batch_command,$interactive_command) = oracle_commands($database_driver,%dburl);
|
||||
}
|
||||
|
||||
my $err;
|
||||
my $retries;
|
||||
$retries ||= defined $::opt_retries ? $::opt_retries : undef;
|
||||
$retries ||= defined $::opt_retry ? $::opt_retry * 3 : undef;
|
||||
$retries ||= 1;
|
||||
|
||||
if(defined $::opt_processlist) {
|
||||
unshift @ARGV, processlist($database_driver,%dburl);
|
||||
}
|
||||
|
||||
if(defined $::opt_dbsize) {
|
||||
unshift @ARGV, dbsize($database_driver,%dburl);
|
||||
}
|
||||
|
||||
if(defined $::opt_tablesize) {
|
||||
unshift @ARGV, tablesize($database_driver,%dburl);
|
||||
}
|
||||
|
||||
do {
|
||||
if(@ARGV) {
|
||||
$::opt_debug and print "$batch_command\n";
|
||||
open(M,"|$batch_command") || die("mysql/psql/sqlplus not in path");
|
||||
print M "@ARGV";
|
||||
close M;
|
||||
} elsif (is_stdin_terminal()) {
|
||||
$::opt_debug and print "$interactive_command\n";
|
||||
system("$interactive_command");
|
||||
} else {
|
||||
$::opt_debug and print "$batch_command\n";
|
||||
system("$batch_command");
|
||||
}
|
||||
$err = $?>>8;
|
||||
} while (--$retries and $err);
|
||||
|
||||
$Global::Initfile && unlink $Global::Initfile;
|
||||
exit ($err);
|
||||
|
||||
sub database_driver_alias {
|
||||
my $driver = shift;
|
||||
my %database_driver_alias = ("mysql" => "mysql",
|
||||
"mysqls" => "mysqlssl",
|
||||
"mysqlssl" => "mysqlssl",
|
||||
"oracle" => "oracle",
|
||||
"ora" => "oracle",
|
||||
"oracles" => "oraclessl",
|
||||
"oras" => "oraclessl",
|
||||
"oraclessl" => "oraclessl",
|
||||
"orassl" => "oraclessl",
|
||||
"postgresql" => "postgresql",
|
||||
"pgsql" => "postgresql",
|
||||
"postgres" => "postgresql",
|
||||
"pg" => "postgresql",
|
||||
"postgresqlssl" => "postgresqlssl",
|
||||
"pgsqlssl" => "postgresqlssl",
|
||||
"postgresssl" => "postgresqlssl",
|
||||
"pgssl" => "postgresqlssl",
|
||||
"postgresqls" => "postgresqlssl",
|
||||
"pgsqls" => "postgresqlssl",
|
||||
"postgress" => "postgresqlssl",
|
||||
"pgs" => "postgresqlssl");
|
||||
return $database_driver_alias{$driver};
|
||||
}
|
||||
|
||||
sub mysql_commands {
|
||||
my ($database_driver,%opt) = (@_);
|
||||
find_command_in_path("mysql") || die ("mysql not in path");
|
||||
if(defined($::opt_s)) { die "Field separator not implemented for mysql" }
|
||||
my $password = defined($opt{'password'}) ? "--password=".$opt{'password'} : "";
|
||||
my $host = defined($opt{'host'}) ? "--host=".$opt{'host'} : "";
|
||||
my $port = defined($opt{'port'}) ? "--port=".$opt{'port'} : "";
|
||||
my $user = defined($opt{'user'}) ? "--user=".$opt{'user'} : "";
|
||||
my $database = defined($opt{'database'}) ? $opt{'database'} : "";
|
||||
my $html = defined($::opt_html) ? "--html" : "";
|
||||
my $no_headers = defined($::opt_n) ? "--skip-column-names" : "";
|
||||
my $ssl = "";
|
||||
if ($database_driver eq "mysqlssl") {
|
||||
$ssl="--ssl";
|
||||
}
|
||||
# -C: Compression if both ends support it
|
||||
$batch_command =
|
||||
"mysql -C $pass_through_options $no_headers $html $ssl $host $user $port $password $database";
|
||||
$interactive_command = $batch_command;
|
||||
return($batch_command,$interactive_command);
|
||||
}
|
||||
|
||||
sub postgresql_commands {
|
||||
my ($database_driver,%opt) = (@_);
|
||||
find_command_in_path("psql") || die ("psql not in path");
|
||||
my $sep = ($::opt_s) ? "-A --field-separator '$::opt_s'" : "";
|
||||
my $password = defined($opt{'password'}) ? "PGPASSWORD=".$opt{'password'} : "";
|
||||
my $host = defined($opt{'host'}) ? "-h ".$opt{'host'} : "";
|
||||
my $port = defined($opt{'port'}) ? "-p ".$opt{'port'} : "";
|
||||
my $user = defined($opt{'user'}) ? "-U ".$opt{'user'} : "";
|
||||
my $database = defined($opt{'database'}) ? "-d ".$opt{'database'} : "";
|
||||
my $html = defined($::opt_html) ? "--html" : "";
|
||||
my $no_headers = defined($::opt_n) ? "--tuples-only" : "";
|
||||
my $ssl = "";
|
||||
if ($database_driver eq "postgresqlssl") {
|
||||
$ssl="PGSSLMODE=require";
|
||||
}
|
||||
$batch_command =
|
||||
"$ssl $password psql $pass_through_options $sep $no_headers $html $host $user $port $database";
|
||||
$interactive_command = $batch_command;
|
||||
|
||||
return($batch_command,$interactive_command);
|
||||
}
|
||||
|
||||
sub oracle_commands {
|
||||
my ($database_driver,%opt) = (@_);
|
||||
# oracle://user:pass@grum:1521/XE becomes:
|
||||
# sqlplus 'user/pass@(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = grum)(PORT = 1521)) (CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = XE) ))'
|
||||
find_command_in_path("sqlplus") || die ("sqlplus not in path");
|
||||
|
||||
# Readline support: if rlwrap installed run rlwrap sqlplus
|
||||
my $rlwrap = find_command_in_path("rlwrap");
|
||||
|
||||
# Set good defaults in the inifile
|
||||
$Global::Initfile = "/tmp/$$.sql.init";
|
||||
open(INIT,">".$Global::Initfile) || die;
|
||||
print INIT "SET LINESIZE 32767\n";
|
||||
$::opt_debug and print "SET LINESIZE 32767\n";
|
||||
print INIT "SET WRAP OFF\n";
|
||||
$::opt_debug and print "SET WRAP OFF\n";
|
||||
if(defined($::opt_html)) {
|
||||
print INIT "SET MARK HTML ON\n";
|
||||
$::opt_debug and print "SET MARK HTML ON\n";
|
||||
}
|
||||
if(defined($::opt_n)) {
|
||||
print INIT "SET PAGES 0\n";
|
||||
$::opt_debug and print "SET PAGES 0\n";
|
||||
} else {
|
||||
print INIT "SET PAGES 50000\n";
|
||||
$::opt_debug and print "SET PAGES 50000\n";
|
||||
}
|
||||
if(defined($::opt_s)) {
|
||||
print INIT "SET COLSEP $::opt_s\n";
|
||||
$::opt_debug and print "SET COLSEP $::opt_s\n";
|
||||
}
|
||||
close INIT;
|
||||
|
||||
my $password = defined($opt{'password'}) ? "/".$opt{'password'} : "";
|
||||
my $host = defined($opt{'host'}) ? $opt{'host'} : "localhost";
|
||||
my $port = defined($opt{'port'}) ? $opt{'port'} : "1521";
|
||||
my $user = defined($opt{'user'}) ? $opt{'user'} : "";
|
||||
# Database is called service in Oracle lingo
|
||||
my $service = defined($opt{'database'}) ? "(SERVICE_NAME = ".$opt{'database'}.")" : "";
|
||||
my $tns = "(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = $host)(PORT = $port)) ".
|
||||
"(CONNECT_DATA =(SERVER = DEDICATED)$service ))";
|
||||
my $ssl = "";
|
||||
# -L: Do not re-ask for password if it is wrong
|
||||
my $common_options = "-L $pass_through_options '$user$password\@$tns' \@$Global::Initfile";
|
||||
my $batch_command =
|
||||
"sqlplus -S ".$common_options;
|
||||
my $interactive_command =
|
||||
"$rlwrap sqlplus ".$common_options;
|
||||
return($batch_command,$interactive_command);
|
||||
}
|
||||
|
||||
|
||||
# Return the code for 'show processlist' in the chosen database dialect
|
||||
sub processlist {
|
||||
my $dbdriver = shift;
|
||||
my %dburl = @_;
|
||||
my %processlist =
|
||||
("mysql" => "show processlist;",
|
||||
"postgresql" => ("SELECT ".
|
||||
" datname AS database,".
|
||||
" usename AS username,".
|
||||
" now()-xact_start AS runtime,".
|
||||
" current_query ".
|
||||
"FROM pg_stat_activity ".
|
||||
"ORDER BY runtime DESC;"),
|
||||
"oracle" => ("SELECT ".
|
||||
' CPU_TIME/100000, SYS.V_$SQL.SQL_TEXT, USERNAME '.
|
||||
"FROM ".
|
||||
' SYS.V_$SQL, SYS.V_$SESSION '.
|
||||
"WHERE ".
|
||||
' SYS.V_$SQL.SQL_ID = SYS.V_$SESSION.SQL_ID(+) '.
|
||||
"AND username IS NOT NULL ".
|
||||
"ORDER BY CPU_TIME DESC;"),
|
||||
);
|
||||
if($processlist{$dbdriver}) {
|
||||
return $processlist{$dbdriver};
|
||||
} else {
|
||||
print STDERR "processlist is not implemented for $dbdriver\n";
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
|
||||
# Return the code for 'show database size' in the chosen database dialect
|
||||
sub dbsize {
|
||||
my $dbdriver = shift;
|
||||
my %dburl = @_;
|
||||
my %processlist =
|
||||
("mysql" => (
|
||||
'SELECT '.
|
||||
' table_schema "Data Base Name", '.
|
||||
' SUM(data_length+index_length)/1024/1024 "Data Base Size in MB" '.
|
||||
'FROM information_schema.TABLES '.
|
||||
'GROUP BY table_schema;'),
|
||||
"postgresql" => (
|
||||
"SELECT ".
|
||||
" pg_database_size('".$dburl{'database'}."') AS bytes,".
|
||||
" pg_size_pretty(pg_database_size('".$dburl{'database'}."')) AS human_readable;"),
|
||||
);
|
||||
if($processlist{$dbdriver}) {
|
||||
return $processlist{$dbdriver};
|
||||
} else {
|
||||
print STDERR "dbsize is not implemented for $dbdriver\n";
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Return the code for 'show database size' in the chosen database dialect
|
||||
sub tablesize {
|
||||
my $dbdriver = shift;
|
||||
my $database = shift;
|
||||
my %processlist =
|
||||
("postgresql" => (
|
||||
"SELECT relname, relpages*8 AS kb, reltuples::int AS \"live+dead rows\" ".
|
||||
"FROM pg_class c ".
|
||||
"ORDER BY relpages DESC;"),
|
||||
"mysql" => (
|
||||
"select table_name, TABLE_ROWS, DATA_LENGTH,INDEX_LENGTH from INFORMATION_SCHEMA.tables;"),
|
||||
);
|
||||
if($processlist{$dbdriver}) {
|
||||
return $processlist{$dbdriver};
|
||||
} else {
|
||||
print STDERR "dbsize is not implemented for $dbdriver\n";
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub is_stdin_terminal {
|
||||
return (-t STDIN);
|
||||
}
|
||||
|
||||
sub find_command_in_path {
|
||||
# Find the command if it exists in the current path
|
||||
my $command = shift;
|
||||
my $path = `which $command`;
|
||||
chomp $path;
|
||||
return $path;
|
||||
}
|
||||
|
||||
sub Usage {
|
||||
if(@_) {
|
||||
print "Error:\n";
|
||||
print map{ "$_\n" } @_;
|
||||
print "\n";
|
||||
}
|
||||
print `cat $0 | pod2man | man -l -`;
|
||||
}
|
||||
|
||||
sub get_alias {
|
||||
my $alias = shift;
|
||||
if ($alias !~ /^:/) {
|
||||
return $alias;
|
||||
}
|
||||
# Find the alias
|
||||
my $path;
|
||||
if (-l $0) {
|
||||
($path) = readlink($0) =~ m|^(.*)/|;
|
||||
} else {
|
||||
($path) = $0 =~ m|^(.*)/|;
|
||||
}
|
||||
my @urlalias=();
|
||||
check_permissions("$ENV{HOME}/.dburl.aliases");
|
||||
my @search=("$ENV{HOME}/.dburl.aliases", "$path/dburl.aliases",
|
||||
"$path/dburl.aliases.dist");
|
||||
for my $alias_file (@search) {
|
||||
if(-r $alias_file) {
|
||||
push @urlalias, `cat "$alias_file"`;
|
||||
}
|
||||
}
|
||||
my ($alias_part,$rest) = $alias=~/(:\w+)(.*)/;
|
||||
my $dburl;
|
||||
for (@urlalias) {
|
||||
/^$alias_part\s+(\S+)/ and do { $dburl = $1; last; }
|
||||
}
|
||||
|
||||
if($dburl) {
|
||||
return get_alias($dburl.$rest);
|
||||
} else {
|
||||
Usage("$alias is not defined in @search");
|
||||
}
|
||||
}
|
||||
|
||||
sub check_permissions {
|
||||
my $file = shift;
|
||||
|
||||
if(-e $file) {
|
||||
if(not -o $file) {
|
||||
my $username = (getpwuid($<))[0];
|
||||
print STDERR "$file should be owned by $username: chown $username $file\n";
|
||||
}
|
||||
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
|
||||
$atime,$mtime,$ctime,$blksize,$blocks) = stat($file);
|
||||
if($mode & 077) {
|
||||
my $username = (getpwuid($<))[0];
|
||||
print STDERR "$file should be only be readable by $username: chmod 600 $file\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub parse_dburl {
|
||||
my $url = shift;
|
||||
my %options = ();
|
||||
# mysql://[user[:password]@][host][:port]/[database[/jobnr]]
|
||||
|
||||
if($url=~m!((?:oracle|ora|mysql|pg|postgres|postgresql)(?:s|ssl|)):// # Databasedriver ($1)
|
||||
(?:
|
||||
([^:@]*) # Username ($2)
|
||||
(?:
|
||||
:([^@]*) # Password ($3)
|
||||
)?
|
||||
@)?
|
||||
([^:/]*)? # Hostname ($4)
|
||||
(?:
|
||||
:
|
||||
([^/]*)? # Port ($5)
|
||||
)?
|
||||
(?:
|
||||
/+
|
||||
([^/]*)? # Database ($6)
|
||||
(?:
|
||||
/+
|
||||
([^/]*)? # Job ($7)
|
||||
)?
|
||||
)?
|
||||
!x) {
|
||||
$options{databasedriver} = undef_if_empty($1);
|
||||
$options{user} = undef_if_empty($2);
|
||||
$options{password} = undef_if_empty($3);
|
||||
$options{host} = undef_if_empty($4);
|
||||
$options{port} = undef_if_empty($5);
|
||||
$options{database} = undef_if_empty($6);
|
||||
$options{job} = undef_if_empty($7);
|
||||
} else {
|
||||
Usage("$url is not a valid DB-URL");
|
||||
exit -1;
|
||||
}
|
||||
return %options;
|
||||
}
|
||||
|
||||
sub undef_if_empty {
|
||||
if(defined($_[0]) and $_[0] eq "") {
|
||||
return undef;
|
||||
}
|
||||
return $_[0];
|
||||
}
|
||||
|
||||
# TODO --list-databases: psql -l eller '\l'. mysql show databases. Oracle ?
|
Loading…
Reference in a new issue