Thrift::TException=HASH(0x25d18e0) error - perl

I am trying to connect to Hive via Perl module Thrift::API::HiveClient and below is the code to connect to Hadoop hive and retrieve the data
#!/usr/bin/perl
use DBI;
use DBI::DBD;
use Data::Dumper;
use List::MoreUtils qw(uniq);
use DateTime;
#use warnings 'all';
use POSIX qw(strftime);
use LWP::Simple;
use Thrift;
use Thrift::API::HiveClient;
use Data::Dumper;
my $latest_return;
# Database connection
my $client = Thrift::API::HiveClient->new(
host => 'localhost',
port => '10000',
);
$client->connect or die "Could not connect";
my $rh = $client->execute('select * from devtest.users');
my $return = [];
while ($latest_return = $client->fetch($rh)) { # will die with an error if it fails
print $latest_return;
}
When I execute the above script it throws below message
Thrift::TException=HASH(0x25d18e0)
I also tried Dumper to print the result nothing got printed.
any help is much appreciated.

OK, so the problem here is - you're doing something that's failing.
The module you import - Thrift::API::Hiveclient warns:
THIS CODE IS ALPHA-QUALITY, EXPERIMENTAL, AND LIKELY FLAMMABLE
Having said that - what is happening here, is for some the action is failing, and it's dieing with an error object.
That error object has status code and message with it. (I don't think this is idomatic perl though, it's more like Java :)).
So in the connect there's an error, that's not being handled properly so your code is dying.
A Thrift::TException is a fairly simple sort of object:
package Thrift::TException;
sub new {
my $classname = shift;
my $self = {message => shift, code => shift || 0};
return bless($self,$classname);
}
1;
Literally just a message and a code.
To get at that message, you'll need to dereference your object, and that's what doesn't seem to be happening.
My best guess is the _open method in Thrift::Socket is returning an error, and the HiveClient isn't actually trapping/handling it.
It should be doing an eval and trapping the error, and then unpacking the TException.
Somewhere here:
sub connect {
my ($self) = #_;
$self->_transport->open;
}
Maybe. I'm not 100% sure, because Moo might do something cute with die, but I can't find or see where that is.
So short answer - you're probably failing to connect, to be sure you'd need to grab that error message - to do that you'll need to hack the Hiveclient to eval the operation. This is what you signed up for by using a module that's "Alpha quality".

Related

Perl database connection

