Perl MySQL INSERT error - mysql

I'm trying to parse a few references from a file and load them into a MySQL table, but I keep on getting this error everytime I run the script
DBD::mysql::st execute failed: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' Njuguna, M.I., Yusuf, J. A., Akama, V.,2013,Animal husbandry in the developed w' at line 1 at manuscripts3.pl line 51, <$fh> line 1.
Uncaught exception from user code
See my code below.
I'm at my wits end. What am I doing wrong?
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
use DBI;
my $driver = "mysql";
my $database = "test";
my $user = "root";
my $password = "";
my $dbh = DBI->connect(
"DBI:$driver:$database",
$user,
$password, {
RaiseError => 1,
PrintError => 1,
AutoCommit => 0,
}
) or die $DBI::errstr;
my $file = "/var/www/manuscripts.txt";
open my $fh, "<", $file;
my #manuscripts;
while (my $lines = <$fh>) {
$lines =~ s/\, \(/\t/g;
$lines =~ s/\) \“/\t/g;
$lines =~ s/\” /\t/g;
my ($authors, $year, $title, $journal) = split(/\t/, $lines);
push #manuscripts, {
authors => $authors,
year => $year,
title => $title,
journal => $journal
};
#print "$title\n";
my $sql = "insert into manuscript($authors,$year,$title,$journal) values (?,?,?,?)";
$dbh->commit();
my $stmt = $dbh->prepare($sql);
$stmt->execute($authors, $year, $title, $journal);
# disconnect from the MySQL database
$dbh->disconnect();
}
#print $manuscripts[0][2];
text file:
Kamau, M.A., Njuguna, M.I., Yusuf, J. A., Akama, V., (2013) “Animal husbandry in the developed world” Journal of Hospital Infenction
Kamau, M.A., Njuguna, M.I., Yusuf, J. A., Akama, V., (2013) “Agriculture and global warming” PLOS Medicine Kamau, M.A., Njuguna,
M.I., Yusuf, J. A., Akama, V., (2013) “Rotational farming as a business” The Journal of Infectious Diseases

The problem is here:
my $sql = "insert into manuscript($authors,$year,$title,$journal)
values (?,?,?,?)";
You are putting the contents of the variables as the field names. I assume you mean:
my $sql = "insert into manuscript(authors,year,title,journal)
values (?,?,?,?)";

You have to use $stmt->bind_param(); to bind the parameter and use $stmt->execute() without parameter
my $sql = "insert into manuscript(authors,year,title,journal)
values (?,?,?,?)";
my $stmt = $dbh->prepare($sql);
$stmt->bind_param(1,$authors);
$stmt->bind_param(2,$year);
$stmt->bind_param(3,$title);
$stmt->bind_param(4,$journal);
$stmt->execute();

Related

Script gives database error on just one system

