Dump prepared sql query from DBI statement in PERL - perl

im using DBI in Perl to connect to my PostgreSQL Database.
Everything is working fine but in my debugging (printing results etc.) iam not able to see if the query prepared by perls DBI module is really correct.
I have something like this:
$sth->prepare( qq{SELECT * FROM company WHERE companyname LIKE ? AND city = ?});
$sth->execute( $name.'%', $city);
Iam not able to see how the sql query looks after calling execute, as execute is the latest step where parameters are binded to the query.
I would like to have something like $sth->getLastExecutedQuery() or something to see how the query looked like.
In this case the function getLastExecutedQuery() would return:
SELECT * FROM company WHERE companyname LIKE 'Company Name%' AND city = 'City name';
Is there any way to get this? Its only for debugging purposes.

DBI supports the following:
There is the DBI->trace($tracefile_handle) method (traces all DBI interactions), or $dbh->trace($tracefile_handle) which would trace just the interactions on a specific handle. Output defaults to STDERR, but by supplying $tracefile_handle, you can explicitly send output to a different file (or just use shell redirection).
DBD::pg also supports $h->trace('SQL'); This must be supported by your DBD driver to work, but fortunately DBD::Pg does support the feature.
The documentation for DBI, at CPAN - DBI,
and for DBD::Pg at CPAN - DBD::Pg really gives you all you need to know on tracing.

Use the DBI tracing facility. It works like this:
use strict;
use warnings;
use DBI;
my %opt = ( RaiseError => 1 );
my $dbh = DBI->connect( 'dbi:mysql:test', 'fred', 'secret', \%opt );
$dbh->trace(2); # level 2 shows statement with inserted parameters
my $sql_i = 'insert into t1 (a, b) values ( ?, ? )';
my $sth_i = $dbh->prepare( $sql_i );
for ( qw/ eins zwei drei / ) {
$sth_i->execute( $_, $_ );
}
$dbh->disconnect;

Beyond the tracing others have mentioned you should look at https://metacpan.org/pod/DBI#Statement which gives you the SQL last executed and https://metacpan.org/pod/DBI#ParamValues and https://metacpan.org/pod/DBI#ParamTypes which tell you about your parameters.
There is also DBIx::Log4perl which can log what you want without all the DBI tracing.

Related

Sorting Perl with Class::DBI

You have the following table called Pets:
name age pet
------------------------
Carol 25 null
Stean 23 cat
Mel 24 dog
Rich 24 rabbit
In a MySQL database on the server mydbserver with the user of 'user' with a
password of 'password'.
Do the following:
1) Create a Class::DBI connection to this database with the above credentials ( DBI.pm ).
2) Create a Class for the table Pets ( Pet.pm )
3) Create a program that prints all the names of people in the Pets table and what kind (if any )
of pet he/she has sorted by name then age.
Here is the code I wrote.....
#!/usr/bin/perl
package Pet::DBI;
use DBI;
use strict;
use base 'Class::DBI';
Pet::DBI->set_db('Main','dbi:mysql:dname', 'user', 'password')
or die $DBI::errstr "\n";
1;
package Pet::Pets;
use base 'Pet::DBI';
use strict;
use warning;
Pet::Pets->table('Pets');
Pet::Pets->columns(All => qw/name age pet/);
1;
use Pet::Pets;
my #pets = Pet::Pets->retrieve_all;
for (sort {$a->name cmp $b->name} || {$a->age <=> $b->age} #Pets) {
print "Name:".$_->name ' => '."Age". $_->age"\n";
}
1;
It's basically correct, but there's a number of small problems.
It's not necessary to load DBI, Class::DBI will take care of that for you.
You should be using connection instead of set_db("Main", ...). set_db comes from Ima::DBI and it's not polite (or necessary) to peek under the hood like that.
Although this isn't directly documented in Class::DBI (it should be), its inherited from Ima::DBI, there's no need to check for DBI errors. RaiseError is on and if the connection fails it will throw an error.
You have a typo, use warning; instead of use warnings;.
Unless you have stitched three files together for the post, if the code is all in one file the 1; statements do nothing. use Pet::Pets will not work because there is no Pet/Pets.pm file. You don't have to use a class which is already in the same file.
In general, avoid using $_ if you don't have to, too many things can quietly use or change it. Instead, give the for loop a proper variable like for my $person.
sort only takes one block, but you're basically correct. It should be sort { ($a->name cmp $b->name) || ($a->age <=> $b->age) } #Pets
To avoid reading the whole, potentially very large, table into memory, the sorting should really be done in the database with an ORDER BY name ASC, age ASC and then retrieved a row at a time using an iterator. Unfortunately, retrieve_all does not support any options. You can use retrieve_from_sql to add arbitrary SQL to the end of the basic SELECT. my $all_people = Pet::Pets->retrieve_from_sql("ORDER BY name ASC, age ASC"); Then your data will already be sorted and can be read a row at a time. while( my $person = $all_people->next ) { ... }
You're missing a . in "Age". $_->age"\n".
Null values in a database come back as undef. You'll want to check if $_->pet is defined and if not use some other string like "no pet" or just a blank "".
You're printing the person's age, the question asks for their pet.
Otherwise, it should work.
But really, tell whomever gave you this homework to stop telling people to use Class::DBI. They can email me if they like, schwern#pobox.com.

Perl dbi : fetchrow_array limit result :

