sql: --list-tables implemented. %-encode all elements of DBURL.

Passes sql-part of unittest.
This commit is contained in:
Ole Tange 2010-09-15 00:24:08 +02:00
parent 28f9796b4e
commit 8703e6b5c5
2 changed files with 64 additions and 101 deletions

90
src/sql
View file

@ -7,7 +7,10 @@ sql - execute a command on a database determined by a dburl
=head1 SYNOPSIS =head1 SYNOPSIS
B<sql> [B<-hnr>] [B<--table-size>] [B<--db-size>] [B<-p> B<sql> [B<-hnr>] [B<--table-size>] [B<--db-size>] [B<-p>
I<pass-through>] [B<-s> I<string>] I<dburl> [I<sqlcommand>] I<pass-through>] [B<-s> I<string>] I<dburl> [I<commands>]
B<sql> [B<-hnr>] [B<--table-size>] [B<--db-size>] [B<-p>
I<pass-through>] [B<-s> I<string>] I<dburl> < commandfile
B<#!/usr/bin/sql> B<--shebang> [options] I<dburl> B<#!/usr/bin/sql> B<--shebang> [options] I<dburl>
@ -19,8 +22,8 @@ clients. So far the focus has been on giving a common way to specify
login information (protocol, username, password, hostname, and port login information (protocol, username, password, hostname, and port
number), size (database and table size), and running queries. number), size (database and table size), and running queries.
The database is addressed using a dburl. If I<command> is left out you The database is addressed using a DBURL. If I<commands> are left out
will get that database's interactive shell. you will get that database's interactive shell.
GNU B<sql> is often used in combination with GNU B<parallel>. GNU B<sql> is often used in combination with GNU B<parallel>.
@ -29,22 +32,19 @@ GNU B<sql> is often used in combination with GNU B<parallel>.
=item I<dburl> =item I<dburl>
A DBURL has the following syntax: A DBURL has the following syntax:
vendor://[[user][:password]@][host][:port]/[database] [sql:]vendor://[[user][:password]@][host][:port]/[database][?sqlquery]
See the section DBURL below. See the section DBURL below.
=item I<command> =item I<commands>
The SQL command to run. The SQL commands to run. Each argument will have a newline appended.
Example: select 1+2 Example: "SELECT 1+2;" "SELECT 'SQL';"
If you use * or ? remember to quote them, as the shell may otherwise If no commands are given SQL is read from the keyboard or STDIN.
expand them.
If no command is given SQL is read from the keyboard or STDIN. Example: echo 'SELECT 1+2;' | sql mysql:///
Example: echo 'select 1+2' | sql mysql:///
=item B<--db-size> =item B<--db-size>
@ -75,6 +75,15 @@ HTML output. Turn on HTML tabular output.
Show the list of running queries. Show the list of running queries.
=item B<--show-tables>
=item B<--list-tables>
=item B<--table-list>
List the tables in the database
=item B<--noheaders> =item B<--noheaders>
=item B<--no-headers> =item B<--no-headers>
@ -151,6 +160,10 @@ For this to work B<--shebang> or B<-Y> must be set as the first option.
A DBURL has the following syntax: A DBURL has the following syntax:
[sql:]vendor://[user[:password]@][host][:port]/[database][?sqlquery] [sql:]vendor://[user[:password]@][host][:port]/[database][?sqlquery]
To quote special characters use %-encoding specified in
http://tools.ietf.org/html/rfc3986#section-2.1 (E.g. a password
containing '/' would contain '%2F').
Examples: Examples:
mysql://user:pa55w0rd@mysqlserver/database mysql://user:pa55w0rd@mysqlserver/database
sql:oracle://scott:tiger@oracleserver/xe sql:oracle://scott:tiger@oracleserver/xe
@ -394,6 +407,10 @@ if(defined $::opt_processlist) {
unshift @ARGV, processlist($database_driver,%dburl); unshift @ARGV, processlist($database_driver,%dburl);
} }
if(defined $::opt_tablelist) {
unshift @ARGV, tablelist($database_driver,%dburl);
}
if(defined $::opt_dbsize) { if(defined $::opt_dbsize) {
unshift @ARGV, dbsize($database_driver,%dburl); unshift @ARGV, dbsize($database_driver,%dburl);
} }
@ -453,6 +470,8 @@ sub parse_options {
"sep|s=s" => \$::opt_s, "sep|s=s" => \$::opt_s,
"html" => \$::opt_html, "html" => \$::opt_html,
"show-processlist|proclist|listproc" => \$::opt_processlist, "show-processlist|proclist|listproc" => \$::opt_processlist,
"show-tables|showtables|listtables|list-tables|tablelist|table-list"
=> \$::opt_tablelist,
"db-size|dbsize" => \$::opt_dbsize, "db-size|dbsize" => \$::opt_dbsize,
"table-size|tablesize" => \$::opt_tablesize, "table-size|tablesize" => \$::opt_tablesize,
"noheaders|no-headers|n" => \$::opt_n, "noheaders|no-headers|n" => \$::opt_n,
@ -621,7 +640,7 @@ sub sqlite_commands {
sub processlist { sub processlist {
my $dbdriver = shift; my $dbdriver = shift;
my %dburl = @_; my %dburl = @_;
my %processlist = my %statement =
("mysql" => "show processlist;", ("mysql" => "show processlist;",
"postgresql" => ("SELECT ". "postgresql" => ("SELECT ".
" datname AS database,". " datname AS database,".
@ -639,19 +658,36 @@ sub processlist {
"AND username IS NOT NULL ". "AND username IS NOT NULL ".
"ORDER BY CPU_TIME DESC;"), "ORDER BY CPU_TIME DESC;"),
); );
if($processlist{$dbdriver}) { if($statement{$dbdriver}) {
return $processlist{$dbdriver}; return $statement{$dbdriver};
} else { } else {
print STDERR "processlist is not implemented for $dbdriver\n"; print STDERR "processlist is not implemented for $dbdriver\n";
exit 1; exit 1;
} }
} }
# Return the code for 'show tables' in the chosen database dialect
sub tablelist {
my $dbdriver = shift;
my %dburl = @_;
my %statement =
("mysql" => "show tables;",
"postgresql" => '\dt',
"oracle" => ("SELECT object_name FROM user_objects WHERE object_type = 'TABLE';"),
);
if($statement{$dbdriver}) {
return $statement{$dbdriver};
} else {
print STDERR "tablelist is not implemented for $dbdriver\n";
exit 1;
}
}
# Return the code for 'show database size' in the chosen database dialect # Return the code for 'show database size' in the chosen database dialect
sub dbsize { sub dbsize {
my $dbdriver = shift; my $dbdriver = shift;
my %dburl = @_; my %dburl = @_;
my %processlist = my %statement =
("mysql" => ( ("mysql" => (
'SELECT '. 'SELECT '.
' table_schema "Data Base Name", '. ' table_schema "Data Base Name", '.
@ -667,8 +703,8 @@ sub dbsize {
"sqlite3" => ( "sqlite3" => (
"SELECT ".(undef_as_zero(-s $dburl{'database'}))." AS bytes;"), "SELECT ".(undef_as_zero(-s $dburl{'database'}))." AS bytes;"),
); );
if($processlist{$dbdriver}) { if($statement{$dbdriver}) {
return $processlist{$dbdriver}; return $statement{$dbdriver};
} else { } else {
print STDERR "dbsize is not implemented for $dbdriver\n"; print STDERR "dbsize is not implemented for $dbdriver\n";
exit 1; exit 1;
@ -680,7 +716,7 @@ sub dbsize {
sub tablesize { sub tablesize {
my $dbdriver = shift; my $dbdriver = shift;
my $database = shift; my $database = shift;
my %processlist = my %statement =
("postgresql" => ( ("postgresql" => (
"SELECT relname, relpages*8 AS kb, reltuples::int AS \"live+dead rows\" ". "SELECT relname, relpages*8 AS kb, reltuples::int AS \"live+dead rows\" ".
"FROM pg_class c ". "FROM pg_class c ".
@ -688,8 +724,8 @@ sub tablesize {
"mysql" => ( "mysql" => (
"select table_name, TABLE_ROWS, DATA_LENGTH,INDEX_LENGTH from INFORMATION_SCHEMA.tables;"), "select table_name, TABLE_ROWS, DATA_LENGTH,INDEX_LENGTH from INFORMATION_SCHEMA.tables;"),
); );
if($processlist{$dbdriver}) { if($statement{$dbdriver}) {
return $processlist{$dbdriver}; return $statement{$dbdriver};
} else { } else {
print STDERR "table size is not implemented for $dbdriver\n"; print STDERR "table size is not implemented for $dbdriver\n";
exit 1; exit 1;
@ -816,12 +852,12 @@ sub parse_dburl {
(.*)? # Query ($7) (.*)? # Query ($7)
)? )?
!x) { !x) {
$options{databasedriver} = undef_if_empty($1); $options{databasedriver} = undef_if_empty(uri_unescape($1));
$options{user} = undef_if_empty($2); $options{user} = undef_if_empty(uri_unescape($2));
$options{password} = undef_if_empty($3); $options{password} = undef_if_empty(uri_unescape($3));
$options{host} = undef_if_empty($4); $options{host} = undef_if_empty(uri_unescape($4));
$options{port} = undef_if_empty($5); $options{port} = undef_if_empty(uri_unescape($5));
$options{database} = undef_if_empty($6); $options{database} = undef_if_empty(uri_unescape($6));
$options{query} = undef_if_empty(uri_unescape($7)); $options{query} = undef_if_empty(uri_unescape($7));
debug("dburl $url\n"); debug("dburl $url\n");
debug("databasedriver ",$options{databasedriver}, " user ", $options{user}, debug("databasedriver ",$options{databasedriver}, " user ", $options{user},

View file

@ -1,73 +0,0 @@
### Test basic --arg-sep
a
b
### Run commands using --arg-sep
echo a
a
echo b
b
### Change --arg-sep
echo a
a
echo b
b
echo a
a
echo b
b
echo a
a
echo b
b
echo a
a
echo b
b
### Test stdin goes to first command only ("-" as argument)
cat -
via first cat
cat -
via pseudotty
### Test stdin goes to first command only ("cat" as argument)
echo a
a
cat
via pseudotty
### Test stdin goes to first command only
cat
via cat
echo b
b
cat
via cat
echo b
b
### Bug made 4 5 go before 1 2 3
1
2
3
4
5
### Bug made 3 go before 1 2
1
2
3
### Bug did not quote
echo \>
>
echo \>
>
echo \> 2
> 2
> 2
### Must not quote
echo | wc -l
1
echo | wc -l
1
echo a b c | wc -w
3
echo a b c | wc -w
3
echo a b | wc -w
2