App-AltSQL
view release on metacpan or search on metacpan
lib/App/AltSQL/Model/MySQL.pm view on Meta::CPAN
}
sub handle_sql_input {
my ($self, $input, $render_opts) = @_;
# Figure out the verb of the SQL by either using regex or a parser. If we
# use the parser, we get error checking here instead of the server.
my $verb;
if (defined $self->sql_parser && $self->sql_parser) {
# Attempt to parse the input with a SQL parser
my $parsed = $self->sql_parser->parse($input);
if (! defined $parsed->root) {
$self->show_sql_error($input, $parsed->pos, $parsed->line);
return;
}
# Figure out the verb
my $statement = $parsed->root->extract('statement');
if (! $statement) {
$self->log_error("Not sure what to do with this; no 'statement' in the parse tree");
return;
}
$verb = $statement->children->[0];
}
else {
($verb, undef) = split /\s+/, $input, 2;
}
# Run the SQL
my $t0 = gettimeofday;
my $sth = $self->execute_sql($input);
return unless $sth; # error may have been reached (and reported)
# Track which database we're in for autocomplete
if (my ($database) = $input =~ /^use \s+ (\S+)$/ix) {
$self->current_database($database);
$self->update_autocomplete_entries($database);
}
my %timing = ( prepare_execute => gettimeofday - $t0 );
my $view = $self->app->create_view(
sth => $sth,
timing => \%timing,
verb => $verb,
);
$view->render(%$render_opts);
}
sub execute_sql {
my ($self, $input) = @_;
my $sth = $self->dbh->prepare($input);
# Execute the statement, allowing Ctrl-C to interrupt the call
eval {
eval {
my $h = set_sig_handler('INT', sub {
my $thread_id = $self->dbh->{mysql_thread_id};
$self->dbh->clone->do("KILL QUERY $thread_id");
die "Query aborted by Ctrl+C\n";
});
$sth->execute();
};
die "$@" if $@;
};
if (my $error = $self->dbh->errstr || $@) {
$self->log_error($error);
return;
}
return $sth;
}
sub update_db_types {
my $self = shift;
## Collect type info from the handle
my %types;
my $type_info_all = $self->{dbh}->type_info_all();
my %key_map = %{ shift @$type_info_all };
$types{unknown} = { map { $_ => 'unknown' } keys %key_map };
foreach my $i (0..$#{ $type_info_all }) {
my %type;
while (my ($key, $index) = each %key_map) {
$type{$key} = $type_info_all->[$i][$index];
}
$types{$i} = \%type;
}
$self->{db_types} = \%types;
}
sub db_type_info {
my ($self, $type) = @_;
my $info = $self->{db_types}{$type};
if (! $info) {
#$self->log_error("No such type info for $type");
return $self->{db_types}{unknown};
}
return $info;
}
sub show_sql_error {
my ($self, $input, $char_number, $line_number) = @_;
my @lines = split /\n/, $input;
my $line = $lines[ $line_number - 1 ];
$self->log_error("There was an error parsing the SQL statement on line $line_number:");
$self->log_error($line);
$self->log_error(('-' x ($char_number - 1)) . '^');
}
my %prompt_substitutions = (
S => ';',
( run in 0.591 second using v1.01-cache-2.11-cpan-39bf76dae61 )