diff --git a/autom4te.cache/requests b/autom4te.cache/requests
index 0cc71478..8e58b38e 100644
--- a/autom4te.cache/requests
+++ b/autom4te.cache/requests
@@ -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,
diff --git a/doc/FUTURE_IDEAS b/doc/FUTURE_IDEAS
index 6f2aca0c..ccb1fd2a 100644
--- a/doc/FUTURE_IDEAS
+++ b/doc/FUTURE_IDEAS
@@ -1,13 +1,9 @@
-Bugfix: --eta/--progress with 0 jobs gave division by zero.
-Bugfix in Makefile by Piotr Jaroszyński
-
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}
diff --git a/doc/release_new_version b/doc/release_new_version
index 9ac34da6..d31b510a 100644
--- a/doc/release_new_version
+++ b/doc/release_new_version
@@ -89,7 +89,7 @@ to:parallel@gnu.org, bug-parallel@gnu.org, info-gnu@gnu.org, bug-directory@gnu.o
cc:Peter Simons , Sandro Cazzaniga ,
Tim Cuthbertson , Ludovic Courtès ,
Markus Ammer , Pavel Nuzhdin ,
- Phil Sung
+ Phil Sung , Michael Shigorin
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
+
+* Alt Linux package of GNU Parallel. Thanks to Michael Shigorin
= About GNU Parallel =
diff --git a/src/Makefile.am b/src/Makefile.am
index 900d7850..8b3c23e8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -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
diff --git a/src/Makefile.in b/src/Makefile.in
index e1d6f61a..07a0a824 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -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
diff --git a/src/sql b/src/sql
new file mode 100755
index 00000000..838f6b7c
--- /dev/null
+++ b/src/sql
@@ -0,0 +1,697 @@
+#!/usr/bin/perl -w
+
+=head1 NAME
+
+sql - execute a command on a database determined by a dburl
+
+=head1 SYNOPSIS
+
+B [B<-hnr>] [B<--table-size>] [B<--db-size>] [B<-p> I] [B<-s> I] I [I]
+
+
+=head1 DESCRIPTION
+
+GNU B 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 is left out you
+will get that database's interactive shell.
+
+GNU B is often used in combination with GNU B.
+
+=over 9
+
+=item I
+
+A DBURL has the following syntax:
+vendor://[user[:password]@][host][:port]/[database]
+
+See the section DBURL below.
+
+=item I
+
+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 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
+
+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
+
+Try I times. If the client program returns with an error,
+retry the command. Default is I<--retries 1>.
+
+
+=item B<--sep> I
+
+=item B<-s> I
+
+Field separator. Use I 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 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 is part of GNU B. Report bugs to .
+
+
+=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 .
+
+=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 copy, distribute and transmit the work
+
+=item B
+
+to adapt the work
+
+=back
+
+Under the following conditions:
+
+=over 9
+
+=item B
+
+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
+
+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
+
+Any of the above conditions can be waived if you get permission from
+the copyright holder.
+
+=item B
+
+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
+
+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
+
+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 uses Perl. If B is installed, MySQL dburls will
+work. If B is installed, PostgreSQL dburls will work. If
+B is installed, Oracle dburls will work. If B is
+installed, GNU B 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(1), B(1), B(1), B(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 ?