package DBIx::dbMan::Extension::Connections;
use strict;
use base 'DBIx::dbMan::Extension';
use Text::FormatTable;
use Term::ReadLine;
BEGIN { import Term::ReadLine::Gnu qw/:prompt/; }
use Term::ANSIColor;
use DBI;
our $VERSION = '0.14';
1;
sub IDENTIFICATION { return "000001-000005-000014"; }
sub preference { return 0; }
sub known_actions { return [ qw/CONNECTION/ ]; }
sub menu {
my $obj = shift;
my @menu_use = ();
my @menu_close = ();
my @menu_reopen = ();
my @menu_open = ();
my @menu_drop = ();
for (@{$obj->{-dbi}->list('active')}) {
my $sel = ' ';
$sel = '*' if $_->{name} eq $obj->{-dbi}->current;
push @menu_use,{ label => $sel.' '.$_->{name},
action => { action => 'CONNECTION', operation => 'use',
what => $_->{name} } };
push @menu_close,{ label => $_->{name},
action => { action => 'CONNECTION', operation => 'close',
what => $_->{name} } };
push @menu_reopen,{ label => $_->{name},
action => { action => 'CONNECTION', operation => 'reopen',
what => $_->{name} } };
}
for (@{$obj->{-dbi}->list('inactive')}) {
push @menu_open,{ label => $_->{name},
action => { action => 'CONNECTION', operation => 'open',
what => $_->{name} } };
}
for (@{$obj->{-dbi}->list()}) {
push @menu_drop,{ label => $_->{name}, submenu => [
{ label => 'Temporarly', action => { action => 'CONNECTION',
operation => 'drop', what => $_->{name} } },
{ label => 'Permanently', action => { action => 'CONNECTION',
operation => 'drop', what => $_->{name}, permanent => 1 } }
] };
}
return ( { label => '_Connection', submenu => [
{ label => 'Select current', preference => 100, submenu => \@menu_use },
{ label => 'Close', preference => 1, submenu => \@menu_close },
{ label => 'Reopen', preference => 2, submenu => \@menu_reopen },
{ label => 'Open', preference => 3, submenu => \@menu_open },
{ label => 'Drop', preference => -10, submenu => \@menu_drop },
{ label => 'Show list', preference => 50, submenu => [
{ label => 'All', preference => 5,
action => { action => 'CONNECTION', operation => 'show' } },
{ separator => 1, preference => 2 },
{ label => 'Active',
action => { action => 'CONNECTION', operation => 'show',
what => 'active' } },
{ label => 'Inactive',
action => { action => 'CONNECTION', operation => 'show',
what => 'inactive' } }
] },
{ separator => 1, preference => 25 },
{ separator => 1, preference => -1 }
] } );
}
sub init {
my $obj = shift;
$obj->{prompt_num} = $obj->{-interface}->register_prompt;
}
sub done {
my $obj = shift;
$obj->{-interface}->deregister_prompt($obj->{-prompt_num});
}
sub solve_open_error {
my ($obj,$error,$name) = @_;
if ($error == -1) {
return "Can't find driver for ".$obj->{connections}->{$name}->{driver}.".\n";
} elsif ($error == -2) {
return "Can't connect to $name (reason: ".DBI->errstr.").\n";
} elsif ($error == -3) {
return "Unknown connection $name.\n";
} elsif ($error == -4) {
return "Already connected to $name.\n";
} elsif (not $error) {
return "Connection to $name established.\n";
}
}
sub solve_close_error {
my ($obj,$error,$name) = @_;
if ($error == -1) {
return "Unknown connection $name.\n";
} elsif ($error == -2) {
return "Not connected to $name.\n";
} elsif (not $error) {
return "Disconnected from $name.\n";
}
}
sub solve_use_error {
my ($obj,$error,$name) = @_;
if ($error == 1) {
return "Unset current connection.\n";
} elsif ($error == -1) {
return "Unknown connection $name.\n";
} elsif ($error == -2) {
return "Not connected to $name.\n";
} elsif (not $error) {
return "Set current connection to $name.\n";
}
}
sub handle_action {
my ($obj,%action) = @_;
if ($action{action} eq 'CONNECTION') {
if ($action{operation} eq 'open') {
my $error = $obj->{-dbi}->open($action{what});
$action{action} = 'OUTPUT';
$action{output} = $obj->solve_open_error($error,$action{what});
$obj->{-interface}->rebuild_menu;
} elsif ($action{operation} eq 'reopen') {
my $reuse = 0;
$reuse = 1 if $obj->{-dbi}->current eq $action{what};
my $was = $obj->{-dbi}->current();
$obj->{-dbi}->set_current($action{what});
my $trans_msg = '';
if ($obj->{-dbi}->in_transaction()) {
$obj->{-dbi}->rollback;
$obj->{-dbi}->trans_end;
$trans_msg = "Transaction end with implicit rollback in connection $action{what}.\n";
}
$action{action} = 'OUTPUT';
my $error = $obj->{-dbi}->close($action{what});
$action{output} = $trans_msg . $obj->solve_close_error($error,$action{what});
$error = $obj->{-dbi}->open($action{what});
$action{output} .= $obj->solve_open_error($error,$action{what});
$error = $obj->{-dbi}->set_current($was);
if ($reuse) {
$action{output} .= $obj->solve_use_error($error,$action{what});
}
$obj->{-interface}->add_to_actionlist({ action => 'NOTIFY', notify => 'connection_change' });
$obj->{-interface}->rebuild_menu;
} elsif ($action{operation} eq 'close') {
my $trans_msg = '';
my $was = $obj->{-dbi}->current();
$obj->{-dbi}->set_current($action{what});
if ($obj->{-dbi}->in_transaction()) {
$obj->{-dbi}->rollback;
$obj->{-dbi}->trans_end;
$trans_msg = "Transaction end with implicit rollback in connection $action{what}.\n";
}
$action{action} = 'OUTPUT';
my $error = $obj->{-dbi}->close($action{what});
$action{output} = $trans_msg . $obj->solve_close_error($error,$action{what});
$obj->{-dbi}->set_current($was);
$obj->{-interface}->rebuild_menu;
$obj->{-interface}->add_to_actionlist({ action => 'NOTIFY', notify => 'connection_change' });
$obj->{-interface}->add_to_actionlist({ action => 'TRANSACTION', operation => 'change' });
} elsif ($action{operation} eq 'use') {
$action{action} = 'OUTPUT';
my $error = $obj->{-dbi}->set_current($action{what});
$action{output} = $obj->solve_use_error($error,$action{what});
$obj->{-interface}->rebuild_menu;
$obj->{-interface}->add_to_actionlist({ action => 'TRANSACTION', operation => 'change' });
$obj->{-interface}->add_to_actionlist({ action => 'NOTIFY', notify => 'connection_change' });
} elsif ($action{operation} eq 'show') {
my @list = @{$obj->{-dbi}->list($action{what})};
my $clist = '';
if (@list) {
$clist .= ($action{what} eq 'active'?'Active c':'C')."onnections:\n";
my $table = new Text::FormatTable '| l l | l | l | l | l | l | l |';
$table->rule;
$table->head('C','NAME','ACTIVE','PERMANENT','DRIVER','LOGIN','DSN','CONFIG');
$table->rule;
for (@list) {
$table->row((($obj->{-dbi}->current eq $_->{name})?'*':' '),$_->{name},($_->{-logged}?'yes':'no'),($obj->{-dbi}->is_permanent_connection($_->{name})?'yes':'no'),$_->{driver},$_->{login},$_->{dsn},$_->{config} || '');
}
$table->rule;
$clist .= $table->render($obj->{-interface}->render_size);
} else {
$action{what} = '' if $action{what} ne 'active';
$clist .= "No".($action{what}?' '.$action{what}:'')." connection.\n";
}
$action{action} = 'OUTPUT';
$action{output} = $clist;
} elsif ($action{operation} eq 'create') {
my %parm = ();
for (qw/driver dsn login password auto_login config prompt_color/) { $parm{$_} = $action{$_} || ''; }
$action{action} = 'NONE';
my $error = $obj->{-dbi}->create_connection($action{what},\%parm);
if ($error == -1) {
$action{action} = 'OUTPUT';
$action{output} = "Connection with name $action{what} already exists.\n";
} elsif ($error >= 0) {
$action{action} = 'OUTPUT';
$action{output} = "Connection $action{what} created.\n";
if ($error > 50) {
$action{output} .= $obj->solve_open_error($error-100,$action{what}) if $error > 50;
}
if ($action{permanent}) {
$error = $obj->{-dbi}->save_connection($action{what});
if ($error == -1) {
$action{output} .= "Connection with name $action{what} not exists.\n";
} elsif (not $error) {
$action{output} .= "Making connection $action{what} permanent.\n";
}
}
$obj->{-interface}->rebuild_menu;
}
} elsif ($action{operation} eq 'drop') {
$action{action} = 'NONE';
my $error = $obj->{-dbi}->drop_connection($action{what});
if ($error == -1) {
$action{action} = 'OUTPUT';
$action{output} = "Connection with name $action{what} not exists.\n";
} elsif (not $error) {
$action{action} = 'OUTPUT';
$action{output} = "Connection $action{what} dropped.\n";
if ($action{permanent}) {
$error = $obj->{-dbi}->destroy_connection($action{what});
if ($error == -2) {
$action{output} .= "Can't destroy connection $action{what}.\n";
} elsif (not $error) {
$action{output} .= "Destroying permanent connection $action{what}.\n";
}
}
$obj->{-interface}->rebuild_menu;
}
}
my $db = '';
if ( $obj->{-dbi}->current ) {
$db .= RL_PROMPT_START_IGNORE . color( $obj->{-dbi}->prompt_color ) . RL_PROMPT_END_IGNORE if $obj->{-dbi}->prompt_color;
$db .= '<'.$obj->{-dbi}->current.'>';
$db .= RL_PROMPT_START_IGNORE . color( 'reset' ) . RL_PROMPT_END_IGNORE if $obj->{-dbi}->prompt_color;
}
$obj->{-interface}->prompt($obj->{prompt_num},$db);
}
$action{processed} = 1;
return %action;
}