I am new in perl, and I need to connect the database use DBI. My code as follows:
use LWP::Simple;
use XML::Simple qw(:strict);
use Data::Dumper;
use DBI;
use Getopt::Long;
use IO::Uncompress::Gunzip qw(gunzip $GunzipError);
use IO::File;
use warnings;
$dbh = DBI->connect("dbi:);
if (!$dbh) {
&logMsg(0, "$DBI::errstr");
die;
} else {&logMsg(0,"Connection to $dbName DB OK")}
I already set the values. Its kind like connection failed, but I didn't get any errors. I also check the log file, there is nothing showing. What can I do for checking the errors? Thanks for any comments and help.
I can't find anything wrong with your code, unless logMsg just doesn't work, but it's a tedious way to go about using DBI.
Rather than checking if something went wrong with DBI, it's much better to set DBI to throw an error. You can do this with RaiseError.
my $dbh = DBI->connect(
"dbi:ODBC:DSN=$dbName;Server=$dbHost",
$dbUser, $dbPassword,
{ RaiseError => 1 }
);
Now if DBI has a failure, including trying to connect, it will throw an error and stop the program. This avoids having to check for an error every time you use the database (you'll forget).
DBI;
$dbh = DBI->connect('Your_Database_Name', 'user_id','Password');
my $sth = $dbh->prepare ("select * from Table_name");
$sth->execute();
my #row_ary = $sth->hetshrow_array;
foreach $item (#row_ary)
{
print "$item\n";
}

Retrieve a value from object in perl

I am getting
$VAR1 = bless( \*{'Fh::fh00001Screenshot.png'}, 'Fh' );
in a variable. But I need to retrieve fh00001Screenshot.png from it. How can I get it?
The Fh package is used internally by the CGI module to handle temporary files used for building multipart data. You shouldn't be using it directly.
Check carefully to make sure there is no better way before using this code which comes from the CGI code for Fh::asString
(my $name = $$VAR1) =~ s/^\*(\w+::fh\d{5})+//;
print $name;
output
Screenshot.png
Update
Rather than picking bits out of the CGI code, it looks like this package - which should really be a private one - is accessible from calling code. Use just $var->asString instead, like this
use strict;
use warnings;
use CGI;
my $var = do {
no strict 'refs';
my $var = bless( \*{'Fh::fh00001Screenshot.png'}, 'Fh' );
};
print $var->asString;

Cannot use subroutine name in socket created by Perl RPC::Serialized::Server::NetServer::Single

I want to use Perl module and wrap it into a standalone socket which would publish the subroutines from the module to other programmes. However, I probably cannot overcome namespace issues, since in the client script, I am still getting an error message:
RPC::Serialized::X::Application\',\'MESSAGE\' => \'No handler for 'predejPOS' .
My server script:
use RPC::Serialized::Server::NetServer::Single;
use RPC::Serialized::Handler::HashTree;
my $s = RPC::Serialized::Server::NetServer::Single->new({
net_server => {log_file => '', port => 20203 },
rpc_serialized => {handler_namespaces => ''},
});
$s->run;
My client script:
use RPC::Serialized::Client::INET;
my $client = RPC::Serialized::Client::INET->new({
io_socket_inet => {PeerAddr => '127.0.0.1', PeerPort => 20203,}
});
my $result = $client->predejPOS('flu-like');
My module (HastTree.pm):
package RPC::Serialized::Handler::HashTree;
require Exporter;
#ISA = qw(Exporter);
#EXPORT = qw(predejPOS);
use base 'RPC::Serialized::Handler';
our $VERSION = '0.01';
sub predejPOS {
my %POS;
$POS{'flu-like'}='<JJ>';
return $POS{$_[0]};
};
1;
I am using Windows 7, Strawberry Perl 5.12.3, and the module sits on the correct address
(C:\PROGS\Strawberry\perl\site\lib\RPC\Serialized\Handler). The function predejPOS is recognised inside the server script (ie. I can print its result from it), but I cannot access it through the client-server communication. I assume that it has something to do with the subtle difference between calling the function and calling the method. I am afraid that it is probably something simple, but even after a substantial effort and googling I was not able to make it work.
Thanks in advance!
Well I eventually solved it by myself:
First, I got completely wrong the concept of calling functions - over the network you can only call so called RPC Handlers. Moreover for each handler there must be a module in RPC::Serialized::Handler directory with the same name and a specific structure with only one subroutine inside called invoke(). Thus I changed my module (named now 'PredejPOS.pm') to:
package RPC::Serialized::Handler::PredejPOS;
{
$RPC::Serialized::Handler::PredejPOS::VERSION = '0.01';
}
use strict;
use warnings FATAL => 'all';
use base 'RPC::Serialized::Handler';
sub invoke {
my $self = shift;
my $key = shift;
my %POS;
$POS{'flu-like'}='<JJ>';
return scalar $POS{$key};
}
1;
But it was still not working.
Finally secondly I found that under Windows environment, the Perl Data::Serialize module does not work properly.
In the package Serialized.pm, subroutine recv (row 115), the chomp does not remove the damned Windows line ending '\cM'. When I corrected it, it started working as envisaged. Actually there is a lenghty discussion of this behaviour here ( http://www.perlmonks.org/?node_id=549385 )
Thanks for the suggestions.
For object method the first argument is always the current object instance itself. Sorry, if I am not clear enough, try to figure out the difference from this example:
Try this:
sub predejPOS {
my $self = shift;
my $key = shift;
my %POS;
$POS{'flu-like'}='<JJ>';
return $POS{$key};
};

Why am I seeing DBI errors on the console even though I have wrapped the DBI calls in an eval?

I have a database query that I am running inside an eval, to trap the error. Problem is that the error message is outputting to console, even though it is being trapped. How do I stop the error message from doing this, as I want to parse it myself and spit back my own messages?
my $dbh = DBI->connect('dbi:Pg:dbname=database;host=localhost',
'user', 'pass',
{RaiseError => 1}
);
eval{
$sth = $dbh->prepare($sql);
$sth->execute;
};
if($#){
#Do my parse/print stuff here I know
}
It's not a good idea to trap and ignore errors, whether they are fatal or not. Also, it is not advisable to check $# in the way you are doing it (see the questions on this site about perl exceptions for better ways to trap exceptions; I use Try::Tiny below, which is arguably the lightest-weight route of all).
Instead of proceeding with a DBI operation when an earlier one might have failed, you should check error conditions at every step:
use strict; use warnings;
use Try::Tiny;
try {
my $sth = $dbh->prepare($sql) or die $dbh->errstr;
$sth->execute or die $sth->errstr;
} catch {
print "got error $_\n";
# return from function, or do something else to handle error
};
And remember, always use strict; use warnings; in every module and script. Your code excerpt suggests that you are not yet doing this.
You can specify 'PrintError => 0' in your connect call (or use HandleError):
my $dbh = DBI->connect('dbi:Pg:dbname=database;host=localhost', $user, $passwd, {
PrintError => 0,
RaiseError => 1,
});
Or to set per statement handle:
my $sth = $dbh->prepare("SELECT * from my_table");
$sth->{PrintError} = 0;
$sth->execute();
...etc.
Also, don't depend on $# for indicating an error. A better way to use eval is:
my $result = eval {
...
$sth->...etc.
1;
}
unless ($result) {
# Do error handling..log/print $#
}
eval { } will trap a fatal error (from a die or Carp::croak call), but not a non-fatal error message (from warn or carp). To handle warning messages, see how to install a warning handler in documentation for %SIG or warn.
A trivial workaround is to use a trivial warning handler inside your eval block.
eval {
local $SIG{__WARN__} = sub { };
...
};
See also: perlfaq7: How do I temporarily block warnings?

Do I need to trap errors in my calls to Win32::OLE->LastError?

[EDIT] - with the benefit of hindsight, this question was misdirected. I have not deleted it because it is a good example of the incorrect use of eval and correct criticism by Perl::Critic.
Perl Critic raises the following criticism for the code below:
Return value of eval not tested. You can't depend upon the value of $#/$EVAL_ERROR to tell whether an eval failed
my $Jet = Win32::OLE->CreateObject('DAO.DBEngine.36')
or croak "Can't create Jet database engine.";
my $DB = $Jet->OpenDatabase($DBFile)
# code omitted for the sake of brevity
# perl script writes results to Access db via an append query
$DB->Execute( $SQLquery, 128 ); #128=DBFailOnError
eval {$err = Win32::OLE->LastError()} ; #<<<< PROBLEM LINE SEE FEEDBACK BELOW
if ( $err){
print $ERROR "WIN32::OLE raised an exception: $err\n";
Win32::OLE->LastError(0); # this clears your error
}
My thinking is that I am using eval to detect the existence of the error object and on the Win32:OLE module to detects the error and reports it.
Am I safe to ignore the criticism?
Leaving aside the perl-critic issuse, your code does not make much sense.
The Win32::OLE docs explain when exceptions will be thrown (and how you can automatically catch them).
LastError just gives you information about an error after it has occurred assuming your program has not died. Wrapping it in eval is pointless.
Update: I would have written something along the following lines (untested because I am on Linux with no access to Windows right now):
use strict;
use warnings;
use Carp;
use Win32;
use Win32::OLE;
$Win32::OLE::Warn = 3;
# No need for this eval if you are OK with the default error message
my $Jet = eval {
Win32::OLE->CreateObject('DAO.DBEngine.36')
} or croak sprintf(
"Can't create Jet database engine: %s",
win32_error_message(Win32::OLE->LastError)
);
# No need for this eval if you are OK with the default error message
my $DB = eval {
$Jet->OpenDatabase($DBFile)
} or croak sprintf(
"Can't open database '$DBFile': %s",
win32_error_message(Win32::OLE->LastError)
);
my $result = eval {
$DB->Execute( $SQLquery, 128 )
};
unless (defined $result) {
print $ERROR win32_error_message(Win32::OLE->LastError);
Win32::OLE->LastError(0);
}
The meaning of that message is detailed in the documentation. In short, it tells you to not rely on $# alone after an eval, but to also check the return value of eval.
However, in your case, the problem is that you aren't checking either the return value of eval nor are you checking $# and moreover it seems that your use of eval is completely superfluous because the method you are calling shouldn't be throwing any exceptions.