perl eval throwing blank exception - exception

I am updating a few records in database. And all the processing is done in eval block.
The problem is that even if the records are successfully updated , I still see a exception being raised.
To debug the exception, I tried printing it using Data Dumper but the exception is blank.
Can any one please help me identify what is this error and why is it thrown every time ?
Environment Details (Perl 5.8 and Unix SUSE)
Dump from Data Dumper:
$VAR1 = '
';
I am using various internal APIs, to update these records.. so I have modified my code to look similar:
sub main{
eval{
DB->updateRecord($value)
};
if($#){
Mail->SendMail(__PACKAGE__,$#):
}
}
package DB;
sub updateRecord{
my ($self , $value) = #_;
my $query = "update set column_value = $value ..<update query> ";
API->processQuery($query );
}

Does your code use warnings;?
The symptom your describing indicated that in your code you are passing die the string "\n". My guess would be that in your source you have a line that is trying to die with an error message but your error message was not initialized. It could be something like
my $error;
if (some_test()) {
$error = 'Some String';
}
if (some_other_test()) {
die "$error\n";
}
If some_test() passes but some_other_test() fails the die will report an error containing only a new line. It would also emit an warning if warnings are enabled.
Another possibility is a typo. If you don't use strict; the error variable might not be correct.
my $error = 'Some String';
if ($error) {
#note the typo (transposed ro to or)
die "$erorr\n";
}
Without use strict; this can be an easy mistake to miss.

Related

“Can't modify constant item in scalar assignment”? in AIX

I'm getting this compilation error when running my code. Can anyone help what is wrong with this code. ?
Operating system is AIX
Error -
Can't modify constant item in scalar assignment at pet_logical_date.pl line 29, near "1}" Execution of
pet_logical_date.pl aborted due to compilation errors.
Line 29 is - *print $cgi=>table({border=1});
CODE is -
#!/usr/bin/perl -w
#####################################################################################
$\="\n";
$ENV{ORACLE_HOME}='/oravl01/11.2.0.3';
$LD_LIBRARY_PATH='/oravl01/11.2.0.3/lib';
use Shell;
use DBI ;
use CGI ;
my $cgi = new CGI;
print $cgi->header;
print $cgi->start_html(-title=>'Basic CGI');
my $dsn = "DBI:Oracle:$db_inst";
$dbh = DBI->connect( 'dbi:Oracle:ABC',"DEF","IJK") or die "Database connection not made: $DBI::errstr";
my $sql = qq{SELECT logical_date,logical_date_type from logical_date where expiration_date is null };
my $sth = $dbh->prepare( $sql ) || die $dbh->errstr;
$sth->execute() || die $dbh->errstr;
print $cgi->table({border=1});
print "<tr align=center><th>$sth->{NAME}->[0]</th><th>$sth->{NAME}->[1]</th></tr>";
while (#data = $sth->fetchrow_array()) {
$Logical_Date_O = $data[0];
$Logical_Date_B = $data[1];
$Logical_Date_R = $data[2];
print "<tr><td><font color='black'>$Logical_Date_O</font></td>
<td>$Logical_Date_B</td><td>$Logical_Date_R</td></tr>\n";
}
print $cgi->end_table;
print $cgi->end_html;
Line 29 should be like this:
print $cgi->table( { -border=>"1" } );
There is something else that, although is not the cause of the error can produce some unexpected behavior: your SQL query return a two fields recordset;
but inside the while loop you try to read a third field:
$Logical_Date_R = $data[2];
the variable Logical_Date_R is likely going to have a null value.
print $cgi=>table({border=1}); is trying to assign border=1. I think you meant border => 1 (changing the assignment operator, =, to the fat comma, =>).

Reuse parameterized (prepared) SQL Query

i've coded an ActiveDirectory logging system a couple of years ago...
it never become a status greater than beta but its still in use...
i got an issue reported and found out what happening...
they are serveral filds in such an ActiveDirectory Event witch are UserInputs, so i've to validate them! -- of course i didnt...
so after the first user got the brilliant idea to use singlequotes in a specific foldername it crashed my scripts - easy injection possible...
so id like to make an update using prepared statements like im using in PHP and others.
Now this is a Powershell Script.. id like to do something like this:
$MySQL-OBJ.CommandText = "INSERT INTO `table-name` (i1,i2,i3) VALUES (#k1,#k2,#k3)"
$MySQL-OBJ.Parameters.AddWithValue("#k1","value 1")
$MySQL-OBJ.Parameters.AddWithValue("#k2","value 2")
$MySQL-OBJ.Parameters.AddWithValue("#k3","value 3")
$MySQL-OBJ.ExecuteNonQuery()
This would work fine - 1 times.
My Script runs endless as a Service and loops all within a while($true) loop.
Powershell clams about the param is already set...
Exception calling "AddWithValue" with "2" argument(s): "Parameter
'#k1' has already been defined."
how i can reset this "bind" without closing the database connection?
id like the leave the connection open because the script is faster without closing and opening the connections when a event is fired (10+ / sec)
Example Code
(shortend and not tested)
##start
function db_prepare(){
$MySqlConnection = New-Object MySql.Data.MySqlClient.MySqlConnection
$MySqlConnection.ConnectionString = "server=$MySQLServerName;user id=$Username;password=$Password;database=$MySQLDatenbankName;pooling=false"
$MySqlConnection.Open()
$MySqlCommand = New-Object MySql.Data.MySqlClient.MySqlCommand
$MySqlCommand.Connection = $MySqlConnection
$MySqlCommand.CommandText = "INSERT INTO `whatever` (col1,col2...) VALUES (#va1,#va2...)"
}
while($true){
if($MySqlConnection.State -eq 'closed'){ db_prepare() }
## do the event reading and data formating stuff
## bild some variables to set as sql param values
$MySQLCommand.Parameters.AddWithValue("#va1",$variable_for_1)
$MySQLCommand.Parameters.AddWithValue("#va2",$variable_for_2)
.
.
.
Try{ $MySqlCommand.ExecuteNonQuery() | Out-Null }
Catch{ <# error handling #> }
}
Change your logic so that the db_prepare() method initializes a MySql connection and a MySql command with parameters. Set the parameter values for pre-declared parameter names in loop. Like so,
function db_prepare(){
# ...
# Add named parameters
$MySQLCommand.Parameters.Add("#val1", <datatype>)
$MySQLCommand.Parameters.Add("#val2", <datatype>)
}
while($true) {
# ...
# Set values for the named parameters
$MySQLCommand.Parameters.SetParameter("#val1", <value>)
$MySQLCommand.Parameters.SetParameter("#val2", <value>)
$MySqlCommand.ExecuteNonQuery()
# ...
}

Perl Compilation Errors Compilation failed in require at

All of the sudden we have CGI errors showing up in the logs and one of the pages isn't working. I checked the syntax but I can't find the bug.. Any help would be greatly appreciated.
Here is the error we get in the browser:
Archive.pl: DBD::mysql::st execute failed: SELECT command denied to user 'mnin_user'#'localhost' for table 'needs' at /home/mnin/MNN_Code/Prod/lib/MySQL.lib line 52.
Compilation failed in require at archive.pl line 9.
Line 47-61 of MySQL.lib reads:
sub RunSQL {
## Executes an sql statement on the database.
my $sqlquery = shift;
$sth = $dbh->prepare($sqlquery);
$sth->execute(); #this is line 52
$MySQL_LastQuery = $sqlquery;
if ($sth->err()) {
return 1, $sth->errstr();
} else {
return 0, $sth->rows;
}
}
This is the Archvie.pl up to line 10
#!/usr/bin/perl
use CGI::Carp qw(fatalsToBrowser); # uncommenting this during debugging phase may be helpful
#use HTML::Template;
#use Win32::ODBC;
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
if($ENV{'REQUEST_METHOD'} eq "POST") { #pairs = split(/&/, $buffer);}
else { #pairs = split(/&/, $ENV{'QUERY_STRING'});}
Althought I don't think the problem is in the Archive.pl becaue these Compilation errors are showing in more than one place.
SELECT command denied to user 'mnin_user'#'localhost' for table 'needs'
This indicates you simply lack the permissions necessary to perform the query. At a minimum, you need the permissions granted by the following command:
GRANT SELECT ON `needs` TO 'mnin_user'#'localhost';

Display MySQL Query Results from Perl Script

My Perl script is supposed to print the results from my query. However, at the moment I'm getting the error:
Can't locate object method "fetchrow_array" via package "SELECT * FROM SERVER" (perhaps you forgot to load "SELECT * FROM SERVER"?) at updateDB.pl line 32
I imagine the problem is an easy one to fix.. but my perl / MySQL skills have much to be desired. My script is below:
#!/usr/bin/perl
use DBI;
use DBD::mysql;
use strict;
use warnings;
MySQL("SELECT * FROM SERVER");
# define subroutine to submit MySQL command
sub MySQL
{
# establish connection with 'serverDNA' database
my $connection = DBI->connect("DBI:mysql:database=serverDNA;host=localhost");
my $query = $_[0]; #assign argument to string
my $statement = $connection->prepare($query); #prepare query
$statement->execute(); #execute query
#loop to print MySQL results
while (my #row = $query->fetchrow_array)
{
print "#row\n";
}
}
Thanks so much!
You're calling fetchrow_array on the query string; you want to call it on the statement.
while (my #row = $statement->fetchrow_array)
{
print "#row\n";
}

Perl param() receiving from its own print HTML

I have a Perl script that reads in data from a database and prints out the result in HTML forms/tables. The form of each book also contains a submit button.
I want Perl to create a text file (or read into one already created) and print the title of the book that was inside the form submitted. But I can't seem to get param() to catch the submit action!
#!/usr/bin/perl -w
use warnings; # Allow for warnings to be sent if error's occur
use CGI; # Include CGI.pm module
use DBI;
use DBD::mysql; # Database data will come from mysql
my $dbh = DBI->connect('DBI:mysql:name?book_store', 'name', 'password')
or die("Could not make connection to database: $DBI::errstr"); # connect to the database with address and pass or return error
my $q = new CGI; # CGI object for basic stuff
my $ip = $q->remote_host(); # Get the user's ip
my $term = $q->param('searchterm'); # Set the search char to $term
$term =~ tr/A-Z/a-z/; # set all characters to lowercase for convenience of search
my $sql = '
SELECT *
FROM Books
WHERE Title LIKE ?
OR Description LIKE ?
OR Author LIKE ?
'; # Set the query string to search the database
my $sth = $dbh->prepare($sql); # Prepare to connect to the database
$sth->execute("%$term%", "%$term%", "%$term%")
or die "SQL Error: $DBI::errstr\n"; # Connect to the database or return an error
print $q->header;
print "<html>";
print "<body>";
print " <form name='book' action='bookcart.php' method=post> "; # Open a form for submitting the result of book selection
print "<table width=\"100%\" border=\"0\"> ";
my $title = $data[0];
my $desc = $data[1];
my $author = $data[2];
my $pub = $data[3];
my $isbn = $data[4];
my $photo = $data[5];
print "<tr> <td width=50%>Title: $title</td> <td width=50% rowspan=5><img src=$photo height=300px></td></tr><tr><td>Discreption Tags: $desc</td></tr><tr><td>Publication Date: $pub</td></tr><tr><td>Author: $author</td></tr><tr><td>ISBN: $isbn</td> </tr></table> <br>";
print "Add this to shopping cart:<input type='submit' name='submit' value='Add'>";
if ($q->param('submit')) {
open(FILE, ">>'$ip'.txt");
print FILE "$title\n";
close(FILE);
}
print "</form>"; # Close the form for submitting to shopping cart
You haven't used use strict, to force you to declare all your variables. This is a bad idea
You have used remote_host, which is the name of the client host system. Your server may not be able to resolve this value, in which case it will remain unset. If you want the IP address, use remote_addr
You have prepared and executed your SQL statement but have fetched no data from the query. You appear to expect the results to be in the array #data, but you haven't declared this array. You would have been told about this had you had use strict in effect
You have used the string '$ip'.txt for your file names so, if you were correctly using the IP address in stead of the host name, your files would look like '92.17.182.165'.txt. Do you really want the single quotes in there?
You don't check the status of your open call, so you have no idea whether the open succeeded, or the reason why it may have failed
I doubt if you have really spent the last 48 hours coding this. I think it is much more likely that you are throwing something together in a rush at the last minute, and using Stack Overflow to help you out of the hole you have dug for yourself.
Before asking for the aid of others you should at least use minimal good-practice coding methods such as applying use strict. You should also try your best to debug your code: it would have taken very little to find that $ip has the wrong value and #data is empty.
Use strict and warnings. You want to use strict for many reasons. A decent article on this is over at perlmonks, you can begin with this. Using strict and warnings
You don't necessarily need the following line, you are using DBI and can access mysql strictly with DBI.
use DBD::mysql;
Many of options are available with CGI, I would recommend reading the perldoc on this also based on user preferences and desired wants and needs.
I would not use the following:
my $q = new CGI;
# I would use as so..
my $q = CGI->new;
Use remote_addr instead of remote_host to retrieve your ip address.
The following line you are converting all uppercase to lowercase, unless it's a need to specifically read from your database with all lowercase, I find this useless.
$term =~ tr/A-Z/a-z/;
Next your $sql line, again user preference, but I would look into sprintf or using it directly inside your calls. Also you are trying to read an array of data that does not exist, where is the call to get back your data? I recommend reading the documentation for DBI also, many methods of returning your data. So you want your data back using an array for example...
Here is an untested example and hint to help get you started.
use strict;
use warnings;
use CGI qw( :standard );
use CGI::Carp qw( fatalsToBrowser ); # Track your syntax errors
use DBI;
# Get IP Address
my $ip = $ENV{'REMOTE_ADDR'};
# Get your query from param,
# I would also parse your data here
my $term = param('searchterm') || undef;
my $dbh = DBI->connect('DBI:mysql:db:host', 'user', 'pass',
{RaiseError => 1}) or die $DBI::errstr;
my $sql = sprintf ('SELECT * FROM Books WHERE Title LIKE %s
OR Description LIKE %s', $term, $term);
my $sth = $dbh->selectall_arrayref( $sql );
# Retrieve your result data from array ref and turn into
# a hash that has title for the key and a array ref to the data.
my %rows = ();
for my $i ( 0..$#{$sth} ) {
my ($title, $desc, $author, $pub, $isbn, $pic) = #{$sth->[$i]};
$rows{$title} = [ $desc, $author, $pub, $isbn, $pic ];
}
# Storing your table/column names
# in an array for mapping later.
my #cols;
$cols[0] = Tr(th('Title'), th('Desc'), th('Author'),
th('Published'), th('ISBN'), th('Photo'));
foreach (keys %rows) {
push #cols, Tr( td($_),
td($rows{$_}->[0]),
td($rows{$_}->[1]),
td($rows{$_}->[2]),
td($rows{$_}->[3]),
td(img({-src => $rows{$_}->[4]}));
}
print header,
start_html(-title => 'Example'),
start_form(-method => 'POST', -action => 'bookcart.php'), "\n",
table( {-border => undef, -width => '100%'}, #cols ),
submit(-name => 'Submit', -value => 'Add Entry'),
end_form,
end_html;
# Do something with if submit is clicked..
if ( param('Submit') ) {
......
}
This assumes that you're using the OO approach to CGI.pm, and that $q is the relevant object. This should work, assuming that you have $q = new CGI somewhere in your script.
Can you post the rest of the script?
I've created a mockup to test this, and it works as expected:
#!/usr/bin/perl
use CGI;
my $q = new CGI;
print $q->header;
print "<form><input type=submit name=submit value='add'></form>\n";
if ($q->param('submit')) {
print "submit is \"" . $q->param('submit') . "\"\n";
}
After the submit button is clicked, the page displays that submit is "add" which means the evaluation is going as planned.
I guess what you need to do is make sure that $q is your CGI object, and move forward from there.