view release on metacpan or search on metacpan
- Term::Choose minimum version is '1.739'.
- Code refactoring.
2.281 2021-08-29
- Adapt the code to the updated Term::Choose.
2.280 2021-08-24
- DBD::SQLite 1.68 or greater is required.
- print_table: table_name -> footer.
- Renamed the option 'f3' to 'search'.
- 'Ctrl-F' instead of 'F3' to open the search prompt.
- PageUP/PageDown: 'Ctrl-P'/'Ctrl-N' instead of 'Ctrl-B'/'Ctrl-F'.
2.279 2021-07-29
- Bugfix in functions Epoch_to_Date/Epoch_to_DateTime: use driver specific regex statement.
2.278 2021-07-29
- Removed the source type 'Copy&Paste'.
- Removed option 'Truncated rows'.
2.277 2021-07-28
bin/db-browser view on Meta::CPAN
squashed to a single white space.
Tab characters (C<\t>) are replaced with a space.
Vertical spaces (C<\v>) are squashed to two spaces.
Control characters, code points of the surrogate ranges and non-characters are removed.
See also the option group L</Output>.
C<Ctrl-F> opens a prompt. A regular expression is expected as input. This enables one to display only rows where at
least one column matches the entered pattern. See option L</Search>.
=head1 MENUS
=head2 Plugins Menu
Choosing a plugin leads to the I<Databases Menu>.
(If there is only one plugin, the plugins menu is not shown, but the plugin is chosen automatically.)
bin/db-browser view on Meta::CPAN
Choosing a schema leads to the I<Tables Menu>.
(If there is not more than one schema, the schemas menu is not shown, but the schema is chosen automatically.)
=head2 Tables Menu
The menu entries of the tables menu:
=head3 Prompt Line
Selecting the prompt line (the database name) opens a menu with these entries:
=over
=item
Create Table
=item
Drop Table
bin/db-browser view on Meta::CPAN
Enter a subquery and use it as a table.
The query can be created in different ways:
=over
=item SQL Menu
Build the query with the SQL Menu.
Before returning the subquery, the result of the subquery can be displayed by selecting the prompt line of the menu.
This does not work if the subquery is a correlated subquery.
=item Readline
Write the query in the prompt.
=item Stored Queries
If stored queries are available, it is possible to select one of those queries.
There are three different types of stored queries:
- permanently saved queries
- previously entered queries
- queries printed with I<Print TABLE>
Queries can be saved permanently by selecting the prompt line (I<Choose:>) in the I<Subquery> menu.
=back
=head3 CTE
Common table expression, available if enabled in L</Extensions>.
=over
=item New CTE
bin/db-browser view on Meta::CPAN
This entry is available if enabled in L</Extensions>.
=head2 SQL Menu
SQL statements are created in this menu.
The SQL Menu has the following menu entries:
=head3 Prompt Line
Selecting this prompt line (I<Customize:>) opens a menu with these entries:
=over
=item
Insert
=item
Update
bin/db-browser view on Meta::CPAN
=head4 OFFSET
=head3 Export
Export the result of the chosen SQL statement to a C<CSV>-file. See options L</Export Data>.
=head1 WRITE ACCESS
=head2 Create/Drop Table/View
I<Create/Drop Table/View> can be accessed by selecting the prompt-line in the L</Tables Menu> if the respective option
is activated.
Selecting the prompt line of the I<Create/Drop Table/View> submenu allows you to set the parse settings described in
L</Import Data>.
=head3 Create Table
If the option I<Source Type> is set to I<menu>, selecting I<Create Table> opens a submenu where you can choose the type
of the data source. If I<Source Type> is set to I<plain> or I<file>, the set data source type is automatically used
without displaying a menu. For more information, see L</Data Input>.
You will be asked:
=over
=item
for the table name
=item
if the first data row should be used as a header (Selecting the prompt line of this menu allows you to set the
L</Create-Table> options)
=item
if an auto increment column should be added (if the option is enabled in L</Create-Table>)
=item
to edit the column names
bin/db-browser view on Meta::CPAN
=head3 Create View
Before creating a view, print the required select statement to make it available in the subquery menu.
=head3 Drop View
Drop a view. The entire view is shown before the user confirms dropping it.
=head2 Insert/Update/Delete
I<Insert>, I<Update> and I<Delete> can be accessed by selecting the prompt-line in the L</SQL Menu> if the respective
option is activated.
I<Delete>, I<Update>, or I<Insert> may not be available with C<Join> and C<Union>/C<Intersect>/C<Except> statements.
=head3 Insert
If the option I<Source Type> is set to I<menu>, selecting I<Insert> opens a submenu where one can choose the type of
the data source. If I<Source Type> is set to I<plain> or I<file>, the set data source type is used without showing a
menu. For more information, see L</Data Input>.
bin/db-browser view on Meta::CPAN
installed automatically. It is up to the user to install the required parser modules.
Selecting I<file> opens the I<Source directory> submenu where one can choose the directory which should be
searched for files.
If the L</Directory History> is set to C<1>, the I<Source directory> submenu is skipped and the directory is chosen
automatically.
After a directory has been chosen, a submenu is opened where one can choose the source file.
Selecting the prompt line of the I<Files> submenu (I<Choose a File:>) allows one to set the parse settings described in
L</Import Data>.
After the data has been read, the user can apply different input filters (See L</Input Filters>).
=back
=head3 Input Filters
=over
bin/db-browser view on Meta::CPAN
1 | 78,975.17 1 | 78975.17
---|------------- ---|-----------
2 | 1,040,745.87 2 | 1040745.87
---|------------- ---|-----------
3 | 3,129,818.21 3 | 3129818.21
Supported L<modifiers|https://perldoc.perl.org/perlre#Modifiers>: C<imnsxage>.
In the replacement, the variable C<$c> can be used as a counter. C<$c> is set to C<0> before each C<s///>.
By selecting the prompt line (I<Your choice:>), one can save I<search & replace> instructions for later use.
If a I<search & replace> has altered the first row of the input data, a menu entry named C<RESTORE header row> is
offered.
=item Convert DateTime
Convert a I<DateTime> to another format or to seconds since the Unix epoch.
id | date_time id | date_time
bin/db-browser view on Meta::CPAN
the right side of operators. Places where extended values are available: C<WHERE>, C<HAVING>, C<SET> in update, and
C<WHEN>, C<THEN> and C<ELSE> in case expressions.
=item
Extended Arguments
If enabled, subqueries, functions and more (see the following list) are available for entering arguments in addition to
constants in the scalar and window functions.
This option can also be enabled later in the functions menu by selecting the prompt line.
=back
=head4 Column/Value/Argument Extensions
Not all of these extensions are available everywhere.
=over
=item Value
bin/db-browser view on Meta::CPAN
Selecting C<SQL> opens the subqueries menu.
See L<Subquery> for the different possibilities to enter a subquery or any other SQL text.
Entries beginning with SELECT or WITH followed by a space are automatically enclosed in parentheses.
=item Scalar Functions
Selecting C<scalar()> opens the menu, where the user can choose from a list of scalar functions.
Extended arguments for scalar functions can be temporarily enabled by selecting the prompt line (I<Scalar functions:>)
of the scalar function menu.
C<DATEADD>, C<EXTRACT> and some other functions: use the keys C<Up-Arrow> and C<Down-Arrow> to choose one of the
predefined fields (in C<Value> if the extended arguments are enabled).
C<TO_EPOCH> and C<Oracle>: The argument I<Column type> can be any of the following: I<DATE>, I<TIMESTAMP> or
I<TIMESTAMP_TZ>. If the column type is I<DATE> or I<TIMESTAMP> the session timezone is used as timezone.
Scalar functions may not work with the C<ODBC> plugin.
bin/db-browser view on Meta::CPAN
Auto Increment
Enabling I<Auto Increment> makes the 'auto-increment primary key' option available when creating a table.
=item
Data Type Guessing
When this option is enabled and a table is created, C<SQL::Type::Guess> is used to guess the data types. These data types
are then used as defaults when the user is prompted for data types.
=item
Encode data for type guessing
If enabled, the data passed to C<SQL::Type::Guess> is encoded.
The setting of this option can affect the size of C<max> in C<varchar(max)> if strings contain multibyte characters.
=back
lib/App/DBBrowser.pm view on Meta::CPAN
_quit => ' Quit',
_back => ' Back',
_continue => ' Continue',
_confirm => ' Confirm',
_reset => ' Reset',
s_back => '<<',
ok => '-OK-',
menu_addition => '%%',
info_thsd_sep => ',',
};
$info->{tc_default} = { hide_cursor => 0, clear_screen => 1, page => 2, keep => 8, undef => $info->{s_back}, prompt => 'Your choice:' }; ##
$info->{tcu_default} = { hide_cursor => 0, clear_screen => 1, page => 2, keep => 8, confirm => $info->{ok}, back => $info->{s_back} };
$info->{tf_default} = { hide_cursor => 2, clear_screen => 1, page => 2, keep => 8, auto_up => 1, skip_items => qr/^\s*\z/ };
$info->{tr_default} = { hide_cursor => 2, clear_screen => 1, page => 2, history => [ 0 .. 1000 ] };
$info->{lyt_h} = { order => 0, alignment => 2 };
$info->{lyt_v} = { undef => $info->{_back}, layout => 2 };
return bless { i => $info }, $class;
}
sub __init {
lib/App/DBBrowser.pm view on Meta::CPAN
if ( @$available_plugins == 1 ) {
$skipped_menus++;
$plugin = $available_plugins->[0];
print clear_screen();
}
else {
my $menu_plugins = [ undef, map( "- $_", @$available_plugins ) ];
# Choose
my $idx_plugin = $tc->choose(
$menu_plugins,
{ %{$sf->{i}{lyt_v}}, prompt => 'DB Plugin: ', index => 1, default => $old_idx_plugin,
undef => $sf->{i}{_quit} }
);
if ( defined $idx_plugin ) {
$plugin = $menu_plugins->[$idx_plugin];
}
if ( ! defined $plugin ) {
last PLUGIN;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $old_idx_plugin == $idx_plugin && ! $ENV{TC_RESET_AUTO_UP} ) {
lib/App/DBBrowser.pm view on Meta::CPAN
$skipped_menus++ if $skipped_menus == 1;
}
else {
my $back;
if ( $prefix ) {
$back = $skipped_menus ? $sf->{i}{_quit} : $sf->{i}{_back};
}
else {
$back = $skipped_menus ? $sf->{i}{quit} : $sf->{i}{back};
}
my $prompt = 'Choose Database:';
my $menu_db = [ undef, @databases ];
# Choose
my $idx_db = $tc->choose(
$menu_db,
{ %{$sf->{i}{lyt_v}}, prompt => $prompt, index => 1, default => $old_idx_db, undef => $back }
);
if ( defined $idx_db ) {
$db = $menu_db->[$idx_db];
}
if ( ! defined $db ) {
next PLUGIN if @$available_plugins > 1;
last PLUGIN;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $old_idx_db == $idx_db && ! $ENV{TC_RESET_AUTO_UP} ) {
lib/App/DBBrowser.pm view on Meta::CPAN
}
elsif ( ! @schemas ) {
# `$schema` remains undefined
}
elsif ( @schemas == 1 ) {
$schema = ( @$user_schemas, @$sys_schemas )[0]; # to preserve unstringified `undef`
$skipped_menus++ if $skipped_menus == 2;
}
else {
my $back = $skipped_menus == 2 ? $sf->{i}{_quit} : $sf->{i}{_back};
my $prompt = $db_string . ':';
my $menu_schema = [ undef, @schemas ];
# Choose
my $idx_sch = $tc->choose(
$menu_schema,
{ %{$sf->{i}{lyt_v}}, prompt => $prompt, index => 1, default => $old_idx_sch, undef => $back }
);
if ( defined $idx_sch ) {
$schema = $menu_schema->[$idx_sch];
}
if ( ! defined $schema ) {
$dbh->disconnect();
next DATABASE if @databases > 1;
next PLUGIN if @$available_plugins > 1;
last PLUGIN;
}
lib/App/DBBrowser.pm view on Meta::CPAN
$menu_table = [ @pre, map( "- $_", @$user_table_keys ) ];
}
push @$menu_table, $from_subquery if $sf->{o}{enable}{m_derived};
push @$menu_table, $from_cte if $sf->{o}{enable}{m_cte};
push @$menu_table, $from_join if $sf->{o}{enable}{join};
push @$menu_table, $from_union if $sf->{o}{enable}{union};
my $back = $skipped_menus == 3 ? $sf->{i}{_quit} : $sf->{i}{_back};
# Choose
my $idx_tbl = $tc->choose(
$menu_table,
{ %{$sf->{i}{lyt_v}}, prompt => '', index => 1, default => $old_idx_tbl, undef => $back }
);
if ( defined $idx_tbl ) {
$table_key = $menu_table->[$idx_tbl];
}
if ( ! defined $table_key ) {
$sf->{d}{cte_history} = [];
next SCHEMA if @schemas > 1;
$dbh->disconnect();
next DATABASE if @databases > 1;
next PLUGIN if @$available_plugins > 1;
lib/App/DBBrowser/Auxil.pm view on Meta::CPAN
}
sub print_error_message {
my ( $sf, $message, $info ) = @_;
utf8::decode( $message );
chomp( $message );
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
$tc->choose(
[ 'Press ENTER to continue' ],
{ prompt => $message, info => $info }
);
}
sub write_json {
my ( $sf, $file_fs, $ref ) = @_;
if ( ! defined $ref ) { ##
#open my $fh, '>', $file_fs or die "$file_fs: $!";
#print $fh;
#close $fh;
lib/App/DBBrowser/CreateDropAttach.pm view on Meta::CPAN
push @entries, $drop_table if $sf->{o}{enable}{drop_table};
push @entries, $create_view if $sf->{o}{enable}{create_view};
push @entries, $drop_view if $sf->{o}{enable}{drop_view};
if ( $sf->{i}{dbms} =~ /^(?:SQLite|DuckDB)\z/ ) {
push @entries, $attach_databases;
push @entries, $detach_databases;
}
if ( ! @entries ) {
return;
}
my $prompt = $sf->{d}{db_string};
my @pre = ( undef );
my $menu = [ @pre, @entries ];
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, prompt => $prompt, index => 1, default => $old_idx_cda, undef => ' <=' }
);
if ( ! defined $idx || ! defined $menu->[$idx] ) {
return;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $old_idx_cda == $idx && ! $ENV{TC_RESET_AUTO_UP} ) {
$old_idx_cda = 0;
next CREATE_DROP_ATTACH;
}
$old_idx_cda = $idx;
lib/App/DBBrowser/CreateDropAttach/AttachDB.pm view on Meta::CPAN
push @tmp_info, $sf->attach_stmt( $dbh, $attached_db->{$key}, $key );
}
push @tmp_info, '';
my @pre = ( undef );
my @choices = ( @{$sf->{d}{user_dbs}}, @{$sf->{d}{sys_dbs}} );
my $menu = [ @pre, @choices ];
my $info = join( "\n", @tmp_info );
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, prompt => "Add database:", info => $info,
undef => '<=', index => 1, default => $old_idx }
);
$ax->print_sql_info( $info );
if ( ! defined $idx || ! defined $menu->[$idx] ) {
return;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $old_idx == $idx && ! $ENV{TC_RESET_AUTO_UP} ) {
$old_idx = 0;
next ATTACH;
lib/App/DBBrowser/CreateDropAttach/AttachDB.pm view on Meta::CPAN
my $plugin = $sf->{i}{plugin};
my $db = $sf->{d}{db};
my $attached_db;
if ( -f $file_fs ) {
my $h_ref = $ax->read_json( $file_fs ) // {};
$attached_db = $h_ref->{$plugin}{$db} // {};
}
if ( ! %$attached_db ) {
my $info = $sf->{d}{db_string};
my $prompt = 'No attached databases.';
$tc->choose(
[ undef ],
{ info => $info, prompt => $prompt, undef => '<<' }
);
return;
}
my $old_idx = 0;
DETACH: while ( 1 ) {
my $info = $sf->{d}{db_string};
my @choices;
my @aliases = ( sort keys %$attached_db );
for my $key ( @aliases ) {
push @choices, sprintf "%s (%s)", $key, $attached_db->{$key};
}
my $prompt = 'Detach database:';
my @pre = ( undef );
# Choose
my $idx = $tc->choose(
[ @pre, @choices ],
{ %{$sf->{i}{lyt_v}}, prompt => $prompt, info => $info, index => 1, undef => '<=', default => $old_idx }
);
$ax->print_sql_info( $info );
if ( ! $idx ) {
return;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $old_idx == $idx && ! $ENV{TC_RESET_AUTO_UP} ) {
$old_idx = 0;
next DETACH;
}
$old_idx = $idx;
}
my $detached_alias = $aliases[$idx - @pre];
my $detached_db = delete $attached_db->{$detached_alias};
my $dbh = $sf->{d}{dbh};
$prompt = sprintf "DETACH DATABASE %s (%s)", $ax->quote_alias( $detached_alias ), $dbh->quote( $detached_db );
# Choose
my $confirm = $tc->choose(
[ undef, 'YES' ],
{ info => $info, prompt => $prompt, clear_screen => 1, undef => 'NO' }
);
$ax->print_sql_info( $info );
if ( ! defined $confirm ) {
$attached_db->{$detached_alias} = $detached_db;
next DETACH;
}
my $h_ref = $ax->read_json( $file_fs ) // {};
if ( %$attached_db ) {
$h_ref->{$plugin}{$db} = $attached_db;
}
lib/App/DBBrowser/CreateDropAttach/CreateTable.pm view on Meta::CPAN
if ( none { $sql->{table} eq $ax->qq_table( $sf->{d}{tables_info}{$_} ) } keys %{$sf->{d}{tables_info}} ) {
my $ok_create_view = $sf->__create( $sql, 'view' );
if ( ! defined $ok_create_view ) {
next SELECT_STMT;
}
elsif( ! $ok_create_view ) {
return;
}
return 1;
}
my $prompt = "$sql->{table} already exists.";
$info = $ax->get_sql_info( $sql );
my $chosen = $tc->choose(
[ undef, ' New name' ],
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => $prompt }
);
$ax->print_sql_info( $info );
if ( ! defined $chosen ) {
return;
}
next VIEW_NAME;
}
}
}
lib/App/DBBrowser/CreateDropAttach/CreateTable.pm view on Meta::CPAN
$sf->{d}{stmt_types} = [ 'Create_Table', 'Insert' ];
# first use of {stmt_types} in get_content/from_col_by_col
my $ok = $gc->get_content( $sql, $source, $goto_filter );
if ( ! $ok ) {
return;
}
if ( ! @{$sql->{insert_args}[0]} ) {
# Choose
$tc->choose(
[ 'No columns!' ],
{ prompt => 'Continue with ENTER', keep => 1 }
);
return;
}
my $tablename_default = '';
GET_TABLE_NAME: while ( 1 ) {
$tablename_default = $sf->__set_table_name( $sql, $source, $tablename_default, $count_table_name_loop ); # first time print_sql_info
if ( ! $tablename_default ) {
$count_table_name_loop = 0;
$goto_filter = 1;
lib/App/DBBrowser/CreateDropAttach/CreateTable.pm view on Meta::CPAN
EDIT_COLUMN_NAMES: while( 1 ) {
$column_names = $sf->__edit_column_names( $sql, $column_names ); # now quoted
if ( ! defined $column_names ) {
next AUTO_INCREMENT if $sf->{auto_increment};
next GET_COLUMN_NAMES;
}
if ( any { ! length } @{$sql->{ct_column_definitions}} ) {
# Choose
$tc->choose(
[ 'Column with no name!' ],
{ prompt => 'Continue with ENTER', keep => 1 }
);
next EDIT_COLUMN_NAMES;
}
my @duplicates = duplicates map { lc } @{$sql->{ct_column_definitions}};
# my @duplicates; ##
# if ( $sf->{o}{G}{quote_columns} ) {
# @duplicates = duplicates @{$sql->{ct_column_definitions}};
# }
# else {
# @duplicates = duplicates map { lc } @{$sql->{ct_column_definitions}};
# }
if ( @duplicates ) {
# Choose
$tc->choose(
[ 'Duplicate column name!' ],
{ prompt => 'Continue with ENTER', keep => 1 }
);
next EDIT_COLUMN_NAMES;
}
my @unedited_ct_column_definitions = @{$sql->{ct_column_definitions}};
my $data_types = {}; # data_types memory
EDIT_COLUMN_TYPES: while( 1 ) {
$data_types = $sf->__edit_column_types( $sql, $source, $data_types );
if ( ! $data_types ) {
$sql->{ct_column_definitions} = [ @unquoted_ct_column_definitions ];
lib/App/DBBrowser/CreateDropAttach/CreateTable.pm view on Meta::CPAN
{ info => $info, default => $tablename_default, history => [] }
);
$ax->print_sql_info( $info );
if ( ! length $table_name ) {
return;
}
$sql->{table} = $ax->qq_table( [ undef, $sf->{d}{schema}, $table_name ] );
if ( none { $sql->{table} eq $ax->qq_table( $sf->{d}{tables_info}{$_} ) } keys %{$sf->{d}{tables_info}} ) {
return $table_name;
}
my $prompt = "Table $sql->{table} already exists.";
my $menu = [ undef, ' New name' ];
$info = $ax->get_sql_info( $sql );
# Choose
my $chosen = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => $prompt, keep => scalar( @$menu ) }
);
$ax->print_sql_info( $info );
if ( ! defined $chosen ) {
return;
}
$tablename_default = $tablename_default ? $table_name : '';
$count_table_name_loop++;
}
}
lib/App/DBBrowser/CreateDropAttach/CreateTable.pm view on Meta::CPAN
my ( $first_row, $user_input ) = ( '- YES', '- NO' );
my $hidden = 'Use the first Data Row as the Table Header:';
my @pre = ( $hidden, undef );
my $menu = [ @pre, $first_row, $user_input ];
while ( 1 ) {
my $info = $ax->get_sql_info( $sql );
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => '', index => 1, default => 1, undef => ' <=',
keep => scalar( @$menu ) }
);
$ax->print_sql_info( $info );
if ( ! defined $idx || ! defined $menu->[$idx] ) {
return;
}
my $header_row;
if ( $menu->[$idx] eq $hidden ) {
my $op = App::DBBrowser::Options->new( $sf->{i}, $sf->{o} );
my $op_rw = App::DBBrowser::Options::ReadWrite->new( $sf->{i}, $sf->{o} );
lib/App/DBBrowser/CreateDropAttach/CreateTable.pm view on Meta::CPAN
sub __autoincrement_column {
my ( $sf, $sql ) = @_;
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my $ax = App::DBBrowser::Auxil->new( $sf->{i}, $sf->{o}, $sf->{d} );
my ( $no, $yes ) = ( '- NO ', '- YES' );
my $menu = [ undef, $yes, $no ];
my $info = $ax->get_sql_info( $sql );
# Choose
my $chosen = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => 'Add an AUTO INCREMENT column:', undef => ' <=',
keep => scalar( @$menu ) }
);
$ax->print_sql_info( $info );
if ( ! defined $chosen ) {
return;
}
elsif ( $chosen eq $no ) {
$sf->{auto_increment} = 0;
}
else {
lib/App/DBBrowser/CreateDropAttach/CreateTable.pm view on Meta::CPAN
sub __edit_column_names {
my ( $sf, $sql, $column_names ) = @_;
my $tf = Term::Form->new( $sf->{i}{tf_default} );
my $ax = App::DBBrowser::Auxil->new( $sf->{i}, $sf->{o}, $sf->{d} );
my $col_number = 0;
my $fields = [ map { [ ++$col_number, $_ ] } @$column_names ];
my $info = $ax->get_sql_info( $sql );
# Fill_form
my $form = $tf->fill_form(
$fields,
{ info => $info, prompt => 'Edit column names:', confirm => $sf->{i}{confirm}, back => $sf->{i}{back} . ' ' }
);
$ax->print_sql_info( $info );
if ( ! defined $form ) {
return;
}
$column_names = [ map { $_->[1] } @$form ];
$sql->{ct_column_definitions} = $ax->quote_cols( $column_names ); # now quoted
$sql->{insert_col_names} = [ @{$sql->{ct_column_definitions}} ]; # now quoted
if ( $sf->{auto_increment} ) {
shift @{$sql->{insert_col_names}};
lib/App/DBBrowser/CreateDropAttach/CreateTable.pm view on Meta::CPAN
if ( $tbl_option_rows ) {
push @$fields, [ $skip ];
for my $i ( 0 .. $tbl_option_rows - 1 ) {
push @$fields, [ 'Tbl Option', $sql->{ct_table_options}[$i] // '' ];
}
}
my $info = $ax->get_sql_info( $sql );
# Fill_form
my $filled_form = $tf->fill_form(
$fields,
{ info => $info, prompt => 'Column data types:', read_only => $read_only,
confirm => $sf->{i}{confirm}, back => $sf->{i}{back} . ' ' }
);
$ax->print_sql_info( $info );
if ( ! $filled_form ) {
return;
}
if ( $tbl_option_rows ) {
$sql->{ct_table_options} = [
grep { length } map { $_->[1] } splice @$filled_form, -$tbl_option_rows, $tbl_option_rows
];
lib/App/DBBrowser/CreateDropAttach/CreateTable.pm view on Meta::CPAN
return $data_types;
}
sub __create {
my ( $sf, $sql, $type ) = @_;
my $ax = App::DBBrowser::Auxil->new( $sf->{i}, $sf->{o}, $sf->{d} );
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my ( $no, $yes ) = ( '- NO', '- YES' );
my $menu = [ undef, $yes, $no ]; ##
my $prompt = "Create $type $sql->{table}";
if ( @{$sql->{insert_args}} ) {
my $row_count = @{$sql->{insert_args}};
$prompt .= "\nInsert " . insert_sep( $row_count, $sf->{i}{info_thsd_sep} ) . " row";
if ( @{$sql->{insert_args}} > 1 ) {
$prompt .= "s";
}
}
my $info = $ax->get_sql_info( $sql );
# Choose
my $create_table_ok = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => $prompt, undef => ' <=', keep => scalar( @$menu ) }
);
$ax->print_sql_info( $info );
if ( ! defined $create_table_ok ) {
return;
}
if ( $create_table_ok eq $no ) {
return 0;
}
my $stmt = $ax->get_stmt( $sql, 'Create_' . ucfirst( $type ), 'prepare' );
# don't reset `$sql->{ct_column_definitions}` and `$sf->{d}{stmt_types}`:
# to get a consistent print_sql_info output in CommitSQL
# to avoid another confirmation prompt in CommitSQL
if ( ! eval { $sf->{d}{dbh}->do( $stmt ); 1 } ) {
$ax->print_error_message( $@ );
return;
};
return 1;
}
sub __insert_data {
my ( $sf, $sql ) = @_;
lib/App/DBBrowser/CreateDropAttach/DropTable.pm view on Meta::CPAN
}
sub __choose_drop_item {
my ( $sf, $type ) = @_;
my $ax = App::DBBrowser::Auxil->new( $sf->{i}, $sf->{o}, $sf->{d} );
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my $tables = [ grep { $sf->{d}{tables_info}{$_}[3] eq uc $type } @{$sf->{d}{user_table_keys}} ];
if ( ! @$tables ) {
my $info = $sf->{d}{db_string};
my $prompt = sprintf 'No user %ss.', $type;
#my $prompt = sprintf 'No %ss.', $type;
$tc->choose(
[ undef ],
{ info => $info, prompt => $prompt, undef => '<<' }
);
return;
}
my $sql = {};
$ax->reset_sql( $sql );
my $prompt = $sf->{d}{db_string} . "\n" . 'Drop ' . $type;
# Choose
my $table = $tc->choose(
[ undef, map { "- $_" } sort @$tables ],
{ %{$sf->{i}{lyt_v}}, prompt => $prompt, undef => ' <=' }
);
if ( ! defined $table || ! length $table ) {
return;
}
$table =~ s/\-\s//;
my $drop_ok = $sf->__drop( $sql, $type, $table );
return $drop_ok;
}
lib/App/DBBrowser/CreateDropAttach/DropTable.pm view on Meta::CPAN
);
$ax->print_sql_info( $info );
if ( ! $ok ) {
return;
}
my $row_count;
if ( ! eval {
my $tbl = App::DBBrowser::Table->new( $sf->{i}, $sf->{o}, $sf->{d} );
my $all_arrayref = $tbl->select_statement_results( $sql );
$row_count = @$all_arrayref - 1;
my $prompt_pt = sprintf "The %s to be deleted:", $type;
my $tp = Term::TablePrint->new( $sf->{o}{table} );
if ( ! $sf->{o}{G}{warnings_table_print} ) {
local $SIG{__WARN__} = sub {};
$tp->print_table( $all_arrayref, { prompt => $prompt_pt, footer => " '" . $table . "' " } );
}
else {
$tp->print_table( $all_arrayref, { prompt => $prompt_pt, footer => " '" . $table . "' " } );
}
1; }
) {
$ax->print_error_message( $@ );
}
if ( $row_count ) {
chomp $info;
$info .= sprintf " (%s %s)\n", insert_sep( $row_count, $sf->{i}{info_thsd_sep} ), $row_count == 1 ? 'row' : 'rows';
}
my $prompt = $sf->{i}{confirm} . ':';
my ( $no, $yes ) = ( '- NO', '- YES' );
# Choose
my $choice = $tc->choose(
[ undef, $no, $yes ],
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => $prompt, undef => ' <=' }
);
$ax->print_sql_info( $info );
if ( ! defined $choice || $choice eq $no ) {
return;
}
my $stmt = $ax->get_stmt( $sql, $stmt_type, 'prepare' );
$sf->{d}{dbh}->do( $stmt ) or die "$stmt failed!";
return 1;
}
lib/App/DBBrowser/Credentials.pm view on Meta::CPAN
}
my $env_var = 'DBI_' . uc $key;
if ( length $sf->{o}{connect_data}{$key} ) {
return $sf->{o}{connect_data}{$key};
}
elsif ( $sf->{o}{connect_data}{"use_dbi_$key"} && exists $ENV{$env_var} ) {
return $ENV{$env_var}; #
}
else {
my $no_echo = $key =~ /^(?:host|port|user)\z/ ? 0 : 1;
my $prompt = ucfirst( $key ) . ': ';
my $tr = Term::Form::ReadLine->new( $sf->{i}{tr_default} );
# Readline
my $new = $tr->readline(
$prompt,
{ info => $show_sofar, no_echo => $no_echo, history => [] }
);
return $new;
}
}
1;
lib/App/DBBrowser/DB/Firebird.pm view on Meta::CPAN
elsif ( $choice eq $confirm ) {
if ( $changed ) {
$ax->write_json( $file_firebird_dbs, $databases );
}
return $databases;
}
elsif ( $choice eq $add ) {
my $tu = Term::Choose::Util->new( $sf->{i}{tcu_default} );
my $new = $tu->choose_a_file( {
info => $info,
prompt => 'Choose the database location:',
cs_label => 'Database: ',
prompt2 => 'Your choice:'
} );
if ( length $new ) {
$databases = [ uniq sort( @$databases, $new ) ];
$changed++;
}
}
elsif ( $choice eq $remove ) {
my $info = 'Remove database';
my @pre = ( undef );
my $idx = $tc->choose( [ @pre, @$databases ], { info => $info, index => 1, layout => 2 } );
lib/App/DBBrowser/DB/Oracle.pm view on Meta::CPAN
}
my $attr = $ax->clone_data( $sf->{o}{connect_attr} );
my $ask_if_sid = delete $attr->{AskIfSID};
my $dsn = "dbi:Oracle:";
if ( $host ) {
my $db_type;
my $sid = 'SID';
if ( $ask_if_sid ) {
$db_type = choose(
[ undef, 'Service_Name', $sid ],
{ info => $show_sofar . "\n", prompt => "DB Identifier Type:", undef => '<' }
);
if ( defined $db_type ) {
$show_sofar .= "\n" . 'Type: ' . $db_type;
}
}
if ( defined $db_type && $db_type eq $sid ) {
if ( $port ) {
$dsn .= "host=$host;port=$port;sid=$db";
}
else {
lib/App/DBBrowser/DB/SQLite.pm view on Meta::CPAN
my $dirs = $db_cache->{directories} // [ $sf->{i}{home_dir} ];
my $databases = $db_cache->{databases} // [];
if ( ! $sf->{i}{search} && @$databases ) {
return $databases;
}
while ( 1 ) {
my ( $ok, $change ) = ( '- Confirm', '- Change' );
# Choose
my $choice = $tc->choose(
[ undef, $ok, $change ],
{ %{$sf->{i}{lyt_v}}, prompt => 'Search databases in: ' . join( ', ', @$dirs ), info => 'SQLite' }
);
if ( ! defined $choice ) {
return $databases;
}
elsif ( $choice eq $change ) {
my $tu = Term::Choose::Util->new( $sf->{i}{tcu_default} );
#my $info = 'Curr: ' . join( ', ', @$dirs ); #
my $new_dirs = $tu->choose_directories( { confirm => $sf->{i}{_confirm}, back => $sf->{i}{_back} } );
if ( ! @{$new_dirs//[]} ) {
next;
lib/App/DBBrowser/DB/SQLite.pm view on Meta::CPAN
utf8::decode( $@ );
print $@;
}
},
no_chdir => 1,
},
$encoding->encode( $dir ) );
}
$tc->choose(
[ 'Press ENTER to continue' ],
{ prompt => 'Search finished.' }
);
}
else {
no warnings qw( File::Find );
my $file;
for my $dir ( @$dirs ) {
File::Find::find( {
wanted => sub {
#my $file_fs = $_;
return if ! -f $_;
lib/App/DBBrowser/From/Cte.pm view on Meta::CPAN
my $cte = {
full_name => $full_cte_name,
query => $query,
name => $cte_name,
};
$default_name = length $default_name ? '' : $full_cte_name;
my @table_keys = keys %{$sf->{d}{tables_info}};
my @cte_names = map { $_->{name} } @$ctes;
if ( any { $_ eq $cte_name } @table_keys, @cte_names ) {
my $type = ( grep { $_ eq $cte_name } @table_keys ) ? 'table' : 'CTE';
my $prompt = "A $type '$cte_name' already exists.";
# Choose
$tc->choose(
[ 'Press ENTER' ],
{ %{$sf->{i}{lyt_h}}, info => $info, prompt => $prompt }
);
$ax->print_sql_info( $info );
next NAME;
}
else {
if ( $cte->{full_name} =~ s/^\s*RECURSIVE\s+//i ) {
$cte->{is_recursive} = 1;
}
push @$ctes, $cte;
$sf->{d}{cte_history} = [ @$ctes ];
lib/App/DBBrowser/From/Cte.pm view on Meta::CPAN
REMOVE_CTE: while ( 1 ) {
$sf->{d}{cte_history} = [ @$ctes ];
my @pre = ( undef, $confirm );
my $menu = [ @pre, map( '- ' . $_->{name}, @$ctes ) ];
push @$menu, $all;
my $info = $ax->get_sql_info( $sql );
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => 'Remove CTE:', index => 1, undef => $sf->{i}{_back} }
);
$ax->print_sql_info( $info );
if ( ! defined $idx || $idx == 0 ) {
if ( @bu ) {
$ctes = pop @bu;
next REMOVE_CTE;
}
return;
}
push @bu, [ @$ctes ];
lib/App/DBBrowser/From/Join.pm view on Meta::CPAN
};
my @choices = map { "- $_" } @$table_keys;
push @choices, $from_subquery if $sf->{o}{enable}{j_derived};
push @choices, $from_cte if $sf->{o}{enable}{j_cte};
push @choices, $join_info;
my @pre = ( undef );
my $menu = [ @pre, @choices ];
my $info = $ax->get_sql_info( $sql );
my $idx_master = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => 'The Main Table:', index => 1, default => $old_idx_master }
);
$ax->print_sql_info( $info );
if ( ! defined $idx_master || ! defined $menu->[$idx_master] ) {
return;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $old_idx_master == $idx_master && ! $ENV{TC_RESET_AUTO_UP} ) {
$old_idx_master = 0;
next MASTER;
}
lib/App/DBBrowser/From/Join.pm view on Meta::CPAN
JOIN_TYPE: while ( 1 ) {
my $enough_tables = $sf->{i}{_confirm};
my @pre = ( undef, $enough_tables );
my $avail_joins = $sf->__available_joins();
my $menu = [ @pre, map { "- $_" } map { s/\b(.)/uc $1/ger } map { lc } @$avail_joins ];
my $info = $ax->get_sql_info( $sql );
# Choose
my $idx_type = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => 'Choose Join Type:', index => 1, default => $old_idx_type }
);
$ax->print_sql_info( $info );
if ( ! defined $idx_type || ! defined $menu->[$idx_type] ) {
if ( @bu ) {
pop @{$sql->{join_data}};
$data = pop @bu;
next JOIN_TYPE;
}
next MASTER;
}
lib/App/DBBrowser/From/Join.pm view on Meta::CPAN
push @choices, $join_info;
my $old_idx_slave = 0;
SLAVE: while ( 1 ) {
my @pre = ( undef );
my $menu = [ @pre, @choices ];
my $info = $ax->get_sql_info( $sql );
# Choose
my $idx_slave = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => 'Add table:', index => 1,
default => $old_idx_slave, undef => $sf->{i}{_reset} }
);
$ax->print_sql_info( $info );
if ( ! defined $idx_slave || ! defined $menu->[$idx_slave] ) {
return;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $old_idx_slave == $idx_slave && ! $ENV{TC_RESET_AUTO_UP} ) {
$old_idx_slave = 0;
next SLAVE;
lib/App/DBBrowser/From/Subquery.pm view on Meta::CPAN
CHOOSE_QUERY: while ( 1 ) {
$sf->{from_build_SQ} = 0;
my $selected_stmt = $sf->__choose_query( $sql, 'subquery', $ext_info );
if ( ! defined $selected_stmt ) {
return;
}
if ( $sf->{from_build_SQ} && ! $sf->{o}{G}{edit_sql_menu_sq} ) {
$sf->{from_build_SQ} = 0;
return "($selected_stmt)";
}
my $prompt = 'Query: ';
my $info = $ext_info || $ax->get_sql_info( $sql );
# Readline
my $stmt = $tr->readline(
#'Query: ',
$prompt,
{ default => $selected_stmt, show_context => 1, info => $info }
);
$ax->print_sql_info( $info );
if ( ! length $stmt ) {
next CHOOSE_QUERY;
}
unshift @{$sf->{d}{subquery_history}}, $stmt;
if ( $stmt =~ /^\s*(?:SELECT|WITH)\s/i ) {
# A statement entered with readline could have a WITH clause.
return "($stmt)";
lib/App/DBBrowser/From/Subquery.pm view on Meta::CPAN
my @pre = ( $edit_sq_history_file, undef, $build_SQ, $readline );
my $old_idx = 1;
SUBQUERY: while ( 1 ) {
my @queries = $sf->__get_queries( $saved_subqueries, $subquery_history, $print_history );
my $menu = [ @pre, @queries ];
my $info = $ext_info || $ax->get_sql_info( $sql );
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => '', index => 1, default => $old_idx, undef => '<=' }
);
$ax->print_sql_info( $info );
if ( ! defined $idx || ! defined $menu->[$idx] ) {
return;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $old_idx == $idx && ! $ENV{TC_RESET_AUTO_UP} ) {
$old_idx = 1;
next SUBQUERY;
}
lib/App/DBBrowser/From/Subquery.pm view on Meta::CPAN
), @$added_sq ); #
}
push @tmp_info, ' ';
my $menu = [ @pre ];
push @$menu, map { $pf_subquery_history . $_ } @$subquery_history;
push @$menu, map { $pf_print_history . $_ } @$print_history;
my $info = join( "\n", @tmp_info );
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, prompt => 'Add:', info => $info, index => 1 }
);
$ax->print_sql_info( $info );
if ( ! $idx ) {
if ( @bu ) {
$added_sq = pop @bu;
next;
}
return;
}
elsif ( $menu->[$idx] eq $confirm ) {
lib/App/DBBrowser/From/Subquery.pm view on Meta::CPAN
sub __edit_subqueries {
my ( $sf, $saved_subqueries ) = @_;
if ( ! @$saved_subqueries ) {
return;
}
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my @pre = ( undef );
my $info = $sf->{d}{db_string};
my $prompt = 'Edit Subquery:';
my $menu = [ @pre, map { $pf_saved_subqueries . $_->{name} } @$saved_subqueries ];
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => $prompt, index => 1, undef => ' <=' }
);
if ( ! $idx ) {
return;
}
$idx -= @pre;
my @tmp_info = ( $info, $prompt, '' );
$info = join( "\n", @tmp_info );
my $tr = Term::Form::ReadLine->new( $sf->{i}{tr_default} );
# Readline
my $stmt = $tr->readline(
'Stmt: ',
{ info => $info, default => $saved_subqueries->[$idx]{stmt}, show_context => 1, clear_screen => 1,
history => [] }
);
if ( ! length $stmt ) {
return;
lib/App/DBBrowser/From/Subquery.pm view on Meta::CPAN
sub __remove_subqueries {
my ( $sf, $saved_subqueries ) = @_;
if ( ! @$saved_subqueries ) {
return;
}
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my $old_idx = 0;
REMOVE: while ( 1 ) {
my $info = $sf->{d}{db_string};
my $prompt = 'Remove subquery:';
my @pre = ( undef );
my $menu = [ @pre, map { $pf_saved_subqueries . $_->{name} } @$saved_subqueries ];
my $idx = $tc->choose(
$menu,
{ info => $info, prompt => $prompt, undef => ' <=', layout => 2, index => 1, default => $old_idx }
);
if ( ! $idx ) {
return;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $old_idx == $idx && ! $ENV{TC_RESET_AUTO_UP} ) {
$old_idx = 0;
next REMOVE;
}
$old_idx = $idx;
}
$idx -= @pre;
my @tmp_prompt = ( '' );
push @tmp_prompt, line_fold(
'Name: ' . $saved_subqueries->[$idx]{name}, { init_tab => '', subseq_tab => ' ' x length( 'Name: ' ) }
);
push @tmp_prompt, line_fold(
'Stmt: ' . $saved_subqueries->[$idx]{stmt}, { init_tab => '', subseq_tab => ' ' x length( 'Stmt: ' ) }
);
push @tmp_prompt, '', $prompt;
my $ok = $tc->choose(
[ undef, 'YES' ],
{ info => $info, prompt => join( "\n", @tmp_prompt ), undef => 'NO' }
);
if ( ! defined $ok ) {
next REMOVE;
}
else {
splice @$saved_subqueries, $idx, 1;
return 1;
}
}
}
lib/App/DBBrowser/From/Subquery.pm view on Meta::CPAN
$menu_table = [ @pre, map( $pf . $_, @$user_table_keys ), map( $sys_prefix . $_, @$sys_table_keys ) ];
}
else {
$menu_table = [ @pre, map( $pf . $_, @$user_table_keys ) ];
}
push @$menu_table, $from_subquery if $sf->{o}{enable}{m_derived};
push @$menu_table, $from_cte if $sf->{o}{enable}{m_cte};
push @$menu_table, $from_join if $sf->{o}{enable}{join};
push @$menu_table, $from_union if $sf->{o}{enable}{union};
my $info = $sf->{d}{main_info};
my $prompt = ( $caller eq 'cte' ? 'CTE statement table:' : 'Subquery table:' );
# Choose
my $idx_tbl = $tc->choose(
$menu_table,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => $prompt, index => 1, default => $old_idx_tbl, undef => '<=' }
);
if ( defined $idx_tbl ) {
$table_key = $menu_table->[$idx_tbl];
}
if ( ! defined $table_key ) {
return;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $old_idx_tbl == $idx_tbl && ! $ENV{TC_RESET_AUTO_UP} ) {
$old_idx_tbl = 0;
lib/App/DBBrowser/From/Subquery.pm view on Meta::CPAN
}
require App::DBBrowser::From; ##
my $fr = App::DBBrowser::From->new( $sf->{i}, $sf->{o}, $sf->{d} );
my $sql = $fr->from_sql( $table_key =~ s/[-\ ]\ //r );
if ( ! defined $sql ) {
next TABLE;
}
$ax->print_sql_info( $ax->get_sql_info( $sql ) ); ##
require App::DBBrowser::Table; ##
my $tbl = App::DBBrowser::Table->new( $sf->{i}, $sf->{o}, $sf->{d} );
$prompt = ( $caller eq 'cte' ? 'CTE statement:' : 'Subquery:' );
my $statement = $tbl->browse_the_table( $sql, $prompt );
if ( ! defined $statement ) {
next TABLE;
}
return $statement;
}
}
1;
lib/App/DBBrowser/From/Union.pm view on Meta::CPAN
}
}
my $old_idx = 0;
OPERATOR: while ( 1 ) {
$sql->{subselect_stmts} = $sf->__get_sub_select_stmts( $data );
my $info = $ax->get_sql_info( $sql );
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, prompt => 'Your choice:', info => $info, index => 1, default => $old_idx }
);
$ax->print_sql_info( $info );
if ( ! defined $idx || ! defined $menu->[$idx] ) {
if ( @$data ) {
$old_idx = 0;
pop @$data;
if ( @$data ) { #
delete $data->[-1]{operator}; #
next OPERATOR; #
} #
lib/App/DBBrowser/From/Union.pm view on Meta::CPAN
push @post, $from_subquery if $sf->{o}{enable}{u_derived};
push @post, $from_cte if $sf->{o}{enable}{u_cte};
my $table_keys;
if ( $sf->{o}{G}{metadata} ) {
$table_keys = [ @{$sf->{d}{user_table_keys}}, @{$sf->{d}{sys_table_keys}} ];
}
else {
$table_keys = [ @{$sf->{d}{user_table_keys}} ];
}
my $menu = [ @pre, map( '- ' . $_, @$table_keys ), @post ];
my $prompt = @$data ? 'Add a table:' : 'Choose the first table:';
my $old_idx_tbl = 0;
TABLE: while ( 1 ) {
$sql->{subselect_stmts} = $sf->__get_sub_select_stmts( $data );
my $info = $ax->get_sql_info( $sql );
# Choose
my $idx_tbl = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => $prompt, index => 1, default => $old_idx_tbl }
);
$ax->print_sql_info( $info );
if ( ! defined $idx_tbl || ! defined $menu->[$idx_tbl] ) {
return;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $old_idx_tbl == $idx_tbl && ! $ENV{TC_RESET_AUTO_UP} ) {
$old_idx_tbl = 0;
next TABLE;
}
lib/App/DBBrowser/From/Union.pm view on Meta::CPAN
my ( $sf, $sql, $data ) = @_;
my $ax = App::DBBrowser::Auxil->new( $sf->{i}, $sf->{o}, $sf->{d} );
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my $old_idx_tbl = 0;
my @bu;
TABLE: while ( 1 ) {
my $confirm = $sf->{i}{_confirm};
my @pre = ( undef, $confirm );
my $menu = [ @pre, map { '- ' . $_->{table_key} } @$data ];
my $prompt = 'Table:';
$sql->{subselect_stmts} = $sf->__get_sub_select_stmts( $data );
my $info = $ax->get_sql_info( $sql );
# Choose
my $idx_tbl = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => $prompt, index => 1, default => $old_idx_tbl,
undef => $sf->{i}{_back} }
);
$ax->print_sql_info( $info );
if ( ! defined $idx_tbl || ! defined $menu->[$idx_tbl] ) {
if ( @bu ) {
my $bu_data = pop @bu;
for my $i ( 0 .. $#$bu_data ) {
$data->[$i] = { %{$bu_data->[$i]} };
}
$old_idx_tbl = 0;
lib/App/DBBrowser/From/Union.pm view on Meta::CPAN
my ( $sf, $sql, $data ) = @_;
my $ax = App::DBBrowser::Auxil->new( $sf->{i}, $sf->{o}, $sf->{d} );
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my @idx_changed_tables;
my $old_idx_tbl = 0;
TABLE: while ( 1 ) {
my @pre = ( undef, $sf->{i}{confirm} );
my $reset_all = ' Reset all';
my $menu = [ @pre, map('- ' . $_->{table_key}, @$data ) , $reset_all ];
my $prompt = 'Parentheses:';
$sql->{subselect_stmts} = $sf->__get_sub_select_stmts( $data );
my $info = $ax->get_sql_info( $sql );
# Choose
my $idx_tbl = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => $prompt, index => 1, default => $old_idx_tbl,
undef => $sf->{i}{back} }
);
$ax->print_sql_info( $info );
if ( ! defined $idx_tbl || ! defined $menu->[$idx_tbl] ) {
if ( @idx_changed_tables ) {
my $idx = pop @idx_changed_tables;
delete $data->[$idx]{parentheses_open};
delete $data->[$idx]{parentheses_close};
$old_idx_tbl = 0;
next TABLE;
lib/App/DBBrowser/From/Union.pm view on Meta::CPAN
}
elsif ( $menu->[$idx_tbl] eq $reset_all ) {
for my $d ( @$data ) {
delete $d->{parentheses_open};
delete $d->{parentheses_close};
}
$old_idx_tbl = 0;
next TABLE;
}
$idx_tbl -= @pre;
$prompt = 'Parentheses' . "\n" . ( '(' x ( $data->[$idx_tbl]{parentheses_open} // 0 ) );
$prompt .= $data->[$idx_tbl]{table_key} . ( ')' x ( $data->[$idx_tbl]{parentheses_close} // 0 ) ) . ':';
my $open = ' + (';
my $close = ' + )';
my $reset = ' Reset';
# Choose
my $p_type = $tc->choose(
[ undef, $open, $close, $reset ],
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => $prompt,
undef => ' <=' }
);
if ( ! defined $p_type ) {
next TABLE;
}
my $max_depth = 3;
if ( $p_type eq $open && ( $data->[$idx_tbl]{parentheses_open} // 0 ) < $max_depth ) {
$data->[$idx_tbl]{parentheses_open} += 1;
}
elsif ( $p_type eq $close && ( $data->[$idx_tbl]{parentheses_close} // 0 ) < $max_depth ) {
lib/App/DBBrowser/GetContent.pm view on Meta::CPAN
$source->{old_idx_menu} //= 0;
MENU: while ( 1 ) {
if ( $goto_filter ) {
# keep current source type
}
elsif ( $data_source_choice_idx =~ /^(?:0|1)\z/ ) {
$source->{source_type} = $choices[$data_source_choice_idx][0];
}
else {
my $prompt = 'Source type:';
my @pre = ( undef );
my $menu = [ @pre, map( $_->[1], @choices ) ];
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, prompt => $prompt, index => 1, default => $source->{old_idx_menu},
undef => ' <=' }
);
if ( ! defined $idx || ! defined $menu->[$idx] ) {
return;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $source->{old_idx_menu} == $idx && ! $ENV{TC_RESET_AUTO_UP} ) {
$source->{old_idx_menu} = 0;
next MENU;
}
lib/App/DBBrowser/GetContent.pm view on Meta::CPAN
return if $data_source_choice_idx =~ /^(?:0|1)\z/;
next MENU;
}
}
else{
$source->{dir} = $dirs->[0];
}
}
else {
my $dirs = $cs->__avail_directories();
my $prompt = 'Choose a Dir:';
my $new_search = ' NEW search';
my @pre = ( undef, $new_search );
my $menu = [ @pre, map( '- ' . $_, @$dirs ) ];
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, prompt => $prompt, index => 1, default => $source->{old_idx_dir}, undef => ' <=' }
);
if ( ! defined $idx || ! defined $menu->[$idx] ) {
return if $data_source_choice_idx =~ /^(?:0|1)\z/;
next MENU;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $source->{old_idx_dir} == $idx && ! $ENV{TC_RESET_AUTO_UP} ) {
$source->{old_idx_dir} = 0;
next DIR;
}
lib/App/DBBrowser/GetContent.pm view on Meta::CPAN
my $hidden = 'Choose a File:';
my @pre = ( $hidden, undef );
my $change_dir = ' Change dir';
if ( $sf->{o}{insert}{history_dirs} == 1 ) {
push @pre, $change_dir;
}
my $menu = [ @pre, map { ' ' . basename $_ } @$files_in_chosen_dir ]; #
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, prompt => '', index => 1, default => $source->{old_idx_file},
undef => ' <=' }
);
if ( ! defined $idx || ! defined $menu->[$idx] ) {
if ( $sf->{o}{insert}{history_dirs} == 1 ) {
return if $data_source_choice_idx =~ /^(?:0|1)\z/;
next MENU;
}
next DIR;
}
if ( $sf->{o}{G}{menu_memory} ) {
lib/App/DBBrowser/GetContent.pm view on Meta::CPAN
if ( $parse_ok && $parse_ok == -1 ) { # reparse
next PARSE;
}
}
if ( ! $parse_ok ) {
next FILE;
}
if ( ! @{$sql->{insert_args}} ) {
$tc->choose(
[ 'Press ENTER' ],
{ prompt => 'Empty File!' }
);
close $fh;
next FILE;
}
}
else {
SHEET: while ( 1 ) {
my $ok = $cp->parse_with_Spreadsheet_Read( $sql, $source, $source->{file_fs} );
if ( ! $ok ) {
next FILE;
}
if ( ! @{$sql->{insert_args}} || ! @{$sql->{insert_args}[0]} ) {
$tc->choose(
[ 'Press ENTER' ],
{ prompt => 'Empty Sheet!' }
);
next SHEET if $source->{saved_book};
next FILE;
}
last SHEET;
}
}
}
if ( ! $sf->{o}{insert}{enable_input_filter} ) {
return 1;
lib/App/DBBrowser/GetContent/Filter.pm view on Meta::CPAN
$reset, $s_and_replace, $convert_date, $skip,
$reparse, $remove_cell, $insert_cell, $skip,
$empty_to_null, $join_columns, $split_column, $append_col,
$cols_to_rows, $split_table, $merge_rows, $fill_up_rows,
];
my $max_cols = 4;
my $info = $sf->__get_filter_info( $sql );
# Choose
my $idx = $tc->choose(
$menu,
{ info => $info, prompt => 'Filter:', layout => 0, order => 0, max_cols => $max_cols, index => 1,
default => $old_idx, undef => $back, busy_string => $working }
);
$sf->__print_busy_string( $working );
if ( ! $idx ) {
$sql->{insert_args} = [];
delete $sf->{d}{fi};
return;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $old_idx == $idx && ! $ENV{TC_RESET_AUTO_UP} ) {
lib/App/DBBrowser/GetContent/Filter.pm view on Meta::CPAN
my $aoa = $sql->{insert_args};
my @pre = ( undef, $sf->{i}{ok} );
my $stringified_rows = [];
$sf->__print_busy_string( $working );
{
no warnings 'uninitialized';
for my $i ( 0 .. $#$aoa ) {
push @$stringified_rows, join ',', @{$aoa->[$i]};
}
}
my $prompt = 'Choose rows:';
$sql->{insert_args} = []; # $sql->{insert_args} refers to a new empty array - this doesn't delete $aoa
while ( 1 ) {
my $info = $sf->__get_filter_info( $sql, $filter_str );
# Choose
my @idx = $tc->choose(
[ @pre, @$stringified_rows ],
{ %{$sf->{i}{lyt_v}}, prompt => $prompt, info => $info, meta_items => [ 0 .. $#pre ],
include_highlighted => 2, index => 1, undef => $sf->{i}{s_back}, busy_string => $working }
);
$sf->__print_busy_string( $working );
if ( ! $idx[0] ) {
$sql->{insert_args} = $aoa;
return;
}
if ( $idx[0] == $#pre ) {
shift @idx;
for my $i ( @idx ) {
lib/App/DBBrowser/GetContent/Filter.pm view on Meta::CPAN
next;
}
$sql->{insert_args} = $aoa;
return;
}
if ( $choice eq $confirm ) {
return 1;
}
}
my $info = $sf->__get_filter_info( $sql, $filter_str );
my $prompt = "Begin range:";
# Stop
my $idx_first_row = $sf->__choose_a_row_idx( $aoa, $info, $prompt, $working );
if ( ! defined $idx_first_row ) {
if ( @{$sql->{insert_args}} ) {
next;
}
$sql->{insert_args} = $aoa;
return;
}
push @{$sql->{insert_args}}, $aoa->[$idx_first_row]; # temporarily for the info output
$info = $sf->__get_filter_info( $sql, $filter_str );
pop @{$sql->{insert_args}};
$prompt = "End range:";
# Stop
my $idx_last_row = $sf->__choose_a_row_idx( [ @{$aoa}[$idx_first_row .. $#$aoa] ], $info, $prompt, $working );
if ( defined $idx_last_row ) {
push @last_indexes, $#{$sql->{insert_args}};
$idx_last_row += $idx_first_row;
push @{$sql->{insert_args}}, @{$aoa}[$idx_first_row .. $idx_last_row];
}
}
}
sub __row_groups {
lib/App/DBBrowser/GetContent/Filter.pm view on Meta::CPAN
my @choices_groups;
my $len = length insert_sep( scalar @{$group{$keys_sorted[0]}}, $sf->{i}{info_thsd_sep} );
for my $col_count ( @keys_sorted ) {
my $row_count = scalar @{$group{$col_count}};
my $row_str = $row_count == 1 ? 'row has ' : 'rows have';
my $col_str = $col_count == 1 ? 'column ' : 'columns';
push @choices_groups, sprintf ' %*s %s %2d %s',
$len, insert_sep( $row_count, $sf->{i}{info_thsd_sep} ), $row_str,
$col_count, $col_str;
}
my $prompt = 'Choose group:';
my $info = $sf->__get_filter_info( $sql, $filter_str );
# Choose
my $idxs = $tu->choose_a_subset(
\@choices_groups,
{ info => $info, prompt => $prompt, layout => 2, index => 1, all_by_default => 1,
cs_label => "Chosen groups:\n", cs_separator => "\n", cs_end => "\n", busy_string => $working }
);
$sf->__print_busy_string( $working );
if ( ! defined $idxs ) {
return;
}
else {
my $row_idxs = [];
for my $idx ( @$idxs ) {
push @$row_idxs, @{$group{ $keys_sorted[$idx] }};
lib/App/DBBrowser/GetContent/Filter.pm view on Meta::CPAN
return;
}
}
sub __remove_cell {
my ( $sf, $sql, $filter_str, $working ) = @_;
my $aoa = $sql->{insert_args};
while ( 1 ) {
my $prompt = "Choose row:";
my $info = $filter_str;
# Stop
my $row_idx = $sf->__choose_a_row_idx( $aoa, $info, $prompt, $working );
if ( ! defined $row_idx ) {
return;
}
$prompt = "Choose cell:";
$info = $sf->__get_filter_info( $sql, $filter_str );
# Stop
my $col_idx = $sf->__choose_a_column_idx( $aoa->[$row_idx], $info, $prompt );
if ( ! defined $col_idx ) {
next;
}
splice( @{$aoa->[$row_idx]}, $col_idx, 1 );
$sql->{insert_args} = $aoa;
return;
}
}
sub _stringify_row { # used only once
lib/App/DBBrowser/GetContent/Filter.pm view on Meta::CPAN
return $stringified_row;
}
sub __insert_cell {
my ( $sf, $sql, $filter_str, $working ) = @_;
my $tr = Term::Form::ReadLine->new( $sf->{i}{tr_default} );
my $aoa = $sql->{insert_args};
while ( 1 ) {
my $prompt = "Choose row:";
my $info = $filter_str;
# Stop
my $row_idx = $sf->__choose_a_row_idx( $aoa, $info, $prompt, $working );
if ( ! defined $row_idx ) {
return;
}
my $cols = [ @{$aoa->[$row_idx]}, 'END_of_Row' ];
$prompt = "Insert cell before:";
$info = $sf->__get_filter_info( $sql, $filter_str );
# Stop
my $col_idx = $sf->__choose_a_column_idx( $cols, $info, $prompt );
if ( ! defined $col_idx ) {
next;
}
my @row = @{$aoa->[$row_idx]};
splice( @row, $col_idx, 0, '<*>' );
my $str_row_with_placeholder = _stringify_row( \@row );
$str_row_with_placeholder =~ s/"<\*>"/<*>/;
my $label = 'Row: ';
my @tmp_info = ( $filter_str );
push @tmp_info, line_fold(
$label . $str_row_with_placeholder, { subseq_tab => ' ' x length $label, join => 0 }
);
$prompt = "<*>: ";
$info = $sf->__get_filter_info( $sql, join( "\n", @tmp_info ) );
# Readline
my $cell = $tr->readline(
$prompt,
{ info => $info, history => [] }
);
$sf->__print_busy_string( $working );
splice( @{$aoa->[$row_idx]}, $col_idx, 0, $cell );
$sql->{insert_args} = $aoa;
return;
}
}
sub __fill_up_rows {
my ( $sf, $sql, $filter_str, $working ) = @_;
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my $aoa = $sql->{insert_args};
my $menu = [ undef, '- YES' ];
my $prompt = 'Fill up shorter rows?';
my $info = $sf->__get_filter_info( $sql, $filter_str );
# Choose
my $ok = $tc->choose(
$menu,
{ info => $info, prompt => $prompt, index => 1, undef => '- NO', layout => 2 }
);
$sf->__print_busy_string( $working );
if ( ! $ok ) {
return;
}
my $longest_row = 0;
for my $row ( @$aoa ) {
my $col_count = scalar @$row;
if ( $col_count > $longest_row ) {
$longest_row = $col_count;
lib/App/DBBrowser/GetContent/Filter.pm view on Meta::CPAN
$sql->{insert_args} = $aoa;
return;
}
sub __append_col {
my ( $sf, $sql, $filter_str, $working ) = @_;
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my $aoa = $sql->{insert_args};
my $menu = [ undef, '- YES' ];
my $prompt = 'Append an empty column?';
my $info = $sf->__get_filter_info( $sql, $filter_str );
# Choose
my $ok = $tc->choose(
$menu,
{ info => $info, prompt => $prompt, index => 1, undef => '- NO', layout => 2 }
);
$sf->__print_busy_string( $working );
if ( $ok ) {
my $new_last_idx = $#{$aoa->[0]} + 1;
for my $row ( @$aoa ) {
$#$row = $new_last_idx;
}
$sql->{insert_args} = $aoa;
}
return;
}
sub __split_column {
my ( $sf, $sql, $filter_str, $working ) = @_;
my $tf = Term::Form->new( $sf->{i}{tf_default} );
my $aoa = $sql->{insert_args};
my $is_empty = $sf->__search_empty_cols( $aoa );
my $header = $sf->__prepare_header( $aoa, $is_empty );
my $prompt = 'Choose column:';
my $info = $sf->__get_filter_info( $sql, $filter_str );
# Stop
my $idx = $sf->__choose_a_column_idx( $header, $info, $prompt );
if ( ! defined $idx ) {
return;
}
my $fields = [
[ 'Pattern', ],
[ 'Limit', ],
[ 'Left trim', '\s+' ],
[ 'Right trim', '\s+' ]
];
my $back = $sf->{i}{back} . ' ' x 3;
$prompt = "Split column \"$header->[$idx]\"";
$info = $sf->__get_filter_info( $sql, $filter_str );
# Fill_form
my $form = $tf->fill_form(
$fields,
{ info => $info, prompt => $prompt, confirm => $sf->{i}{confirm}, back => $back }
);
$sf->__print_busy_string( $working );
if ( ! $form ) {
return;
}
my ( $pattern, $limit, $left_trim, $right_trim ) = map { $_->[1] } @$form;
$pattern //= '';
for my $row ( @$aoa ) { # modifies $aoa
my $col = splice @$row, $idx, 1;
lib/App/DBBrowser/GetContent/Filter.pm view on Meta::CPAN
$col_count = $tu->choose_a_number(
$digits,
{ info => $info, cs_label => 'Number columns new table: ', small_first => 1,
confirm => $sf->{i}{confirm}, back => $sf->{i}{back} }
);
$sf->__print_busy_string( $working );
if ( ! $col_count ) {
return;
}
if ( @{$aoa->[0]} < $col_count ) {
my $prompt = sprintf 'Chosen number(%d) bigger than the available columns(%d)!', $col_count, scalar( @{$aoa->[0]} );
my $info = $sf->__get_filter_info( $sql, $filter_str );
$tc->choose(
[ 'Continue with ENTER' ],
{ info => $info, prompt => $prompt }
);
$sf->__print_busy_string( $working );
next CHOOSE_A_NUMBER;
}
if ( @{$aoa->[0]} % $col_count ) {
my $prompt = sprintf 'The number of available columns(%d) cannot be divided by the selected number(%d) without remainder!', scalar( @{$aoa->[0]} ), $col_count;
my $info = $sf->__get_filter_info( $sql, $filter_str );
$tc->choose(
[ 'Continue with ENTER' ],
{ info => $info, prompt => $prompt }
);
$sf->__print_busy_string( $working );
next CHOOSE_A_NUMBER;
}
last CHOOSE_A_NUMBER;
}
my $begin = 0;
my $end = $col_count - 1;
my $tmp = [];
lib/App/DBBrowser/GetContent/Filter.pm view on Meta::CPAN
@$stringified_rows = map {
my $str_row = join( ',', @$_ );
if ( print_columns( $str_row ) > $term_w ) {
$str_row = unicode_sprintf( $str_row, $term_w, { suffix_on_truncate => $sf->{i}{dots} } );
}
else {
$str_row;
}
} @$aoa;
}
my $prompt = 'Choose rows:';
my $info = $filter_str;
# Choose
my $chosen_idxs = $tu->choose_a_subset(
$stringified_rows,
{ cs_separator => "\n", cs_end => "\n", layout => 2, order => 0, all_by_default => 0, prompt => $prompt,
index => 1, info => $info, busy_string => $working }
);
$sf->__print_busy_string( $working );
if ( ! defined $chosen_idxs || ! @$chosen_idxs ) {
return;
}
my $merged = [];
for my $col ( 0 .. $#{$aoa->[$chosen_idxs->[0]]} ) {
my @tmp;
for my $row ( @$chosen_idxs ) {
next if ! defined $aoa->[$row][$col];
next if $aoa->[$row][$col] =~ /^\s*\z/;
$aoa->[$row][$col] =~ s/^\s+|\s+\z//g;
push @tmp, $aoa->[$row][$col];
}
$merged->[$col] = join ' ', @tmp;
}
$prompt = @$chosen_idxs == 1 ? 'Edit row cells:' : 'Edit cells of merged rows:';
my $col_number = 0;
my $fields = [ map { [ ++$col_number, defined $_ ? "$_" : '' ] } @$merged ];
$info = $sf->__get_filter_info( $sql, $filter_str );
# Fill_form
my $form = $tf->fill_form(
$fields,
{ info => $info, prompt => $prompt, confirm => $sf->{i}{confirm},
back => $sf->{i}{back} . ' ' }
);
$sf->__print_busy_string( $working );
if ( ! $form ) {
return;
}
$merged = [ map { $_->[1] } @$form ];
my $first_idx = shift @$chosen_idxs;
$aoa->[$first_idx] = $merged; # modifies $aoa
for my $idx ( sort { $b <=> $a } @$chosen_idxs ) {
lib/App/DBBrowser/GetContent/Filter.pm view on Meta::CPAN
# Choose
my $chosen_idxs = $tu->choose_a_subset(
$header,
{ cs_label => 'Cols: ', layout => 0, order => 0, index => 1, info => $info, busy_string => $working }
);
$sf->__print_busy_string( $working );
if ( ! defined $chosen_idxs || ! @$chosen_idxs ) {
return;
}
my $join_char = '';
my $prompt;
if ( @$chosen_idxs == 1 ) {
$prompt = 'Edit cells of ' . ( $aoa->[0][$chosen_idxs->[0]] // '--' ) . ':';
}
else {
$prompt = 'Edit cells of joined columns:';
my @tmp_info = ( $filter_str );
my $label = 'Cols: ';
push @tmp_info, line_fold(
$label . '"' . join( '", "', @{$header}[@$chosen_idxs] ) . '"',
{ subseq_tab => ' ' x length $label, join => 0 }
);
$info = $sf->__get_filter_info( $sql, join( "\n", @tmp_info ) );
# Readline
$join_char = $tr->readline(
'Join-string: ',
lib/App/DBBrowser/GetContent/Filter.pm view on Meta::CPAN
push @tmp, $aoa->[$row][$col];
}
$merged->[$row] = join $join_char, @tmp;
}
my $col_number = 0;
my $fields = [ map { [ ++$col_number, defined $_ ? "$_" : '' ] } @$merged ];
$info = $filter_str;
# Fill_form
my $form = $tf->fill_form(
$fields,
{ info => $info, prompt => $prompt, confirm => $sf->{i}{confirm},
back => $sf->{i}{back} . ' ' }
);
$sf->__print_busy_string( $working );
if ( ! $form ) {
$sql->{insert_args} = $aoa;
return;
}
$merged = [ map { $_->[1] } @$form ];
my $first_idx = shift @$chosen_idxs;
for my $row ( 0 .. $#{$aoa} ) { # modifies $aoa
lib/App/DBBrowser/GetContent/Filter.pm view on Meta::CPAN
$sql->{insert_args} = $aoa;
return;
}
sub __transpose_rows_to_cols {
my ( $sf, $sql, $filter_str, $working ) = @_;
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my $aoa = $sql->{insert_args};
my $menu = [ undef, '- YES' ];
my $prompt = 'Transpose columns to rows?';
my $info = $sf->__get_filter_info( $sql, $filter_str );
my $ok = $tc->choose(
$menu,
{ info => $info, prompt => $prompt, index => 1, undef => '- NO', layout => 2, busy_string => $working }
);
$sf->__print_busy_string( $working );
if ( $ok ) {
my $tmp_aoa = [];
for my $row ( 0 .. $#$aoa ) {
for my $col ( 0 .. $#{$aoa->[$row]} ) {
$tmp_aoa->[$col][$row] = $aoa->[$row][$col];
}
}
$sql->{insert_args} = $tmp_aoa;
lib/App/DBBrowser/GetContent/Filter.pm view on Meta::CPAN
else {
$header->[$col_idx] = 'tmp_' . ( $col_idx + 1 );
}
}
}
return $header;
}
sub __choose_a_column_idx {
my ( $sf, $columns, $info, $prompt ) = @_;
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my @pre = ( undef );
# Choose
my $col_idx = $tc->choose(
[ @pre, map( defined $_ ? $_ : '', @$columns ) ],
{ layout => 0, order => 0, index => 1, info => $info, prompt => $prompt, empty => '--' }
);
if ( ! $col_idx ) {
return;
}
return $col_idx - @pre;
}
sub __choose_a_row_idx {
my ( $sf, $aoa, $info, $prompt, $working ) = @_;
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my @stringified_rows;
{
no warnings 'uninitialized';
@stringified_rows = map { join ',', @$_ } @$aoa;
}
my @pre = ( undef );
# Choose
my $row_idx = $tc->choose(
[ @pre, @stringified_rows ],
{ layout => 2, index => 1, info => $info, prompt => $prompt, busy_string => $working }
);
$sf->__print_busy_string( $working );
if ( ! $row_idx ) {
return;
}
return $row_idx - @pre;
}
lib/App/DBBrowser/GetContent/Filter/ConvertDate.pm view on Meta::CPAN
$step = 1_000;
my $total = int $row_count / $step;
$fmt = $busy_text . $total . '/%' . length( $total ) . 'd';
}
}
my $is_empty = $cf->__search_empty_cols( $aoa );
my $header = $cf->__prepare_header( $aoa, $is_empty );
COL: while ( 1 ) {
my $info = $cf->__get_filter_info( $sql, $filter_str);
my $prompt = "Choose column:";
# Stop
my $col_idx = $cf->__choose_a_column_idx( $header, $info, $prompt );
if ( ! defined $col_idx ) {
return;
}
my $col = $header->[$col_idx];
my @col_info = ( $filter_str, 'Column: ' . $col );
$info = $cf->__get_filter_info( $sql, join( "\n", @col_info ) );
SKIP_HEADER: while ( 1 ) {
my @pre = ( undef );
my ( $no, $yes ) = ( 'NO', 'YES' );
my $row_idx_begin = 0;
if ( $sf->{d}{stmt_types}[0] eq 'Create_Table' ) {
# Choose
my $choice = $tc->choose(
[ @pre, $yes, $no ],
{ prompt => 'Skip the first row?', undef => $sf->{i}{s_back}, info => $info }
);
if ( ! defined $choice ) {
next COL;
}
$row_idx_begin = 1 if $choice eq $yes;
}
my $count_error_in = 0;
my $default_pattern_in;
IN: while ( 1 ) {
my @in_info = @col_info;
$info = $cf->__get_filter_info( $sql, join( "\n", @in_info ) );
my $prompt_patter_in = 'Pattern in: ';
# Readline
my $pattern_in = $tr->readline(
$prompt_patter_in,
{ info => $info, default => $default_pattern_in, history => $sf->__pattern_history( 'in' ) }
);
if ( ! length $pattern_in ) {
next SKIP_HEADER if $sf->{d}{stmt_types}[0] eq 'Create_Table';
next COL;
}
$default_pattern_in = $count_error_in > 1 ? '' : $pattern_in;
push @in_info, $prompt_patter_in . $pattern_in;
my $formatter_args = { pattern => $pattern_in };
if ( $pattern_in =~ /$rx_locale_dependent/ ) {
$info = $cf->__get_filter_info( $sql, join( "\n", @in_info ) );
my $prompt_locale_in = 'Locale in: ';
# Readline
my $locale_in = $tr->readline(
$prompt_locale_in,
{ info => $info, history => [] }
);
if ( length $locale_in ) {
$formatter_args->{locale} = $locale_in;
push @in_info, $prompt_locale_in . $locale_in;
}
}
my $formatter = DateTime::Format::Strptime->new( %$formatter_args, on_error => 'undef' );
TYPE: while ( 1 ) {
$info = $cf->__get_filter_info( $sql, join( "\n", @in_info ) );
my ( $format, $epoch ) = ( '- DateTime', '- Epoch' );
# Choose
my $choice = $tc->choose(
[ @pre, $format, $epoch ],
{ %{$sf->{i}{lyt_v}}, prompt => 'To: ', undef => $sf->{i}{s_back}, info => $info }
);
if ( ! defined $choice ) {
++$count_error_in;
next IN;
}
my $count_error_out = 0;
my $default_pattern_out;
OUT: while ( 1 ) {
my @tmp_info = @in_info;
lib/App/DBBrowser/GetContent/Filter/ConvertDate.pm view on Meta::CPAN
}
1 }
) {
$ax->print_error_message( $@ );
++$count_error_in;
next IN;
}
}
else {
$info = $cf->__get_filter_info( $sql, join( "\n", @tmp_info ) );
my $prompt_pattern_out = 'Pattern out: ';
# Readline
my $pattern_out = $tr->readline(
$prompt_pattern_out,
{ info => $info, default => $default_pattern_out, history => $sf->__pattern_history( 'out' ) }
);
if ( ! length $pattern_out ) {
next TYPE;
}
$default_pattern_out = $count_error_out > 1 ? '' : $pattern_out;
my $locale_out;
if ( $pattern_out =~ /$rx_locale_dependent/ ) {
push @tmp_info, $prompt_pattern_out . $pattern_out;
$info = $cf->__get_filter_info( $sql, join( "\n", @tmp_info ) );
my $prompt_locale_out = 'Locale out: ';
# ReadLine
$locale_out = $tr->readline(
$prompt_locale_out,
{ info => $info, history => [] }
);
if ( length $locale_out ) {
push @tmp_info, $prompt_locale_out . $locale_out;
}
}
$cf->__print_busy_string( $working );
if ( ! eval {
for my $row ( $row_idx_begin .. $#$aoa ) {
next if ! length $aoa->[$row][$col_idx];
my $dt = $formatter->parse_datetime( $aoa->[$row][$col_idx] );
if ( ! defined $dt ) {
for my $row ( 1 .. $row ) {
$aoa->[$row][$col_idx] = $bu_insert_args->[$row][$col_idx];
lib/App/DBBrowser/GetContent/Filter/SearchAndReplace.pm view on Meta::CPAN
}
else {
push @$prefixed_available, '- ' . $name;
}
}
my $menu = [ @pre, @$prefixed_available ];
my $info = $cf->__get_filter_info( $sql, join( "\n", @tmp_info ) );
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => '', default => $old_idx, index => 1, undef => $sf->{i}{_back} }
);
if ( ! defined $idx || ! defined $menu->[$idx] ) {
if ( @bu ) {
( $used_names, $all_sr_groups ) = @{pop @bu};
next ADD_SEARCH_AND_REPLACE;
}
return;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $old_idx == $idx && ! $ENV{TC_RESET_AUTO_UP} ) {
lib/App/DBBrowser/GetContent/Filter/SearchAndReplace.pm view on Meta::CPAN
}
}
if ( $header_changed ) {
my ( $yes, $no ) = ( '- YES', '- NO' );
my $menu = [ undef, $yes, $no ];
my @tmp_info_addition = ( 'Header: ' . join( ', ', map { $_ // '' } @{$sql->{insert_args}[0]} ), ' ' );
$info = $cf->__get_filter_info( $sql, join( "\n", @tmp_info, @tmp_info_addition ) );
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => 'Restore header?', index => 1, undef => $sf->{i}{s_back} }
);
if ( ! defined $idx || ! defined $menu->[$idx] ) {
if ( @$aoa * @$col_idxs > 500_000 ) {
$cf->__print_busy_string( 'Working ...' );
}
$sql->{insert_args} = [ map { [ @$_ ] } @{$bu_insert_args} ];
return;
}
my $choice = $menu->[$idx];
if ( $choice eq $yes ) {
$sql->{insert_args}[0] = $header;
}
}
return 1;
}
elsif ( $choice eq $add ) {
my $prompt = 'Build s///;';
my $skip = ' ';
my $fields = [];
for my $nr ( 1 .. 5 ) {
push @$fields,
[ $skip ],
[ $nr . ' Pattern', ],
[ $nr . ' Replacement', ],
[ $nr . ' Modifiers', ];
}
my $back = $sf->{i}{back} . ' ';
SUBSTITUTION: while ( 1 ) {
$info = $cf->__get_filter_info( $sql, join( "\n", @tmp_info ) );
# Fill_form
my $form = $tf->fill_form(
$fields,
{ info => $info, prompt => $prompt, confirm => $sf->{i}{confirm}, back => $back }
);
if ( ! defined $form ) {
next ADD_SEARCH_AND_REPLACE;
}
my $sr_group = [ $sf->__from_form_to_sr_group_data( $form ) ];
if ( ! @$sr_group ) {
next ADD_SEARCH_AND_REPLACE;
}
if ( ! eval {
$sf->__execute_substitutions( [ [ 'test_string' ] ], [ 0 ], [ $sr_group ] );
lib/App/DBBrowser/GetContent/Filter/SearchAndReplace.pm view on Meta::CPAN
my ( $section_separator, $pattern, $replacement, $modifiers ) = map { $_->[1] // '' } splice @copy, 0, 4;
if ( length $pattern ) {
push @sr_group_data, { pattern => $pattern, replacement => $replacement, modifiers => $modifiers };
}
}
return @sr_group_data;
}
sub __choose_column_indexes {
my ( $sf, $columns, $info, $prompt ) = @_;
my $tu = Term::Choose::Util->new( $sf->{i}{tcu_default} );
# Choose
my $col_idxs = $tu->choose_a_subset(
$columns,
{ cs_label => $prompt, info => $info, layout => 0, all_by_default => 1, index => 1, keep_chosen => 0 }
);
if ( ! defined $col_idxs ) {
return;
}
return $col_idxs;
}
sub __execute_substitutions {
my ( $sf, $aoa, $col_idxs, $all_sr_groups ) = @_;
lib/App/DBBrowser/GetContent/Filter/SearchAndReplace.pm view on Meta::CPAN
my $ax = App::DBBrowser::Auxil->new( $sf->{i}, $sf->{o}, $sf->{d} );
my $skip = ' ';
my $fields = [];
for my $nr ( 1 .. 9 ) {
push @$fields,
[ $skip ],
[ $nr . ' Pattern', ],
[ $nr . ' Replacement', ],
[ $nr . ' Modifiers', ];
}
my $prompt = 'Add "search & replace":';
ADD_CODE: while ( 1 ) {
# Fill_form
my $form = $tf->fill_form(
$fields,
{ prompt => $prompt, confirm => $sf->{i}{_confirm}, back => $sf->{i}{_back} . ' ' }
);
if ( ! defined $form ) {
return;
}
my $sr_group = [ $sf->__from_form_to_sr_group_data( $form ) ];
if ( ! @$sr_group ) {
return;
}
if ( ! eval {
$sf->__execute_substitutions( [ [ 'test_string' ] ], [ 0 ], [ $sr_group ] );
1 }
) {
$ax->print_error_message( $@ );
$fields = $form;
next ADD_CODE;
}
my @code = _stringified_sr_group( $sr_group );
my $info = join "\n", map { ( ' ' x 6 ) . $_ } @code;
$info =~ s/^\s{5}/Code:/;
$info = $prompt . "\n\n" . $info;
my $name = $sf->__get_new_name( $info, 'Name: ', $saved, $sr_group );
if ( ! length $name ) {
$fields = $form;
next ADD_CODE;
}
$saved->{$name} = [ @$sr_group ];
return 1;
}
}
sub __get_new_name {
my ( $sf, $info, $prompt, $saved, $sr_group ) = @_;
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my $tr = Term::Form::ReadLine->new( $sf->{i}{tr_default} );
my $name_default = '';
if ( @$sr_group == 1 ) {
$name_default = ( _stringified_sr_group( $sr_group ) )[0];
}
my $count = 1;
NAME: while ( 1 ) {
# Readline
my $new_name = $tr->readline(
$prompt,
{ info => $info, default => $name_default, history => [] }
);
if ( ! length $new_name ) {
return;
}
if ( any { $new_name eq $_ } keys %$saved ) {
my $prompt = "\"$new_name\" already exists.";
my $choice = $tc->choose(
[ undef, ' New name' ],
{ %{$sf->{i}{lyt_v}}, prompt => $prompt, info => $info }
);
if ( ! defined $choice ) {
return;
}
if ( $count > 1 ) {
$new_name = undef;
}
$name_default = $new_name;
$count++;
next NAME;
lib/App/DBBrowser/GetContent/Filter/SearchAndReplace.pm view on Meta::CPAN
}
sub __edit_saved {
my ( $sf, $saved ) = @_;
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my $tf = Term::Form->new( $sf->{i}{tf_default} );
my $tr = Term::Form::ReadLine->new( $sf->{i}{tr_default} );
my @pre = ( undef );
my $menu = [ @pre, map( '- ' . $_, sort { $a cmp $b } keys %$saved ) ];
my $prompt = 'Edit "search & replace":';
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, prompt => $prompt, index => 1, undef => ' <=' }
);
if ( ! defined $idx || ! defined $menu->[$idx] ) {
return;
}
my $name = $menu->[$idx] =~ s/^- //r;
my $skip = ' ';
my $sr_group = $saved->{$name};
my $fields = [
[ $skip ],
[ ' Pattern', ],
lib/App/DBBrowser/GetContent/Filter/SearchAndReplace.pm view on Meta::CPAN
push @$fields,
[ $skip ],
[ $c . ' Pattern', $sr_single->{pattern} ],
[ $c . ' Replacement', $sr_single->{replacement} ],
[ $c . ' Modifiers', $sr_single->{modifiers} ],
[ $skip ],
[ ' Pattern', ],
[ ' Replacement', ],
[ ' Modifiers', ];
}
my $info_fmt = "$prompt\n\nName: \"%s\"\nCode: %s\n";
my $code_str = join "\n" . ( ' ' x 6 ), _stringified_sr_group( $sr_group );
my $info = sprintf $info_fmt, $name, $code_str;
# Readline
my $new_name = $tr->readline(
'Confirm name: ',
{ info => $info, default => $name, history => [] }
);
if ( ! length $new_name ) {
return;
}
my $old_code_str = join "\n" . ( ' ' x 6 ), _stringified_sr_group( $sr_group );
$info = sprintf $info_fmt, $new_name, $old_code_str;
# Fill_form
my $form = $tf->fill_form(
$fields,
{ prompt => "Edit \"$new_name\":", info => $info, confirm => $sf->{i}{_confirm},
back => $sf->{i}{_back} . ' ' }
);
if ( ! defined $form ) {
return;
}
my $new_sr_group = [ $sf->__from_form_to_sr_group_data( $form ) ];
if ( ! @$new_sr_group ) {
return;
}
if ( $new_name ne $name ) {
lib/App/DBBrowser/GetContent/Filter/SearchAndReplace.pm view on Meta::CPAN
}
$saved->{$new_name} = [ @$new_sr_group ];
return 1;
}
sub __remove_saved {
my ( $sf, $saved ) = @_;
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my @pre = ( undef );
my $prompt = 'Remove "search & replace":';
my $menu = [ @pre, map { '- ' . $_ } sort { $a cmp $b } keys %$saved ];
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, index => 1, undef => ' <=', prompt => $prompt }
);
if ( ! defined $idx || ! defined $menu->[$idx] ) {
return;
}
my $name = $menu->[$idx] =~ s/^- //r;
my $sr_group = $saved->{$name};
my $code_str = join "\n" . ( ' ' x 6 ), _stringified_sr_group( $sr_group );
my $info_fmt = "$prompt\n\nName: \"%s\"\nCode: %s\n";
my $info = sprintf $info_fmt, $name, $code_str;
my ( $no, $yes ) = ( '- NO', '- YES' );
$menu = [ undef, $no, $yes ];
# Choose
$idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, prompt => "Remove \"$name\"?", index => 1, undef => ' <=', info => $info }
);
if ( ! defined $idx || ! defined $menu->[$idx] ) {
return;
}
elsif ( $menu->[$idx] eq $yes ) {
delete $saved->{$name};
return 1;
}
else {
return;
lib/App/DBBrowser/GetContent/Parse.pm view on Meta::CPAN
require Text::CSV_XS;
my $csv = Text::CSV_XS->new( $options ) or die Text::CSV_XS->error_diag();
$csv->callbacks( error => sub {
my ( $code, $str, $pos, $rec, $fld ) = @_;
if ( $code == 2012 ) {
# no warnings for end of data.
# 2012 "EOF - End of data in parsing input stream"
}
else {
my $error_input = $csv->error_input() // 'No Error Input defined.';
my $prompt = "Error Input:";
$error_input =~ s/\R/ /g;
my $info = "Close with ENTER\nText::CSV_XS\n$code $str\nrecord:$rec field:$fld position:$pos\n";
$tc->choose(
[ line_fold( $error_input, { join => 0 } ) ],
{ info => $info, prompt => $prompt }
);
$ax->print_sql_info( $info );
return;
}
} );
my $rows_of_cols = $csv->getline_all( $fh );
$sql->{insert_args} = $rows_of_cols;
return 1;
}
lib/App/DBBrowser/GetContent/Parse.pm view on Meta::CPAN
sub parse_with_template {
my ( $sf, $sql, $fh ) = @_;
my $ax = App::DBBrowser::Auxil->new( $sf->{i}, $sf->{o}, $sf->{d} );
my $tf = Term::Form->new( $sf->{i}{tf_default} );
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my $old_idx = 0;
IRS: while ( 1 ) {
my $prompt = 'Choose the input record separator:';
my @irs = ( "\\n", "\\r", "\\r\\n" );
my $reparse = ' Reparse';
my @pre = ( undef );
my $menu = [ @pre, map( ' "' . $_ . '"', @irs ), $reparse ];
my $info = "Parse mode: Template\n";
# Choose
my $idx = $tc->choose(
$menu,
{ prompt => $prompt, index => 1, default => $old_idx, layout => 2, undef => ' <=', clear_screen => 1, info => $info }
);
$ax->print_sql_info( $info );
if ( ! $idx ) {
return;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $old_idx == $idx && ! $ENV{TC_RESET_AUTO_UP} ) {
$old_idx = 0;
next IRS;
}
lib/App/DBBrowser/GetContent/Parse.pm view on Meta::CPAN
seek $fh, 0, 0;
my @rows = grep { ! /^\s+\z/ } <$fh>;
chomp @rows;
my $fields_set = [ [ 'Col count', ], [ 'Sep width', ], ];
SETTINGS: while ( 1 ) {
my $info = $sf->__print_template_info( \@rows, 7 + @$fields_set );
# Fill_form
my $form_set = $tf->fill_form(
$fields_set,
{ info => $info, prompt => 'Settings:', confirm => $sf->{i}{confirm}, back => $sf->{i}{back} . ' ' }
);
$ax->print_sql_info( $info );
if ( ! $form_set ) {
next IRS;
}
my $number_of_columns = $form_set->[0];
my $separator_width = $form_set->[1];
my $prompt;
if ( ! defined $number_of_columns->[1] || $number_of_columns->[1] !~ /^[1-9][0-9]*\z/ ) { ## defined
$prompt = "'$number_of_columns->[0]' requires a value of 1 or greater!";
}
if ( ! length $separator_width->[1] ) {
$separator_width->[1] = 0;
}
if ( $separator_width->[1] !~ /^(?:0|[1-9][0-9]*)\z/ ) {
$prompt = "'$separator_width->[0]' requires a value of 0 or greater!";
}
if ( $prompt ) {
my $info = $sf->__print_template_info( \@rows, 6 );
$tc->choose(
[ 'Press ENTER' ],
{ info => $info, prompt => $prompt }
);
$ax->print_sql_info( $info );
@$fields_set = @$form_set;
next SETTINGS;
}
my $col_count = $number_of_columns->[1];
my $col_sep_w = $separator_width->[1];
my $col_names = [ map { 'c' . $_ } 1 .. $col_count ];
my $fields = [ map { [ $_, ] } @$col_names ];
$fields->[-1][1] = '*';
COL_WIDTHS: while ( 1 ) {
my $info = $sf->__print_template_info( \@rows, 7 + $col_count );
my $prompt = 'Separator width: ' . $col_sep_w;
$prompt .= "\n". 'Column widths:';
# Fill_form
my $form = $tf->fill_form(
$fields,
{ info => $info, prompt => $prompt, confirm => $sf->{i}{_confirm}, back => $sf->{i}{_back} . ' ' }
);
$ax->print_sql_info( $info );
if ( ! $form ) {
@$fields_set = @$form_set;
next SETTINGS;
}
my @values;
for my $field ( @$form ) {
my ( $field_name, $field_value ) = @$field;
my ( $valid_regex, $error_message );
if ( $field_name eq $form->[-1][0] ) {
$valid_regex = qr/^(?:\*|[1-9][0-9]*)\z/;
$error_message = " requires * or a value of 1 or greater!";
}
else {
$valid_regex = qr/^[1-9][0-9]*\z/;
$error_message = " requires a value of 1 or greater!";
}
if ( ! defined $field_value || $field_value !~ $valid_regex ) { ## defined
$prompt = "'$field_name' " . $error_message;
my $info = $sf->__print_template_info( \@rows, 6 );
$tc->choose(
[ 'Press ENTER' ],
{ info => $info, prompt => $prompt, info => $info }
);
$ax->print_sql_info( $info );
@$fields = @$form;
next COL_WIDTHS;
}
push @values, $field_value;
}
$prompt = 'Remove leading spaces?';
my ( $no, $yes ) = ( '- NO', '- YES' );
$info = $sf->__print_template_info( \@rows, 8 );
# Choose
my $remove_leading_spaces = $tc->choose(
[ undef, $no, $yes ],
{ info => $info, prompt => $prompt, undef => $sf->{i}{_back}, layout => 2 }
);
$ax->print_sql_info( $info );
if ( ! defined $remove_leading_spaces ) {
next COL_WIDTHS;
}
my $template = join( 'x' x $col_sep_w, map { 'A' . $_ } @values );
my $rows_of_cols = [];
if ( ! eval {
seek $fh, 0, 0;
if ( $remove_leading_spaces eq $yes ) {
lib/App/DBBrowser/GetContent/Parse.pm view on Meta::CPAN
if ( ! defined $book ) {
if ( ! eval {
$book = Spreadsheet::Read::ReadData( $file_fs, cells => 0, attr => 0, rc => 1, strip => 0 );
1 }
) {
die "Spreadsheet::Read: $@";
}
if ( ! defined $book ) {
$tc->choose(
[ 'Press ENTER' ],
{ prompt => 'No Book in ' . decode( 'locale_fs', $file_fs ) . '!' }
);
return;
}
}
my $sheet_count = @$book - 1; # first sheet in $book contains meta info
if ( $sheet_count == 0 ) {
$tc->choose(
[ 'Press ENTER' ],
{ prompt => 'No Sheets in ' . decode( 'locale_fs', $file_fs ) . '!' }
);
return;
}
my $sheet_idx;
if ( $sheet_count == 1 ) {
$sheet_idx = 1;
}
else {
$source->{saved_book} = $book; # save book if more than one sheet
my @sheets = map { '- ' . ( length $book->[$_]{label} ? $book->[$_]{label} : 'sheet_' . $_ ) } 1 .. $#$book;
my @pre = ( undef );
my $menu = [ @pre, @sheets ];
SHEET: while ( 1 ) {
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, prompt => 'Choose a sheet', index => 1, default => $source->{old_idx_sheet},
undef => ' <=' }
);
if ( ! defined $idx || ! defined $menu->[$idx] ) {
return;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $source->{old_idx_sheet} == $idx && ! $ENV{TC_RESET_AUTO_UP} ) {
$source->{old_idx_sheet} = 0;
next SHEET;
}
$source->{old_idx_sheet} = $idx;
}
$sheet_idx = $idx - @pre + 1;
last SHEET;
}
}
# if ( $book->[$sheet_idx]{maxrow} == 0 ) { # works for some file formats; catch empty sheets later ##
# my $sheet = length $book->[$sheet_idx]{label} ? $book->[$sheet_idx]{label} : 'sheet_' . $_;
# $tc->choose(
# [ 'Press ENTER' ],
# { prompt => $sheet . ': Empty Sheet!' }
# );
# return 1;
# }
$sql->{insert_args} = [ Spreadsheet::Read::rows( $book->[$sheet_idx] ) ];
if ( ! -T $file_fs && length $book->[$sheet_idx]{label} ) {
$source->{sheet_name} = $book->[$sheet_idx]{label};
}
return 1;
}
lib/App/DBBrowser/GetContent/Source.pm view on Meta::CPAN
my $aoa = [];
my $col_names;
if ( $stmt_type eq 'Create_Table' ) {
my $col_count = $sf->{o}{insert}{max_cols_plain} || 25; ##
my $width = length $col_count;
my $info = 'CREATE TABLE';
my $fields = [ map { [ sprintf( "%*d", $width, $_ ), '' ] } 1 .. $col_count ];
# Fill_form
my $form = $tf->fill_form(
$fields,
{ info => $info, prompt => 'Column names:', confirm => $confirm, back => $back . ' ' }
);
if ( ! $form ) {
return;
}
$col_names = [ map { $_->[1] } grep { length $_->[1] } @$form ]; # not quoted
unshift @$aoa, $col_names;
}
else {
$col_names = $sql->{insert_col_names};
}
lib/App/DBBrowser/GetContent/Source.pm view on Meta::CPAN
my $menu = [ @pre, $add ];
my $info = $sf->__get_read_info( $aoa );
my $choice;
if ( $stmt_type eq 'Insert' && ! $count ) {
$choice = $add;
}
else {
# Choose
$choice = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_h}}, info => $info, prompt => '', default => $default }
);
$ax->print_sql_info( $info );
if ( ! defined $choice ) {
if ( $stmt_type eq 'Create_Table' && @$aoa == 1 ) {
next COL_BY_COL;
}
elsif ( $stmt_type eq 'Insert' && @$aoa == 0 ) {
return;
}
else {
lib/App/DBBrowser/GetContent/Source.pm view on Meta::CPAN
$sql->{insert_args} = $aoa;
return 1;
}
}
elsif ( $choice eq $add ) {
my $info = $sf->__get_read_info( $aoa );
my $fields = [ map { [ $_, ] } @$col_names ];
# Fill_form
my $data = $tf->fill_form(
$fields,
{ info => $info, confirm => $confirm, back => $back . ' ', prompt => 'Enter Data:' }
);
$ax->print_sql_info( $info );
if ( ! defined $data ) {
if ( ! @$aoa && $stmt_type eq 'Create_Table' ) {
next COL_BY_COL;
}
$default = 0;
}
else {
if ( $sf->{o}{insert}{empty_to_null_plain} ) {
lib/App/DBBrowser/Options.pm view on Meta::CPAN
CONFIG_PLUGIN: while ( 1 ) {
if ( @$chosen_plugins == 1 ) {
my $plugin = $chosen_plugins->[0];
my $groups = $op_mn->groups( $plugin );
$sf->config_groups( $groups, $plugin );
last CONFIG_PLUGIN;
}
else {
my @pre = ( undef );
my $menu = [ @pre, map { '- ' . $_ } @$chosen_plugins ];
my $prompt = 'Configure Plugins';
# Choose
my $config_idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, prompt => $prompt, index => 1, default => $config_old_idx, undef => $sf->{i}{_back} }
);
if ( ! $config_idx ) {
return;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $config_old_idx == $config_idx && ! $ENV{TC_RESET_AUTO_UP} ) {
$config_old_idx = 0;
next CONFIG_PLUGIN;
}
$config_old_idx = $config_idx;
lib/App/DBBrowser/Options.pm view on Meta::CPAN
my $op_mn = App::DBBrowser::Options::Menus->new( $sf->{i}, $sf->{o} );
my $op_rw = App::DBBrowser::Options::ReadWrite->new( $sf->{i}, $sf->{o} );
my $driver = '';
if ( $plugin ) {
my $plugin_full_name = "App::DBBrowser::DB::$plugin";
eval "require $plugin_full_name" or die $@;
my $plugin = $plugin_full_name->new( $sf->{i}, $sf->{o} );
$driver = $plugin->get_db_driver();
}
my $lo = $op_rw->read_config_file( $driver, $plugin );
my $prompt = '';
my $info;
my @pre = ( undef );
if ( $plugin ) {
$info = 'Configure ' . $plugin;
$prompt = $info;
}
else {
#$prompt = 'Your choice:';
}
my $grp_old_idx = 0;
GROUP: while( 1 ) {
my ( $group, $group_prompt );
if ( @$groups == 1 ) {
$group = $groups->[0]{name};
$group_prompt = $groups->[0]{text};
}
else {
my $menu = [ @pre, map( $_->{text}, @$groups ) ];
# Choose
my $grp_idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, prompt => $prompt, index => 1, default => $grp_old_idx, undef => ' <=' }
);
if ( ! defined $grp_idx || ! defined $menu->[$grp_idx] ) {
$op_rw->write_config_file( $lo, $plugin );
return;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $grp_old_idx == $grp_idx && ! $ENV{TC_RESET_AUTO_UP} ) {
$grp_old_idx = 0;
next GROUP;
}
$grp_old_idx = $grp_idx;
}
$group = $groups->[$grp_idx-@pre]{name};
$group_prompt = $groups->[$grp_idx-@pre]{text};
};
if ( length $group_prompt ) {
$group_prompt = $group_prompt =~ s/^- //r . ':';
}
my $sub_groups = $op_mn->sub_groups( $group, $driver );
my $sub_group_old_idx = 0;
OPTION: while ( 1 ) {
my ( $section, $sub_group );
if ( @$sub_groups == 1 ) {
$section = $sub_groups->[0]{section};
$sub_group = $sub_groups->[0]{name};
}
else {
my @pre = ( undef );
my $menu = [ @pre, map( $_->{text}, @$sub_groups ) ];
# Choose
my $sub_group_idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => $group_prompt,
index => 1, default => $sub_group_old_idx, undef => ' <=' } ##
);
if ( ! $sub_group_idx ) {
if ( @$groups == 1 ) {
$op_rw->write_config_file( $lo, $plugin );
return;
}
next GROUP;
}
if ( $sf->{o}{G}{menu_memory} ) {
lib/App/DBBrowser/Options.pm view on Meta::CPAN
sub __display_info {
my ( $sf ) = @_;
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my $app_dir = $sf->{i}{app_dir};
eval { $app_dir = decode( 'locale', $app_dir ) };
my $info = 'db-browser' . "\n\n";
$info .= 'Version: ' . $main::VERSION . "\n\n";
$info .= 'Path: ' . catfile( $RealBin, $RealScript ) . "\n\n";
$info .= 'App-Dir: ' . $app_dir . "\n";
$tc->choose( [ ' << ' ], { prompt => $info, color => 1, margin => [ 1, 1, 1, 1 ] } );
}
1;
__END__
lib/App/DBBrowser/Options/Menus.pm view on Meta::CPAN
sub group_connect {
my ( $sf, $info, $lo, $section, $sub_group, $driver ) = @_;
my $sub_menu_required_fields = [
[ 'host_required', "- Host required", [ $no, $yes ] ],
[ 'port_required', "- Port required", [ $no, $yes ] ],
[ 'user_required', "- User required", [ $no, $yes ] ],
[ 'pass_required', "- Password required", [ $no, $yes ] ],
];
my $items_login_data = [
{ name => 'host', prompt => "- Host" },
{ name => 'port', prompt => "- Port" },
{ name => 'user', prompt => "- User" },
];
my $sub_menu_env_variables = [
[ 'use_dbi_host', "- Use DBI_HOST", [ $no, $yes ] ],
[ 'use_dbi_port', "- Use DBI_PORT", [ $no, $yes ] ],
[ 'use_dbi_user', "- Use DBI_USER", [ $no, $yes ] ],
[ 'use_dbi_pass', "- Use DBI_PASS", [ $no, $yes ] ],
];
my $items_read_attributes = [
{ name => 'LongReadLen', text => "- LongReadLen" },
];
lib/App/DBBrowser/Options/Menus.pm view on Meta::CPAN
[ 'odbc_utf8_on', "- odbc_utf8_on", [ $no, $yes ] ],
[ 'odbc_ignore_named_placeholders', "- odbc_ignore_named_placeholders", [ $no, $yes ] ],
#[ 'odbc_array_operations', "- odbc_array_operations", [ $no, $yes ] ];
}
elsif ( $driver eq 'DuckDB' ) {
$sub_menu_required_fields = [];
$items_login_data = [];
$sub_menu_env_variables = [];
}
if ( $sub_group eq '_required_fields' ) {
my $prompt = 'Required Fields:';
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu_required_fields, $prompt );
}
elsif ( $sub_group eq '_login_data' ) {
my $prompt = 'Login Data:';
$sf->__group_readline( $info, $lo, $section, $items_login_data, $prompt );
}
elsif ( $sub_group eq '_env_variables' ) {
my $prompt = 'Environment Variables:';
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu_env_variables, $prompt );
}
elsif ( $sub_group eq '_read_attributes' ) {
my $prompt = 'Read Attributes:';
$sf->__group_readline( $info, $lo, $section, $items_read_attributes, $prompt );
}
elsif ( $sub_group eq '_set_attributes' ) {
my $prompt = 'Set Attributes:';
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu_set_attributes, $prompt );
}
else {
die "connect: unknown sub_group $sub_group";
}
return;
}
sub group_extensions {
my ( $sf, $info, $lo, $section, $sub_group ) = @_;
if ( $sub_group eq '_e_table' ) {
my $prompt = 'Extend tables menu:';
my $sub_menu = [
[ 'm_derived', "- Add subquery", [ $no, $yes ] ],
[ 'm_cte', "- Add cte", [ $no, $yes ] ],
[ 'join', "- Add join", [ $no, $yes ] ],
[ 'union', "- Add union", [ $no, $yes ] ],
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_e_join' ) {
my $prompt = 'Extend join menu:';
my $sub_menu = [
[ 'j_derived', "- Add subquery", [ $no, $yes ] ],
[ 'j_cte', "- Add cte", [ $no, $yes ] ],
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_e_union' ) {
my $prompt = 'Extend union menu:';
my $sub_menu = [
[ 'u_derived', "- Add subquery", [ $no, $yes ] ],
[ 'u_cte', "- Add cte", [ $no, $yes ] ],
[ 'u_edit_stmt', "- Edit statement", [ $no, $yes ] ],
[ 'u_parentheses', "- Parentheses", [ $no, $yes ] ],
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_e_expressions' ) {
my $prompt = 'Extended expressions:';
my $sub_menu = [
[ 'extended_cols', "- Exdented columns", [ $no, $yes ] ],
[ 'extended_values', "- Exdented values", [ $no, $yes ] ],
[ 'extended_args', "- Exdented arguments", [ $no, $yes ] ],
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_e_write_access' ) {
my $prompt = 'Write access: ';
my $sub_menu = [
[ 'insert_into', "- Insert records", [ $no, $yes ] ],
[ 'update', "- Update records", [ $no, $yes ] ],
[ 'delete', "- Delete records", [ $no, $yes ] ],
[ 'create_table', "- Create table", [ $no, $yes ] ],
[ 'drop_table', "- Drop table", [ $no, $yes ] ],
[ 'create_view', "- Create view", [ $no, $yes ] ],
[ 'drop_view', "- Drop view", [ $no, $yes ] ],
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
else {
die "extensions: unknown sub_group $sub_group";
}
return;
}
sub group_sql_settings {
my ( $sf, $info, $lo, $section, $sub_group, $driver ) = @_;
if ( $sub_group eq '_meta' ) {
my $prompt = 'System data ';
my $sub_menu = [
[ 'metadata', "- Show system DB/schemas/tables", [ $no, $yes ] ]
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq 'operators' ) {
my $prompt = 'Choose operators';
my $avail_operators = [
" = ", " != ", " <> ", " < ", " > ", " >= ", " <= ",
"REGEXP", "REGEXP_i", "NOT REGEXP", "NOT REGEXP_i", "LIKE", "NOT LIKE",
"IS NULL", "IS NOT NULL", "IN", "NOT IN", "BETWEEN", "NOT BETWEEN",
"ANY", "ALL",
];
$sf->__choose_a_subset_wrap( $info, $lo, $section, $sub_group, $avail_operators, $prompt );
}
elsif ( $sub_group eq '_add_aliases' ) {
my $prompt = 'Add alias:';
my $sub_menu = [
[ 'complex_cols_select', "- Functions/Subqueries in select", [ 'NO', undef, 'ASK', undef ] ],
[ 'tables_in_join', "- Tables in join", [ undef, 'AUTO', undef, 'ASK/AUTO' ] ],
[ 'join_columns', "- Non-unique columns in join", [ 'NO', 'AUTO', 'ASK', 'ASK/AUTO' ] ],
[ 'derived_table', "- Derived table", [ 'NO', 'AUTO', 'ASK', 'ASK/AUTO' ] ],
[ 'ordinary_table', "- Ordinary table", [ 'NO', 'AUTO', 'ASK', 'ASK/AUTO' ] ],
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_aliases_in_clauses' ) {
my $prompt = 'Use aliases in: ';
my $sub_menu = [
[ 'use_in_group_by', "- Group by", [ $no, $yes ] ],
[ 'use_in_having', "- Having", [ $no, $yes ] ],
[ 'use_in_order_by', "- Order by", [ $no, $yes ] ],
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_sql_identifiers' ) {
my $prompt = 'Your choice: ';
my $sub_menu = [
[ 'qualified_table_name', "- Qualified table names", [ $no, $yes ] ],
[ 'quote_tables', "- Quote table names", [ $no, $yes ] ],
[ 'quote_columns', "- Quote column names", [ $no, $yes ] ],
];
if ( $driver eq 'Firebird' ) {
shift @$sub_menu;
}
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_view_name_prefix' ) {
my $items = [
{ name => 'view_name_prefix', prompt => "View name prefix" },
];
my $prompt = 'Set a view name prefix';
$sf->__group_readline( $info, $lo, $section, $items, $prompt );
}
elsif ( $sub_group eq '_other_sql_settings' ) {
my $prompt = 'Your choice: ';
my $sub_menu = [
[ 'edit_sql_menu_sq', "- Subqueries created with 'SQL Menu': Allow editing.", [ $no, $yes ] ],
];
if ( $driver eq 'Pg' ) {
push @$sub_menu, [ 'pg_autocast', "- Pg: Convert to 'text' automatically when required.", [ $no, $yes ] ];
}
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
else {
die "sql_settings: unknown sub_group $sub_group";
}
return;
}
sub group_create_table {
my ( $sf, $info, $lo, $section, $sub_group ) = @_;
if ( $sub_group eq '_enable_ct_opt' ) {
my $prompt = 'Activate options';
my $sub_menu = [
[ 'option_ai_column_enabled', "- Offer auto increment column", [ $no, $yes ] ],
[ 'data_type_guessing', "- Data type guessing", [ $no, $yes ] ],
[ 'encode_for_data_type_guessing', "- Encode for data type guessing", [ $no, $yes ] ],
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_add_ct_fields' ) {
my $prompt = 'Add fields';
my $sub_menu = [
[ 'table_constraint_rows', "- Table constraint fields", [ 0 .. 9 ] ],
[ 'table_option_rows', "- Table option fields", [ 0 .. 9 ] ],
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_default_ai_column_name' ) {
my $items = [
{ name => 'default_ai_column_name', prompt => "Default primary key auto increment column name" },
];
my $prompt = 'Set a default auto increment column name';
$sf->__group_readline( $info, $lo, $section, $items, $prompt );
}
else {
die "create_table: unknown sub_group $sub_group";
}
return;
}
sub group_output {
my ( $sf, $info, $lo, $section, $sub_group ) = @_;
if ( $sub_group eq '_binary_filter' ) {
my $prompt = 'How to print arbitrary binray data';
my $sub_menu = [
[ 'binary_filter', "- Binary filter", [ $no, 'BNRY', 'Hexadecimal' ] ]
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_squash_spaces' ) {
my $prompt = 'Remove leading and trailing spaces and squash consecutive spaces';
my $sub_menu = [
[ 'squash_spaces', "- Squash spaces", [ $no, $yes ] ]
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_set_string' ) {
my $items = [
{ name => 'undef', prompt => "Show undefined fields as" },
];
my $prompt = 'Undef string';
$sf->__group_readline( $info, $lo, $section, $items, $prompt );
}
elsif ( $sub_group eq '_color' ) {
my $prompt = '"ANSI color escapes"';
my $sub_menu = [
[ 'color', "- ANSI color escapes", [ $no, $yes ] ]
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq 'trunc_fract_first' ) {
my $prompt = 'If the terminal is not wide enough:';
my $sub_menu = [
[ 'trunc_fract_first', "- First step: truncate fraction of numbers", [ $no, $yes ] ]
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_base_indent' ) {
my $prompt = 'Set the indentation width for SQL substatements';
my $sub_menu = [
[ 'base_indent', "- Indentation", [ 0, 1, 2, 3, 4 ] ]
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq 'tab_width' ) {
my $digits = 3;
my $prompt = 'Set the tab width ';
$sf->__choose_a_number_wrap( $info, $lo, $section, $sub_group, $prompt, $digits, 0 );
}
elsif ( $sub_group eq '_pad_row_edges' ) {
my $prompt = '"Pad row edges"';
my $sub_menu = [
[ 'pad_row_edges', "- Pad row edges with a space.", [ $no, $yes ] ]
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_expand_rows' ) {
my $prompt = 'Your choice: ';
my $sub_menu = [
[ 'table_expand', "- Expand table rows", [ $no, $yes ] ],
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_expanded_line_spacing' ) {
my $prompt = 'Your choice: ';
my $sub_menu = [
[ 'expanded_line_spacing', "- Blank line between columns when a row is expanded.", [ $no, $yes ] ],
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq 'expanded_max_width' ) {
my $digits = 3;
my $prompt = 'Maximum width of expanded table rows';
$sf->__choose_a_number_wrap( $info, $lo, $section, $sub_group, $prompt, $digits, 0 );
}
elsif ( $sub_group eq 'col_trim_threshold' ) {
my $digits = 3;
my $prompt = 'Column trim threshold ';
$sf->__choose_a_number_wrap( $info, $lo, $section, $sub_group, $prompt, $digits, 0 );
}
elsif ( $sub_group eq '_db2_encoding' ) {
my $items = [
{ name => 'db2_encoding', prompt => "DB2 application code set" },
];
my $prompt = 'Set the DB2 application code set';
$sf->__group_readline( $info, $lo, $section, $items, $prompt );
}
else {
die "output: unknown sub_group $sub_group";
}
return;
}
sub group_import {
my ( $sf, $info, $lo, $section, $sub_group ) = @_;
if ( $sub_group eq '_data_source_type' ) {
my $prompt = 'Data source options';
my $sub_menu = [
[ 'data_source_create_table', "- Data source \"Create table\"", [ 'plain', 'file', 'menu' ], ],
[ 'data_source_insert', "- Data source \"Insert into\"", [ 'plain', 'file', 'menu' ], ],
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq 'max_cols_plain' ) {
my $digits = 2;
my $prompt = 'Create table, source plain.' . "\n" . 'Maximum columns:';
$sf->__choose_a_number_wrap( $info, $lo, $section, $sub_group, $prompt, $digits, 1 );
}
elsif ( $sub_group eq '_parse_file' ) {
my $prompt = 'How to parse input files';
my $sub_menu = [
[ 'parse_mode_input_file', "- Use", [ 'Text::CSV', 'split', 'Template', 'Spreadsheet::Read' ] ],
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_csv_in_char' ) {
my $items = [
{ name => 'sep_char', prompt => "sep_char " },
{ name => 'quote_char', prompt => "quote_char " },
{ name => 'escape_char', prompt => "escape_char" },
{ name => 'eol', prompt => "eol " },
{ name => 'comment_str', prompt => "comment_str" },
];
my $prompt = 'Text::CSV_XS options a';
$sf->__group_readline( $info, $lo, $section, $items, $prompt );
}
elsif ( $sub_group eq '_csv_in_options' ) {
my $prompt = 'Text::CSV_XS options b';
my $sub_menu = [
[ 'allow_loose_escapes', "- allow_loose_escapes", [ $no, $yes ] ],
[ 'allow_loose_quotes', "- allow_loose_quotes", [ $no, $yes ] ],
[ 'allow_whitespace', "- allow_whitespace", [ $no, $yes ] ],
[ 'blank_is_undef', "- blank_is_undef", [ $no, $yes ] ],
[ 'binary', "- binary", [ $no, $yes ] ],
[ 'decode_utf8', "- decode_utf8", [ $no, $yes ] ],
[ 'empty_is_undef', "- empty_is_undef", [ $no, $yes ] ],
[ 'skip_empty_rows', "- skip_empty_rows", [ $no, $yes ] ],
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_split_config' ) {
my $items = [
{ name => 'field_sep', prompt => "Field separator " },
{ name => 'field_l_trim', prompt => "Trim field left " },
{ name => 'field_r_trim', prompt => "Trim field right " },
{ name => 'record_sep', prompt => "Record separator " },
{ name => 'record_l_trim', prompt => "Trim record left " },
{ name => 'record_r_trim', prompt => "Trim record right" },
];
my $prompt = 'Config \'split\' mode';
$sf->__group_readline( $info, $lo, $section, $items, $prompt );
}
elsif ( $sub_group eq '_input_filter' ) {
my $prompt = 'Enable input filter';
my $sub_menu = [
[ 'enable_input_filter', "- Enable input filter", [ $no, $yes ] ]
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_empty_to_null' ) {
my $prompt = 'Enable "Empty to NULL":';
my $sub_menu = [
[ 'empty_to_null_plain', "- Source type 'plain'", [ $no, $yes ] ],
[ 'empty_to_null_file', "- Source type 'file'", [ $no, $yes ] ],
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_file_encoding_in' ) {
my $items = [
{ name => 'file_encoding', prompt => "Input file encoding" },
];
my $prompt = 'Encoding of input data text files';
$sf->__group_readline( $info, $lo, $section, $items, $prompt );
}
elsif ( $sub_group eq 'history_dirs' ) {
my $digits = 2;
my $prompt = 'Number of saved dirs: ';
$sf->__choose_a_number_wrap( $info, $lo, $section, $sub_group, $prompt, $digits, 1 );
}
elsif ( $sub_group eq '_file_filter' ) {
my $items = [
{ name => 'file_filter', prompt => "File filter glob pattern" },
];
my $prompt = 'Set the glob pattern for the file filter';
$sf->__group_readline( $info, $lo, $section, $items, $prompt );
}
elsif ( $sub_group eq '_show_hidden_files' ) {
my $prompt = 'Show hidden files';
my $sub_menu = [
[ 'show_hidden_files', "- Show hidden files", [ $no, $yes ] ]
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
else {
die "import: unknown sub_group $sub_group";
}
return;
}
sub group_export {
my ( $sf, $info, $lo, $section, $sub_group ) = @_;
if ( $sub_group eq 'export_dir' ) {
my $prompt = 'Select the destination folder for data exported as CSV files.';
$sf->__choose_a_directory_wrap( $info, $lo, $section, $sub_group, $prompt );
}
elsif ( $sub_group eq '_exported_files' ) {
my $prompt = 'Data export to CSV files';
my $sub_menu = [
[ 'add_extension', "- Add automatically '.csv'-extension", [ $no, $yes ] ],
[ 'default_filename', "- Table name is default file name", [ $no, $yes ] ]
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_file_encoding_out' ) {
my $items = [
{ name => 'file_encoding', prompt => "Encoding CSV file" },
];
my $prompt = 'Data to CSV-files';
$sf->__group_readline( $info, $lo, $section, $items, $prompt );
}
elsif ( $sub_group eq '_csv_out_char' ) {
my $items = [
{ name => 'sep_char', prompt => "sep_char " },
{ name => 'quote_char', prompt => "quote_char " },
{ name => 'escape_char', prompt => "escape_char" },
{ name => 'eol', prompt => "eol " },
{ name => 'undef_str', prompt => "undef_str" },
];
my $prompt = 'Text::CSV_XS write options a';
$sf->__group_readline( $info, $lo, $section, $items, $prompt );
}
elsif ( $sub_group eq '_csv_out_options' ) {
my $prompt = 'Text::CSV_XS write options b';
my $sub_menu = [
[ 'always_quote', "- always_quote", [ $no, $yes ] ],
[ 'binary', "- binary", [ $no, $yes ] ],
[ 'escape_null', "- escape_null", [ $no, $yes ] ],
[ 'quote_binary', "- quote_binary", [ $no, $yes ] ],
[ 'quote_empty', "- quote_empty", [ $no, $yes ] ],
[ 'quote_space', "- quote_space", [ $no, $yes ] ],
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
else {
die "export: unknown sub_group $sub_group";
}
return;
}
sub group_misc {
my ( $sf, $info, $lo, $section, $sub_group, $driver ) = @_;
if ( $sub_group eq '_search' ) {
my $prompt = 'Your choice: ';
my $sub_menu = [
[ 'search', "- Row filter", [ 'disabled', 'case insensitive', 'case sensitive' ] ]
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_warnings' ) {
my $prompt = '"Disable/Enable warnings"';
my $sub_menu = [
[ 'warnings_table_print', "- Warnings table-print", [ $no, $yes ] ],
];
if ( $driver eq 'SQLite' ) {
push @$sub_menu, [ 'file_find_warnings', "- Warnings \"File::Find\" search", [ $no, $yes ] ];
}
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq 'progress_bar' ) {
my $digits = 7;
my $prompt = 'Set the threshold for the progress bar ';
$sf->__choose_a_number_wrap( $info, $lo, $section, $sub_group, $prompt, $digits, 0 );
}
else {
die "misc: unknown sub_group: $sub_group";
}
return;
}
sub group_global {
my ( $sf, $info, $lo, $section, $sub_group ) = @_;
if ( $sub_group eq '_menu_memory' ) {
my $prompt = 'Your choice: ';
my $sub_menu = [
[ 'menu_memory', "- Menu memory", [ $no, $yes ] ],
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
elsif ( $sub_group eq '_mouse' ) {
my $prompt = 'Your choice: ';
my $sub_menu = [
[ 'mouse', "- Mouse mode", [ $no, $yes ] ]
];
$sf->__settings_menu_wrap( $info, $lo, $section, $sub_menu, $prompt );
}
else {
die "global: unknown sub_group: $sub_group";
}
return;
}
sub group_select_plugins {
my ( $sf, $info, $lo, $section, $sub_group ) = @_;
if ( $sub_group eq 'plugins' ) {
my %installed_plugins;
for my $dir ( @INC ) {
my $glob_pattern = catfile $dir, 'App', 'DBBrowser', 'DB', '*.pm';
map { $installed_plugins{( fileparse $_, '.pm' )[0]}++ } glob $glob_pattern;
}
my $avail_plugins = [ sort keys %installed_plugins ];
my $prompt = 'Select plugins';
# $info = undef;
$sf->__choose_a_subset_wrap( $info, $lo, $section, $sub_group, $avail_plugins, $prompt );
}
else {
die "global: unknown sub_group: $sub_group";
}
return;
}
sub __settings_menu_wrap {
# sets the options to the index of the chosen values, not to the values itself
my ( $sf, $info, $lo, $section, $sub_menu, $prompt ) = @_;
my $tu = Term::Choose::Util->new( $sf->{i}{tcu_default} );
my $changed = $tu->settings_menu(
$sub_menu, $lo->{$section},
{ info => $info, prompt => $prompt, back => $sf->{i}{_back}, confirm => $sf->{i}{_confirm} }
);
}
sub __choose_a_subset_wrap {
my ( $sf, $info, $lo, $section, $opt, $available, $prompt ) = @_;
my $tu = Term::Choose::Util->new( $sf->{i}{tcu_default} );
my $current = $lo->{$section}{$opt};
$info .= "\n" if length $info;
$info .= 'Cur: ';
$info .= join( ', ', @$current ) if defined $current;
my $name = 'New: ';
# Choose_a_list
my $list = $tu->choose_a_subset(
$available,
{ info => $info, prompt => $prompt, cs_label => $name, prefix => '- ', keep_chosen => 0,
index => 0, confirm => $sf->{i}{_confirm}, back => $sf->{i}{_back}, layout => 2,
clear_screen => 1 }
);
return if ! defined $list;
return if ! @$list;
$lo->{$section}{$opt} = $list;
return;
}
sub __choose_a_number_wrap {
my ( $sf, $info, $lo, $section, $opt, $prompt, $digits, $small_first ) = @_;
my $tu = Term::Choose::Util->new( $sf->{i}{tcu_default} );
my $current = $lo->{$section}{$opt};
my $w = $digits + int( ( $digits - 1 ) / 3 ) * length $sf->{i}{info_thsd_sep};
$info .= "\n" . 'Cur: ';
$info .= sprintf( "%*s", $w, insert_sep( $current, $sf->{i}{info_thsd_sep} ) ) if defined $current;
my $name = 'New: ';
# Choose_a_number
my $choice = $tu->choose_a_number( $digits,
{ info => $info, prompt => $prompt, cs_label => $name, small_first => $small_first,
clear_screen => 1, confirm => $sf->{i}{confirm}, back => $sf->{i}{back} }
);
return if ! defined $choice;
$lo->{$section}{$opt} = $choice;
return;
}
sub __choose_a_directory_wrap {
my ( $sf, $info, $lo, $section, $opt, $prompt ) = @_;
my $tu = Term::Choose::Util->new( $sf->{i}{tcu_default} );
my $current = $lo->{$section}{$opt};
# Choose_a_directory
my $choice = $tu->choose_a_directory(
{ show_hidden => 1, info => $info, prompt => $prompt, clear_screen => 1, decoded => 1,
confirm => $sf->{i}{confirm}, back => $sf->{i}{back}, init_dir => $current }
);
return if ! defined $choice;
$lo->{$section}{$opt} = $choice;
return;
}
sub __group_readline {
my ( $sf, $info, $lo, $section, $items, $prompt ) = @_;
my $list = [ map {
[ exists $_->{prompt} ? $_->{prompt} : $_->{name}, $lo->{$section}{$_->{name}} ]
} @{$items} ];
my $tf = Term::Form->new( $sf->{i}{tf_default} );
# Fill_Form
my $new_list = $tf->fill_form(
$list,
{ info => $info, prompt => $prompt, confirm => $sf->{i}{confirm}, back => $sf->{i}{back} }
);
if ( $new_list ) {
for my $i ( 0 .. $#$items ) {
$lo->{$section}{$items->[$i]{name}} = $new_list->[$i][1];
}
}
}
lib/App/DBBrowser/Table.pm view on Meta::CPAN
my ( $class, $info, $options, $d ) = @_;
bless {
i => $info,
o => $options,
d => $d
}, $class;
}
sub browse_the_table {
my ( $sf, $sql, $return_stmt_prompt ) = @_;
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my $ax = App::DBBrowser::Auxil->new( $sf->{i}, $sf->{o}, $sf->{d} );
my $sb = App::DBBrowser::Table::Substatement->new( $sf->{i}, $sf->{o}, $sf->{d} );
$sf->{d}{stmt_types} = [ 'Select' ];
my $changed = {};
my $hidden = 'Customize:';
my ( $print_table, $select, $distinct, $where, $group_by, $having, $order_by, $limit, $offset, $export ) =
( 'Print TABLE',
'- SELECT',
'- DISTINCT',
lib/App/DBBrowser/Table.pm view on Meta::CPAN
'- GROUP BY',
'- HAVING',
'- ORDER BY',
'- LIMIT',
'- OFFSET',
' Export',
);
my @choices = ( $print_table, $select, $distinct, $where, $group_by, $having, $order_by, $limit, $offset, $export );
my @pre = ( $hidden, undef );
my $back = $sf->{i}{back};
my ( $return_statement, $hidden_print ) = ( $sf->{i}{_confirm}, $return_stmt_prompt );
if ( $return_stmt_prompt ) {
$choices[0] = $return_statement;
@pre = ( $hidden_print, undef );
$back = $sf->{i}{_back};
}
my $footer = $sf->{d}{table_origin} eq 'ordinary' ? $sf->{d}{table_key} : ucfirst $sf->{d}{table_origin};
$sf->{d}{table_footer} = " '$footer' ";
my $old_idx = 1;
CUSTOMIZE: while ( 1 ) {
my $menu = [ @pre, @choices ];
my $info = $ax->get_sql_info( $sql );
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => '', index => 1, default => $old_idx, undef => $back }
);
$ax->print_sql_info( $info );
if ( ! defined $idx || ! defined $menu->[$idx] ) {
for my $key ( keys %{$changed} ) {
if ( $changed->{$key} ) {
$changed = {};
$ax->reset_sql( $sql );
next CUSTOMIZE;
}
}
lib/App/DBBrowser/Table.pm view on Meta::CPAN
if ( $sf->{o}{export}{add_extension} && $tmp_file_name !~ /\.csv\z/i ) {
$file_name .= '.csv';
}
my $export_dir = $sf->{o}{export}{export_dir};
my $dir_fs = realpath( encode( 'locale_fs', $export_dir ) ) or die "$export_dir: $!";
my $file_fs = catfile $dir_fs, encode( 'locale_fs', $file_name );
my ( $new_name, $overwrite ) = ( '- New name', '- Overwrite' );
my $chosen;
if ( -e $file_fs ) {
my $menu;
my $prompt;
if ( -d $file_fs ) {
$prompt = 'A directory \'' . decode( 'locale_fs', $file_fs ) . '\' already exists:';
$menu = [ undef, $new_name ];
}
else {
$prompt = 'A file \'' . decode( 'locale_fs', $file_fs ) . '\' already exists:';
$menu = [ undef, $new_name, $overwrite ];
}
# Choose
$chosen = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => $prompt, keep => scalar( @$menu ) }
);
$ax->print_sql_info( $info );
if ( ! defined $chosen ) {
return;
}
elsif ( $chosen eq $new_name ) {
next FILE_NAME;
}
}
my ( $yes, $no ) = ( '- YES', '- NO' );
my $hidden;
if ( defined $chosen && $chosen eq $overwrite ) {
$hidden = 'Overwrite "' . decode( 'locale_fs', $file_fs ) . '"?';
}
else {
$hidden = 'Write data to "' . decode( 'locale_fs', $file_fs ) . '"?';
}
# Choose
my $choice = $tc->choose(
[ $hidden, undef, $yes, $no ],
{ info => $info, prompt => '', default => 1, layout => 2, undef => ' <<' }
);
$ax->print_sql_info( $info );
if ( ! defined $choice ) {
next FILE_NAME;
}
elsif ( $choice eq $hidden ) {
my $op = App::DBBrowser::Options->new( $sf->{i}, $sf->{o} );
my $op_rw = App::DBBrowser::Options::ReadWrite->new( $sf->{i}, $sf->{o} );
$op->config_groups( [ { name => 'group_export', text => "- Export" } ], $sf->{i}{plugin} );
$op_rw->read_config_file( $sf->{i}{driver}, $sf->{i}{plugin} );
lib/App/DBBrowser/Table/CommitWriteSQL.pm view on Meta::CPAN
my $sth = $dbh->prepare( $stmt );
$sth->execute();
my $col_names = $sth->{NAME};
$all_arrayref = $sth->fetchall_arrayref;
$count_affected = @$all_arrayref;
unshift @$all_arrayref, $col_names;
1 }
) {
$ax->print_error_message( $@ );
}
my $prompt = "Affected records:";
my $info = $ax->get_sql_info( $sql );
if ( @$all_arrayref > 1 ) {
my $tp = Term::TablePrint->new( $sf->{o}{table} );
if ( ! $sf->{o}{G}{warnings_table_print} ) {
local $SIG{__WARN__} = sub {};
$tp->print_table( $all_arrayref, { info => $info, prompt => $prompt, footer => $sf->{d}{table_footer} } );
}
else {
$tp->print_table( $all_arrayref, { info => $info, prompt => $prompt, footer => $sf->{d}{table_footer} } );
}
}
$ax->print_sql_info( $info, $waiting );
}
else {
die $stmt_type // 'undefined_stmt_type';
}
my $transaction;
lib/App/DBBrowser/Table/CommitWriteSQL.pm view on Meta::CPAN
if ( $stmt_type eq 'Insert' && $sf->{d}{stmt_types}[0] eq 'Create_Table' ) {
# already asked for confirmation (create table + insert data) in Create_Table
}
else {
my $commit_ok = sprintf qq( %s %s "%s"), 'EXECUTE', insert_sep( $count_affected, $sf->{i}{info_thsd_sep} ), $stmt_type;
my $menu = [ undef, $commit_ok ];
my $info = $ax->get_sql_info( $sql ); #
# Choose
my $choice = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => '', keep => scalar( @$menu ) }
);
$ax->print_sql_info( $info, $waiting );
if ( ! defined $choice || $choice ne $commit_ok ) {
return;
}
}
if ( ! eval {
my $sth = $dbh->prepare( $ax->get_stmt( $sql, $stmt_type, 'prepare' ) );
if ( $stmt_type eq 'Insert' ) {
$sth->execute( @$_ ) for @{$sql->{insert_args}};
lib/App/DBBrowser/Table/Extensions.pm view on Meta::CPAN
#my $last_idx = $#$r_data;
my $ext_argument = $sf->__choose_extension( $sql, $clause, $r_data, 'argument', $extensions, $opt );
#die if $#$r_data != $last_idx;
return $ext_argument;
}
sub enable_extended_arguments {
my ( $sf, $info ) = @_;
my $tc = Term::Choose->new( $sf->{i}{tc_default} );
my $prompt = 'Extended arguments:';
my $yes = '- YES';
# Choose
my $choice = $tc->choose(
[ undef, '- NO', $yes ],
{ %{$sf->{i}{lyt_v}}, info => $info, prompt => $prompt, undef => '<=' }
);
if ( ! defined $choice ) {
return;
}
if ( $choice eq $yes ) {
$sf->{o}{enable}{extended_args} = 1;
}
else {
$sf->{o}{enable}{extended_args} = 0;
}
lib/App/DBBrowser/Table/Extensions.pm view on Meta::CPAN
else {
my $empty;
if ( $caller eq 'column' && $clause eq 'where' ) {
$empty = 'skip'; ##
}
my @pre = ( undef );
# Choose
my $idx = $tc->choose(
[ @pre, @$extensions ],
{ %{$sf->{i}{lyt_h}}, info => $info, index => 1, default => $old_idx,
prompt => $opt->{prompt}, undef => '<<', empty => $empty }
);
$ax->print_sql_info( $info );
if ( ! $idx ) { ##
return;
}
if ( $sf->{o}{G}{menu_memory} ) {
if ( $old_idx == $idx && ! $ENV{TC_RESET_AUTO_UP} ) {
$old_idx = 0;
next EXTENSION;
}
$old_idx = $idx;
}
$extension = $extensions->[$idx-@pre];
}
my $cols = $sf->__avail_cols_in_extenstions( $sql, $clause, $extension );
if ( $extension eq $e_const ) {
my $prompt = $opt->{prompt} // 'Value: ';
# Readline
my $value = $tr->readline(
$prompt,
{ info => $info, history => $opt->{history} }
);
$ax->print_sql_info( $info );
if ( ! defined $value ) {
return if @$extensions = 1;
next EXTENSION;
}
# return if ! length $value; ##
if ( $opt->{is_numeric} ) {
if ( $opt->{is_numeric} == -1 ) {
lib/App/DBBrowser/Table/Extensions.pm view on Meta::CPAN
if ( ! defined $col_aliases ) {
return if @$extensions == 1;
next EXTENSION;
}
return $col_aliases;
}
elsif ( $extension eq $e_multi_col ) {
# Choose
my $chosen_cols = $tu->choose_a_subset(
$cols,
{ info => $info, prompt => '', layout => 1, index => 0, all_by_default => 0,
cs_label => 'Columns: ', cs_begin => '(', cs_separator => ',', cs_end => ')' }
);
$ax->print_sql_info( $info );
if ( ! defined $chosen_cols ) {
return if @$extensions == 1;
next EXTENSION;
}
return "(" . join( ",", @$chosen_cols ) . ")";
}
}
lib/App/DBBrowser/Table/Extensions/Case.pm view on Meta::CPAN
$menu = [ @pre, $end ];
}
else {
$menu = [ @pre, $when, $else, $end ];
}
$r_data->[-1] = [ 'case', @$case_parts, '' ];
my $info = $ax->get_sql_info( $sql ) . $ext->nested_func_info( $r_data );
# Choose
my $idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_h}}, info => $info, prompt => 'Your choice:', index => 1, undef => '<=' }
);
$ax->print_sql_info( $info );
if ( ! $idx ) {
if ( @bu ) {
$case_parts = pop @bu;
$r_data->[-1] = [ 'case', @$case_parts ];
$else_on = 0;
next SUBSTMT;
}
pop @$r_data;
lib/App/DBBrowser/Table/Extensions/ColAliases.pm view on Meta::CPAN
}
elsif ( $menu->[$idx] eq $rearrange ) {
$rearranged = $sf->__rearrange_columns( $sql );
next COLUMN;
}
elsif ( $menu->[$idx] eq $change_table_alias ) {
$sf->__table_alias( $sql, $table_no_alias );
next COLUMN;
}
my $chosen_col = $sql->{selected_cols}[$idx - @pre];
my $prompt = $ax->normalize_space_in_stmt( $chosen_col );
my $default = $sql->{alias}{$chosen_col} // '';
$info = $ax->get_sql_info( $sql );
# Readline
my $alias = $tr->readline(
$prompt . " as ",
{ info => $info, default => $default, history => [ 'a' .. 'z' ] }
);
$ax->print_sql_info( $info );
if ( ( $alias // '' ) eq $default ) {
next COLUMN;
}
if ( ! length $alias ) {
push @bu, { %{$sql->{alias}} };
delete $sql->{alias}{$chosen_col};
next COLUMN;
lib/App/DBBrowser/Table/Extensions/ColAliases.pm view on Meta::CPAN
my @bu_selected_cols = @{$sql->{selected_cols}};
$sql->{selected_cols} = [];
my @pre = ( undef, $sf->{i}{ok} );
my $menu = [ @pre, @bu_selected_cols ];
COLUMNS: while ( 1 ) {
my $info = $ax->get_sql_info( $sql );
# Choose
my @idx = $tc->choose(
$menu,
{ %{$sf->{i}{lyt_h}}, info => $info, prompt => 'Rearragne columns:', meta_items => [ 0 .. $#pre - 1 ], no_spacebar => [ $#pre ],
include_highlighted => 2, index => 1 }
);
$ax->print_sql_info( $info );
if ( ! $idx[0] ) {
if ( @{$sql->{selected_cols}} ) {
pop @{$sql->{selected_cols}};
next COLUMNS;
}
$sql->{selected_cols} = [ @bu_selected_cols ];
return;
lib/App/DBBrowser/Table/Extensions/Columns.pm view on Meta::CPAN
@table_key = ( map( "- $_", @$user_table_keys ) );
}
my $local_table = ' Local table';
my @pre = ( undef, $local_table );
my @tmp_id_alias = map { '- ' . $ax->unquote_identifier( $_->[0] ) } @identifier_alias;
my $menu_tables = [ @pre, @tmp_id_alias, @table_key ];
my $info = $ax->get_sql_info( $sql );
# Choose
my $idx = $tc->choose(
$menu_tables,
{ %{$sf->{i}{lyt_v}}, prompt => 'Column from:', info => $info, undef => '<<', index => 1 }
);
$ax->print_sql_info( $info );
if ( ! defined $idx || ! defined $menu_tables->[$idx] ) {
next COLUMN;
}
elsif ( $menu_tables->[$idx] eq $local_table ) {
@avail_cols = @$cols;
next COLUMN;
}
else {