When I use the same request in mySQL Workbench, the count of results is 41100.
In my script, the count is 1015. I have no error in my code (I use die for see it).
What is the cause of this difference?
# Create the statement
# select all id in table contacts
$statement = "select distinct contacts.id from $database.contacts";
# Prepare and execute the SQL query
$sqlQuery = $connectGrc->prepare($statement)
# Execute the statement
$sqlQuery->execute()
# Make id in array
while($oneId = $sqlQuery->fetchrow_array())
{
push(#ArrayId,$oneId);
}
There's nothing obviously wrong (except for the lack of error checking and that your comments are not program comments). Try connecting with RaiseError on, 'use strict;', and see if there are problems which you otherwise might not see. Also, if all you want is a one-column array of results, and can settle for an array reference, consider selectcol_arrayref() for convenience.

Can't get Extended SNMP output in Perl

I have written a Perl script to put back some SNMP values, which works fine. I have now written a script on the remote server and used the extend function in SNMP to put the value from the script into SNMP.
If I run:
snmpget -v2c -c public 10.0.0.10 'NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."cc_power"'
I get the result:
NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."cc_power" = STRING: 544
But when I try to use my script to get the information back it doesn't get it. Here is the script:
#!/usr/bin/perl
use strict;
use SNMP;
use RRDs;
my $rrd_db = "/storage/db/rrd/cc_power.rrd";
my $sess;
my $val;
my $error;
$sess = new SNMP::Session(DestHost => "10.0.0.10", Community => "public", Version => 2);
my $power = $sess->get('NET-SNMP-EXTEND-MIB::nsExtendOutput1Line.\"cc_power\"');
$error=RRDs::error;
die "ERROR while updating RRD: $error\n" if $error;
my $date=time;
print "Data Script has been run - Output: ${date}:${power}\n";
but nothing is returned, and I have no idea why... no errors or anything, have I missed something stupid?
Hope someone can help as this is driving me nuts :)
I assume that you used netsnmp snmpget. Well, it hides too many details from you, as it loads MIB documents in background and nicely translate OIDs and SNMP values to all kinds of user friendly formats.
So next time pay attention to what decoration it performs and simulate that in your own code to achieve the same effects.

Where is my associative array and how do I access it using Perl DBI?

I'm working with perl, and using DBI. Up to now, I've been using ->fetchall_arrayref to get the results of a database query, and just accessing the array by numeric keys. However, I much prefer to be able to access records by the field names (associative fetch) than numeric.
How do I do this, and what is the correct syntax for accessing the keys?
I would prefer something like:
$data[0]['name']
Instead of:
$data[0][1]
Working Solution
my %data;
#{$data{$id}}{('name')} = 'something';
Read the DBI docs. Particularly, fetchall_hashref.
And you should also learn Perl syntax, as it's not the same as PHP.
You can use selectall_arrayref for this. Here's example from the DBI manpage:
You may often want to fetch an array of rows where each row is stored as a hash.
That can be done simple using:
my $emps = $dbh->selectall_arrayref(
"SELECT ename FROM emp ORDER BY ename",
{ Slice => {} }
);
foreach my $emp ( #$emps ) {
print "Employee: $emp->{ename}\n";
}
If you do fetchall_hashref() then you get the hash you are looking for. The keys will be the field names from the database. I am a little late, and Joe got it, but it will be.
$data->{0}->{'field'};

How do I call Informix stored procedures from Perl?

How do I call informix stored procedures from Perl? I use DBD::ODBC to connect to informix database, but I don't know how to call procedures. my code like this:
my $dbh = DBI->connect("dbi:".DBDRIVE.":".DBNAME,DBUSER,DBPASS,
{RaiseError=>0,PrintError=>0,AutoCommit=>1}) ||
die $DBI::errstr;
$dbh->do("execute procedure sp_test('2010-05-01 00:00:00')") ||
warn "failed\n";
$dbh->disconnect();
When I run it, it didn't get error. But I get nothing when I check the database. The store procedure works fine if I run it in database directly.
Anyone can help me out?
As strange as it sounds, you need to fetch() from your statement handle in order to actually execute your stored procedure. Try changing your do() call to this instead:
my $sth = $dbh->prepare("execute procedure sp_test('2010-05-01 00:00:00')")
or die $dbh->errstr
$sth->execute() or die $dbh->errstr
$sth->fetch(); # SPL actually executed here
(You may also want to consider setting RaiseError => 1 in your connect() options to avoid having to do all the ... or die ... stuff after every call.)
Pass 1
I suppose DBDRIVE, DBNAME, DBUSER and DBPASS have been defined via the constant module:
use constant DBDRIVE => "informix"; # ...mitsake...
use constant DBNAME => "stores"; # Or whatever
use constant DBUSER => "me";
use constant DBPASS => "mine";
You should use 'or' rather than '||' after the call to DBI->connect().
From 'perldoc DBI':
$dbh = DBI−>connect($data_source, $username, $password, \%attr)
or die $DBI::errstr;
You can can get better help while resolving problems by using 'RaiseError=>1' and/or 'PrintError=>1'; that is what they are there for.
In general terms, the syntax of the EXECUTE PROCEDURE is correct, and should work OK as long as the procedure doesn't return anything...
Pass 2
Oh, you stipulate DBD::ODBC rather than DBD::Informix. Therefore, you are are at the mercy of a lot of code that I don't know so well as I know DBD::Informix.
Can we assume that you can connect to the database successfully using DBD::ODBC? And modify it and so on?
You will probably need to turn on the DBI tracing. You may also need to turn on lower level. Is the ODBC driver you are using provided by Informix, or is it the IBM DB2 CLI (C Common Client) driver, or one provided by someone else? Which version of Informix (IDS) are you using? Which platform are you running on? Which versions of Perl, DBI, DBD::ODBC and the various drivers are you using?
ODBC drivers can go munging SQL sent to it. I'm not clear what the various drivers I mentioned would do with the statement.
Pass 3
Did you consider contacting the dbi-users#perl.org mailing list? That's where the maintainers of DBI and DBD::ODBC hang out.