I am a VOIP administrator and I have script for updating directory database in Perl which was purchased from vendor before I was employed here.
The script is working fine on all of the servers except for one.
#!/usr/bin/perl
use lib "/opt/asterisk/lib/";
use DBI;
use Asterisk::config;
sub trim($);
# database information
$db="kesc";
$host="sip-ho.kesc.com.pk";
$userid="foo";
$passwd="bar";
$connectionInfo="dbi:mysql:$db;$host";
$hubname = "";
# make connection to database
$dbh = DBI->connect($connectionInfo,$userid,$passwd);
# Perl trim function to remove whitespace from the start and end of the string
sub trim($)
{
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}
my $rc = new Asterisk::config (file=>'/etc/asterisk/sip.conf',keep_resource_array=>0);
#list = $rc->fetch_sections_list();
$n = 1;
foreach (#list)
{
if ($_ ne "general") {
$entry = $rc->fetch_keys_hashref(section=>$_);
while ( my ($key, #value) = each(%$entry) )
{
if ($key eq "callerid") {
#vars = split('<',$value[0][0]);
$query = "insert into directory (extension,name,hub) values (" . trim($_) . ", '" . trim($vars[0]) . "', '$hubname') ON DUPLICATE KEY UPDATE hub='$hubname'";
$sth = $dbh->prepare($query);
$sth->execute();
}
}
}
$n++;
}
Now I get below mentioned error when executing it.
DBD::mysql::st execute failed: You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax to use near 's Office', '') ON DUPLICATE KEY UPDATE hub=''' at line 1 at ./directory line 39.
I have also replaced it from other server with same MySQL version where it works perfectly.
Please guide me.
Thank you for the code. It is as I suspected; you really shouldn't insert values directly into an SQL statement
Change line 37, 38, and 39 to this and it should work for you
$query = 'INSERT INTO directory (extension, name, hub) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE hub = ?';
$sth = $dbh->prepare($query);
$sth->execute( trim($_), trim($vars[0]), $hubname, $hubname );
Beware that the same problem is likely to exist elsewhere in the code base, so it really should be completely reviewed

PERL::DBI Getting user databases in a list

I am trying to make a little script to extract databases/tables/columns from my database, but in the first step I couldn't move on, I am getting databases in strange list, please look:
#!/usr/bin/perl
use DBI;
$host = "localhost";
$user = "wnyclick_siteusr";
$pw = "Hank0402\$";
$dsn = "dbi:mysql:$database:localhost:3306";
$connect = DBI->connect($dsn, $user, $pw);
$databases = $connect->selectcol_arrayref('show databases');
use Data::Dumper;
print Dumper $databases;
executing this code giving me the following:
$VAR1 = [
'information_schema',
'wnyclick_sitedatawp'
];
How can I put this execution result in a list?
print #VAR1[0];
print #databases[0];
I just modified your code. Try the below code:
#!/usr/bin/perl -w
use DBI;
use DBD::mysql;
my $user = "wnyclick_siteusr";
my $pw = "Hank0402\$";
#Connecting Database
$dbh = DBI->connect( 'dbi:mysql:database=mysql;host=localhost;port=3306', '$user', '$pw' )
or die "Connection Error: $DBI::errstr\n";
$sql = "show databases";
$sth = $dbh->prepare($sql);
$sth->execute or die "SQL Error: $DBI::errstr\n";
while ( #row = $sth->fetchrow_array ) {
#print $row[1];
print "#row\n";
}

From CSV to MySQL Database Using Perl

I tried to upload some data from CSV to MySQL database - But it not working
Below one is my code
#!/usr/bin/perl -w
use DBI;
use strict;
use TEXT::CSV;
use warnings;
my $driver = "mysql";
my $database = "test";
my $host = "localhost"
my $databaseport = "3306";
my $userid = "root";
my $password = "password";
my $csv = "C:/Perl/scripts/table.csv";
my $dsn = "dbi:mysql:dbname=$databasename;host=$dbhost;port=$dbport;";
open (CSV, "$csv") or die "Couldn't open csvfile: $!";
my $dbh = DBI->connect($dsn, $userid, $password,{ RaiseError => 1})
or die "Could not connect to database! $DBI::errstr";
{
local $/ = undef;
$dbh->do("INSERT INTO student (stud_id,stud_name,dept_id,stud_mark,stud_address)
values (?, ?, ?, ?, ?)", undef, <CSV>);
}
$dbh->disconnect;
close CSV;
There are a few issues here. I'll list the ones that will give you error messages first.
There is no module TEXT::CSV. There is one called Text::CSV though.
You are using 5 placeholders in your query, but you are passing the first line of the csv file through the diamond operator <CSV>. That will give an error message.
Then there are problems with your logic. You are passing the complete file to the DB (as the first argument). That does not make sense. You need to split the input or use Text::CSV to do it and read the file line by line.
Furthermore, it is good practice nowadays to use open with three arguments and make the filehandle lexical.
I've written all of this up as an example with self-made CSV handling. If your file is more complex, read up on Text::CSV und use it.
use DBI;
use strict;
use warnings;
my $csv = "C:/Perl/scripts/table.csv";
# omitted settings here ...
my $dbh = DBI->connect($dsn, $userid, $password,{ RaiseError => 1})
or die "Could not connect to database! $DBI::errstr";
open (my $fh, '<', $csv)
or die "Couldn't open csvfile: $!";
# prepare statement handle for reuse in the loop
my $sth = $dbh->prepare(qq{
INSERT INTO student(stud_id,stud_name,dept_id,stud_mark,stud_address)
VALUES (?, ?, ?, ?, ?)});
# read the file line by line
while (my $line = <$fh>) {
chomp $line; # remove newline
$sth->execute( split /;/, $line ); # assuming the separator is a semicolon
}
close $fh;
# DB handle will disconnect implicitly on end of program
As you can see, I decided to prepare the statement up front and reuse it. That saves a lot of time in the loop, because the DB will remember the statement.
Reading from a filehandle in list context (i.e. the <CSV> bit in your code) reads all the lines from the file and returns them as a list. So your ?, ?, ?, ? placeholders each get given a whole line from the file (including the line break character at the end). For some of the fields (perhaps dept_id?) this may not be a valid value, so the INSERT statement fails.
Though actually, you're also setting $/ to undef, which makes it even wrongerer. $/ changes Perl's notion of a new line when it's reading text files. Setting it to undef means that Perl will consider the entire file to be a single line.
At a guess, what you're trying to do is read the CSV file one line at a time, and pump each into the database.
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use Text::CSV; # case-sensitive!
my $driver = "mysql";
my $database = "test";
my $host = "localhost"
my $databaseport = "3306";
my $userid = "root";
my $password = "password";
my $csv = "C:/Perl/scripts/table.csv";
# Connect to database.
my $dsn = "dbi:mysql:dbname=$databasename;host=$dbhost;port=$dbport;";
my $dbh = DBI->connect($dsn, $userid, $password,{ RaiseError => 1})
or die "Could not connect to database! $DBI::errstr";
# DBI can be more efficient if you prepare the SQL query once, and then
# execute it multiple times, rather than calling `do` for each insert.
my $sth = $dbh->prepare(<<'SQL');
INSERT INTO student (stud_id,stud_name,dept_id,stud_mark,stud_address)
VALUES (NULL, ?, ?, ?, ?)"
SQL
# Open the CSV file.A
open my $CSV, '<', $csv
or die "Couldn't open csvfile: $!";
# Create an instance of Text::CSV.
my $reader = Text::CSV->new;
# Use Text::CSV to read a line.
while (my $row = $reader->getline($CSV))
{
# Insert into database.
$sth->execute( #$row );
}
# Clean up (optional; Perl will do this when your script ends anyway).
$dbh->disconnect;
close $CSV;

Unable to insert a record into MySQL database using DBI

I am trying to insert a record into a MySQL database using Perl DBI. I am not getting any errors but the insert is not working. However, I am able to successfully fetch records from the database using DBI.
Here is the code that does the insert:
#!"C:\xampp\perl\bin\perl.exe"
use diagnostics;
use DBI;
use strict;
use warnings;
my $driver = "mysql";
my $database = "mysql";
my $dsn = "DBI:$driver:database=$database";
my $userid = "root";
my $password = "password";
my $buffer;
my #pairs;
my $pair;
my $name;
my $value;
my %FORM;
# Read in text
my $ENV;
$ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/;
if ($ENV{'REQUEST_METHOD'} eq "GET")
{
$buffer = $ENV{'QUERY_STRING'};
}
# Split information into name/value pairs
#pairs = split(/&/, $buffer);
foreach $pair (#pairs)
{
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%(..)/pack("C", hex($1))/eg;
$FORM{$name} = $value;
}
my $first_name= $FORM{name};
my $address = $FORM{address};
my $city = $FORM{city};
my $occupation = $FORM{occupation};
my $age = $FORM{age};
my $dbh = DBI->connect("dbi:mysql:dbname=mysql", "root", "password",{ AutoCommit => 0,RaiseError => 1}, ) or die ("Couldn't connect to database: ") , $DBI::errstr;
# my $sth = $dbh->prepare("INSERT INTO persons
# (FirstName, LastName,Address,City)
# values
# ($first_name, $last_name,$address,$city)");
my $query = "insert into userrecords(Address,Age,City,Name,Occupation)
values (?, ?, ?, ?, ?) ";
my $statement = $dbh->prepare($query) or die ("Couldn't connect to database: "), $DBI::errstr;
$statement->execute($address,$age,$city,$name,$occupation) or die ("Couldn't connect to database: "), $DBI::errstr;
$dbh->disconnect();
my $URL = "http://.....:81/cgi-bin/showdata.cgi";
print "Location: $URL\n\n";
exit(0);
When I run my code in the Padre IDE, I get the following errors:
****Error*********
Useless use of a variable in void context at InsertRecord.cgi line 50 (#1)
(W void) You did something without a side effect in a context that does
nothing with the return value, such as a statement that doesn't return a
value from a block, or the left side of a scalar comma operator. Very
often this points not to stupidity on your part, but a failure of Perl
to parse your program the way you thought it would. For example, you'd
get this if you mixed up your C precedence with Python precedence and
said
$one, $two = 1, 2;
when you meant to say
($one, $two) = (1, 2);
Another common error is to use ordinary parentheses to construct a list
reference when you should be using square or curly brackets, for
example, if you say
$array = (1,2);
when you should have said
$array = [1,2];
The square brackets explicitly turn a list value into a scalar value,
while parentheses do not. So when a parenthesized list is evaluated in
a scalar context, the comma is treated like C's comma operator, which
throws away the left argument, which is not what you want. See
perlref for more on this.
This warning will not be issued for numerical constants equal to 0 or 1
since they are often used in statements like
1 while sub_with_side_effects();
String constants that would normally evaluate to 0 or 1 are warned
about.
Useless use of a variable in void context at InsertRecord.cgi line 59 (#1)
Useless use of a variable in void context at InsertRecord.cgi line 60 (#1)
Use of uninitialized value in transliteration (tr///) at InsertRecord.cgi line
23 (#2)
(W uninitialized) An undefined value was used as if it were already
defined. It was interpreted as a "" or a 0, but maybe it was a mistake.
To suppress this warning assign a defined value to your variables.
To help you figure out what was undefined, perl will try to tell you the
name of the variable (if any) that was undefined. In some cases it cannot
do this, so it also tells you what operation you used the undefined value
in. Note, however, that perl optimizes your program and the operation
displayed in the warning may not necessarily appear literally in your
program. For example, "that $foo" is usually optimized into "that "
. $foo, and the warning will refer to the concatenation (.) operator,
even though there is no . in your program.
Use of uninitialized value $ENV{"REQUEST_METHOD"} in string eq at
InsertRecord.cgi line 24 (#2)
Use of uninitialized value $buffer in split at InsertRecord.cgi line 29 (#2)
Location: http://.......:81/cgi-bin/showdata.cgi
Press any key to continue . . .
***********END***********************
What is the issue?
When I was editing your code so that it was more readable, I stumbled upon what I assume is the solution:
You are using $name when inserting into the database, but you use $first_name when getting the value $FORM{name}. So since you used $name above, it has the value of the last name used, whatever that might be. The relevant code snippets:
($name, $value) = split(/=/, $pair);
...
$FORM{$name} = $value;
...
my $first_name = $FORM{name};
...
$statement->execute($address,$age,$city,$name,$occupation)
# ^^^^^--- should be $first_name
Your problem would have been solved if you had used proper scope on your variables, namely something like this:
foreach my $pair (#pairs) {
my ($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%(..)/pack("C", hex($1))/eg;
$FORM{$name} = $value;
}
Then when you later would try to use $name, you would get the error
Global variable "$name" requires explicit package name ...
Which would alert you to your mistake and save you hours in debugging time. When you declare variables at the top of the script, instead of in the smallest possible scope, you effectively disable the protection that use strict 'vars' offers. So don't do that.
Also, you should probably use the CGI module instead of trying to handle it manually. It will make things easier, and safer. Don't forget to perform sanity checks on your data to prevent database injection attacks.
Your script when cleaned up and properly formatted looks like this.
What happens when you replace your code with this:
#!"C:\xampp\perl\bin\perl.exe"
use strict;
use warnings;
use diagnostics;
use DBI;
use CGI qw[param redirect];
my $driver = "mysql";
my $database = "mysql";
my $dsn = "DBI:$driver:database=$database";
my $userid = "root";
my $password = "password";
my $dbh = DBI->connect("dbi:mysql:dbname=mysql", "root", "password",
{ AutoCommit => 0,RaiseError => 1}, )
or die "Couldn't connect to database: ", $DBI::errstr;
my $query = "insert into userrecords(Address,Age,City,Name,Occupation)
values (?, ?, ?, ?, ?) ";
my $statement = $dbh->prepare($query)
or die "Couldn't connect to database: " , $DBI::errstr;
$statement->execute(param('address'), param('age'), param('city'),
param('name'), param('occupation'))
or die "Couldn't connect to database: " , $DBI::errstr;
$dbh->disconnect();
my $URL = "http://.....:81/cgi-bin/showdata.cgi";
print redirect($URL);
I've basically made two changes:
Use the CGI.pm module to handle the CGI interaction (getting the parameters and printing the redirection header).
Fixed your "void context" errors by removing the misplaced parentheses in all of your calls to die.
I'm made no substantive changes to the code, but at least we now have a clean version to go with.
Update: D'oh. It's obvious now the code is cleaned up a bit. If you have "Autocommit" turned off, then you need to commit your changes. Add $dbh->commit between the calls to execute() and disconnect().
The warning comes from this:
or die ("Couldn't connect to database: ") , $DBI::errstr;
The , $DBI::errstr is outside of the die and nothing is done with it, thus being in void context. You want something like this:
or die ("Couldn't connect to database: $DBI::errstr");
Also, your form handling code has some issues. If you're writing CGI scripts, you may as well use the CGI module. Here's a quick cleanup of your code:
#!"C:\xampp\perl\bin\perl.exe"
use diagnostics;
use CGI ':standard';
use DBI;
use strict;
use warnings;
my $driver = "mysql";
my $database = "mysql";
my $dsn = "DBI:$driver:database=$database";
my $userid = "root";
my $password = "password";
my $name = param('name');
my $address = param('address');
my $city = param('city');
my $occupation = param('occupation');
my $age = param('age');
my $dbh = DBI->connect( $dsn, $userid, $password,
{ AutoCommit => 1, RaiseError => 1 },
) or die("Couldn't connect to database: $DBI::errstr");
my $query = <<'END';
INSERT INTO userrecords(Address,Age,City,Name,Occupation)
VALUES ( ?, ?, ?, ?, ?)
END
my $statement = $dbh->prepare($query);
$statement->execute( $address, $age, $city, $name, $occupation );
$dbh->disconnect();
my $URL = "http://.....:81/cgi-bin/showdata.cgi";
print "Location: $URL\n\n";
Note that I've removed many or die statements because you already have RaiseError set to a true value.
For simplicity's sake, I've also (reluctantly) turned on AutoCommit.

Deleting and updating data from database

I have created a code that connects to database and i want to delete data from database using a button the same for update. but i just can display data in a table and cant delete.
my $q= new CGI;
print $q->header;
print $q-> start_html(
-title => "",
);
# print $q->start_form;
## mysql user database name
my $db = "people";
## mysql database user name
my $user = "root";
## mysql database password
my $pass = "";
## user hostname : This should be "localhost" but it can be diffrent too
my $host="127.0.0.1";
## SQL query
my $query = "select ID,Name,Surname,Gender from person";
my $dbh = DBI->connect("DBI:mysql:$db:$host", $user, $pass);
my $sqlQuery = $dbh->prepare($query)
or die "Can't prepare $sqlQuery: $dbh->errstr\n";
my $rv = $sqlQuery->execute
or die "can't execute the query: $sqlQuery->errstr";
print start_form (-method => 'post', -action => "modify.pl" );
my #aRows;
while (my #data = $sqlQuery->fetchrow_array()) {
my $cRowId = hidden('ID', $data[0]);
my $bt1 = submit('action','delete');
my $bt2 = submit('action','update');
push #aRows, ($cRowId, $q->Tr($q->td([$data[1], $data[2], $data[3],$bt1,$bt2])));
}
print $q->table({-border =>'1', -align =>'center', -width => '100%'},
$q->Tr([$q->th([ 'Name', 'Surname', 'Gender', 'Delete', 'Update', ])]),
#aRows,
);
print $q->input({-type => 'button', -class => 'button', -onclick => "window.location.href='insert.pl';", -value => 'Shto'});
print $q->end_form;
print $q->end_html;
delete.pl
use CGI;
use CGI qw(standard);
use DBI;
use CGI::Carp qw(set_die_handler);
use CGI qw/:all/;
BEGIN {
sub handle_errors {
my $msg = shift;
print "content-type: text/html\n\n";
#proceed to send an email to a system administrator,
#write a detailed message to the browser and/or a log,
#etc....
}
set_die_handler(\&handle_errors);
}
my $q = CGI->new();
my $db = "people";
my $user = "root";
my $pass = "";
my $host="127.0.0.1";
my $dbh = DBI->connect("DBI:mysql:$db:$host", $user, $pass);
my $action = $q->param('action'){
given ($action){
when('delete'){
my $row_id = $q->param('ID');
my $sth = $dbh->prepare("DELETE FROM person WHERE ID = $row_id ") or die "Can't prepare $query: $dbh->errstr\n";
my $rv = $sth->execute() or die $DBI::errstr;
print "deleted";
my $sth->finish();
my $dbh->commit or die $DBI::errstr;
}
} }
I dont know where may be the problem
The vast majority of Perl CGI problems can be solved by:
Adding use strict and use warnings to your code
Fixing all of the errors that now appear in your error log
You assign a value to $row_id after you try to use that variable to create your query.
Additionally, using raw user input in SQL queries makes you vulnerable to XSS attacks. Rewrite your code to use parameterized queries
Do not use my if you do not want a new variable. Remove all my's from the method calls:
my $sth->finish();
my $dbh->commit or die $DBI::errstr;