I have a table with no primary key.
I need to execute the following:
UPDATE t1
SET tstamp = now()
WHERE `col1` = 1
AND `col2` = 'this';
In Workbench it throws Error 1175 until I execute this line before the update:
SET SQL_SAFE_UPDATES = 0;
With this line it works just fine.
But when I try to do this in perl it doesn't work. I tried both
$dbh->do("SET SQL_SAFE_UPDATES = 0");
and
my $dbh = DBI->connect("DBI:mysql:$db:$host:$port",$user,$password, { RaiseError => 1, AutoCommit => 0, sql_safe_updates => 0 })
but it still doesn't work.
How can I get this work in perl?
UPD.
I updated the code with ##sql_safe_updates check and commit.
The code:
$sth = $dbh->prepare("SELECT #\#sql_safe_updates"); $sth->execute; while(my #row = $sth->fetchrow_array) { print "sql_safe_updates before: ". $row[0] . "\n"; }
$dbh->do("SET SQL_SAFE_UPDATES = 0") or die $dbh->errstr;
$sth = $dbh->prepare("SELECT #\#sql_safe_updates"); $sth->execute; while(my #row = $sth->fetchrow_array) { print "sql_safe_updates after: " . $row[0] . "\n"; }
$query = "UPDATE t1 SET tstamp = now() WHERE `col1` = 1 AND `col2` = 'this'";
$sth = $dbh->prepare($query);
$rv = $sth->execute or die $sth->err();
$dbh->commit;
if ("$rv" ne "1") {
$query =~ s/\n/ /g; $query =~ s/ / /g;
print "Failed to run query: $query\n";
exit;
}
Output:
sql_safe_updates before: 0
sql_safe_updates after: 0
Failed to run query: UPDATE t1 SET tstamp = now() WHERE `col1` = 1 AND `col2` = 'this'
UPD2. I checked the table - everything works after I commited. It is confusing thought, that $rv is 1 on successful select and 2 on successful update
It was a return code check error, and a missing commit.
Regarding the return code check, for a non-SELECT statement, execute returns the number of rows affected, if known.. Zero rows affected (as opposed to an error) is represented as the special "zero but true" value "0E0". In the OP's case, the statement was returning 2.
Related
I have the following code, which generates DQL queries.
When I echo my $dql and copy paste it into phpmyadmin and execute it, it works perfectly, but when trying to execute it with Doctrine I keep running into "'[Syntax Error] line 0, col 6981: Error: Unexpected 'WHERE'" error. What am I doing wrong?
$dqlStaticPartial = $dql = "UPDATE \VendorName\MyBundle\Entity\Product cp SET cp.guide_number = CASE ";
$uniqueIds = [];
$i = 0;
foreach($result as $row){
$guideNumber = $this->generateGuideNumber($param1, $param2);
$dql .= "WHEN cp.uniqid = '".$row['uniqid']."' THEN '$guideNumber' ";
$uniqueIds[] = "'".$row['uniqid']."'";
$i++;
if($i % 100 === 0){
$dql .= " END WHERE uniqid IN (".implode(',', $uniqueIds).")";
$this->entityManager->createQuery($dql)->execute();
$dql = $dqlStaticPartial;
}
}
(I know, this is not okay, i'm going to put this in a transaction and I will execute the query after every 100th iteration and I'm gonna escape inputs etc...first I want my query to work)
My guess is that you have more then 100 records and if that is the case then one of the problems you're creating is that your query ends up like this:
UPDATE cp SET cp.guide_number = CASE
WHEN cp.uniqid = '1' THEN '1234'
-- more rows ...
WHEN cp.uniqid = '99' THEN '4563'
END
WHERE uniqid IN (1,...,99)
WHEN cp.uniqid = '100' THEN '1234'
-- more rows ...
WHEN cp.uniqid = '199' THEN '4563'
END
WHERE uniqid IN (100,...,199)
etc. etc.
You should clear the allready executed part of your query and then restart building up your query once you reach ($i % 100 === 0)
I have a simple SELECT statement:
$sql = "SELECT count(*) FROM member_temp WHERE member_Id = '".trim($id)."'";
The member_Id column is a VARCHAR(25) NOT NULL
This works fine until the SELECT gets to a member_Id that has a alpha value behind it, like 1126A. It then throws the error
Could not prepare SQL statement:SELECT count(*) FROM member_temp WHERE member_Id = '1126A'
As a test I remove this record and the SELECT runs fine until the next value with an A.
How can I make this query run and process records with an alpha character?
This is part of larger block of code that deletes records not found from the main member table:
while ( #data = $sth->fetchrow_array() ) {
my $id = $data[2];
my $pk = $data[0];
$sql = "SELECT count(*) FROM member_temp WHERE member_Id = '" . trim($id) . "'";
#print "$sql\n";
my $xth = $dbh->prepare($sql);
$xth->execute();
$cRows = $xth->fetchrow_array() || die "Could not prepare SQL statement:$sql";
#print "$cRows\n";
if ( $cRows == 0 ) {
$sql = "DELETE FROM member WHERE sys_Id = " . $pk;
$xth = $dbh->prepare($sql);
$xth->execute();
$cnt_del++;
}
Ok, this is Perl answer now :)
There is nothing wrong with your query (except that it is not preparing statements correctly and you are using string interpolation).
In the comments you said if this query is run directly
It completes successfully and returns a value of 0
Then in your code you have one condition which is wrong
$cRows = $xth->fetchrow_array() || die "Could not prepare SQL statement:$sql";
That means even if the query executed correctly but has 0 rows, it should show you that error message, which is not right.
So all you need to do is to fix that error message. That die should be shown if the query failed to execute, not when it executed correctly but has no results.
You can correct your query like
$sql = "SELECT count(*) FROM member_temp WHERE member_Id = ?";
$xth = $dbh->prepare($sql);
$xth->execute($id) or die("Failed to execute query:". $xth->errstr);
And your rows check can be
if ($xth->rows == 0)
// No match found
I am using the Perl DBI module with MySQL and trying to get the initial value before adding 1 to it when updating a row.
If the current value was 1000 I need to return the value of 1000 and then add 1 to the value.
I use this statement in perl to use one transaction...
update TABLE_NAME set ID = (\#cur_value := ID) + 1
I know I can do a select then an update as two statements or lock the tables manually but transactions happen so fast on our platform that it may cause inconsistencies and this is the fastest way to do it.
However I simply cannot find a way to return the original value before the increment using this statement.
It works fine in ASP as below:
qry = "update V15_TRACKING set TRACKING_ID = (#cur_value := TRACKING_ID) + 1 where TRACKING_TYPE='ABC'"
Set oRS = oConn.Execute(qry)
qry = "select #cur_value"
if not oRS.EOF then
while not oRS.EOF
CurrTrackingID = oRs.Fields("#cur_value")
oRS.movenext
wend
oRS.close
end if
Please can someone advise me what I need to do to return the original value in Perl as I have searched everywhere and tried all sorts of solutions.
A snippet to show what you're actually doing in perl, and your result would help diagnose what is going on in your script.
I tried this trivial example:
The DB:
CREATE DATABASE TEST;
CREATE TABLE foo (
id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
val int(11) NOT NULL
);
INSERT INTO foo (val) VALUES (1);
And the Perl
#!/bin/env perl
use strict;
use warnings;
use Data::Dumper;
use DBI;
my $dbh = DBI->connect('DBI:mysql:database=test', 'dbuser', 'dbpass');
my $select = $dbh->prepare('SELECT * FROM foo WHERE id=?');
my $select_old_val = $dbh->prepare('SELECT #old_val');
my $update = $dbh->prepare('UPDATE foo SET val=(#old_val := val) + 1 WHERE id=?');
$update->execute(1);
$select_old_val->execute();
$select->execute(1);
while (my $row = $select_old_val->fetchrow_hashref) {
print Dumper $row;
}
while (my $row = $select->fetchrow_hashref) {
print Dumper $row;
}
And after a few goes:
$ perl select_and_update.pl
$VAR1 = {
'#old_val' => '10'
};
$VAR1 = {
'id' => '1',
'val' => '11'
};
I want to insert data from a fifo pipe into a mysql table
my script as follows:
#!/usr/bin/perl
#Script to read data out of a named pipe and write to MySQL database.
$| = 1;
use strict;
use DBI();
my $filename;
my $inputline;
my $linenumber;
my #arr;
$filename = "./SEC_fifo";
open(FIFO, "+< $filename") or die "FIFO error on $filename $!";
my $dbh = DBI->connect("DBI:mysql:database=ecdb;host=localhost",
"user", "[pwd]",
{'RaiseError' => 1});
while (<FIFO>)
{
$inputline = $_;
#arr = split(/,/,$inputline);
# Quit read loop when requested.
last if($inputline =~ /quit/i);
chop $inputline;
$linenumber++;
print "Got: [$inputline], ";
my $sql="";
my $sth="";
my #row;
print "output.\n".$arr[0],$arr[1],$arr[2],$arr[3],$arr[4],$arr[5],$arr[6],$arr[7],$arr[8],$arr[9],$arr[10],$arr[11],$arr[12],$arr[13]."\n";
# perl trim function - remove leading and trailing whitespace
my $str = $arr[6] ;
$str =~ s/^\s+//;
$str =~ s/\s+$//;
if($str ne 'Normal')
{
print "arr[6]=".$arr[6]."\n";
$sql = "select Hid from Devices where hostname = '$arr[2]'";
print $sql."\n";
$sth = $dbh->prepare($sql);
$sth->execute || die "Could not execute SQL statement ... maybe invalid? \n\n $sql
\n";
#row=$sth->fetchrow_array;
my $hid1=#row[0];
$sql = "select Hid from Devices where hostname = '$arr[3]'";
$sth = $dbh->prepare($sql);
$sth->execute || die "Could not execute SQL statement ... maybe invalid? \n\n $sql \n";
#row=$sth->fetchrow_array;
my $hid2=#row[0];
$sql = "select Eid from Event where Eventname = '$arr[8]' and severity = '$arr[9]' and Trapoid='$arr[10]'";
print "sql=".$sql."\n";
$sth = $dbh->prepare($sql);
$sth->execute || die "Could not execute SQL statement ... maybe invalid? \n\n $sql \n";
#row=$sth->fetchrow_array;
my $eid1=#row[0];
#print "eid1=".#row[0]."\n";
$sql = "select Eid from Event where Eventname = '$arr[11]' and severity = '$arr[12]' and Trapoid='$arr[13]'";
#print "sql=".$sql."\n";
$sth = $dbh->prepare($sql);
$sth->execute || die "Could not execute SQL statement ... maybe invalid? \n\n $sql \n";
#row=$sth->fetchrow_array;
my $eid2=#row[0];
print "eid1=".$eid1."\n";
print "eid2=".#row[0]."\n";
$sql = "insert into secresult (Hid_1,Hid_2,interface_1,interface_2,ifindex_1,ifindex_2,Eid_1,Eid_2,start_time_1,start_time_2,effect_range,description) values ($hid1,$hid2,'$arr[4]','$arr[5]',$arr[6],$arr[7],$eid1,$eid2,'$arr[0]','$arr[1]','$arr[14]','$arr[15]')";
print $sql."\n";
$dbh->do($sql);
print "inserted it.\n";
}
else
{
$sql = "select Hid from Devices where hostname = '$arr[1]'";
$sth = $dbh->prepare($sql);
$sth->execute || die "Could not execute SQL statement ... maybe invalid? \n\n $sql \n";
#row=$sth->fetchrow_array;
my $hid=#row[0];
$sql = "select Eid from Event where trapoid = '$arr[0]' and severity != 'Normal'";
#print "sql=".$sql."\n";
$sth = $dbh->prepare($sql);
$sth->execute || die "Could not execute SQL statement ... maybe invalid? \n\n $sql \n";
#row=$sth->fetchrow_array;
my $eid=#row[0];
$sql = "select id from (SELECT * FROM secresult WHERE end_time_1 ='' and Hid_1=$hid and interface_1 ='$arr[4]' and ifindex_1=$arr[5] ORDER BY start_time_1 DESC LIMIT 1) result where result.eid_1 = $eid";
print "sql=".$sql."\n";
$sth = $dbh->prepare($sql);
$sth->execute || die "Could not execute SQL statement ... maybe invalid? \n\n $sql \n";
#row=$sth->fetchrow_array;
my $id=#row[0];
if($id !="")
{
$sql = "update secresult set end_time_1 = '$arr[2]' where id = '$id'";
print $sql."\n";
$dbh->do($sql);
print "updated it.\n";
}
else
{
$sql = "select id from (SELECT * FROM secresult WHERE end_time_2 ='' and Hid_1=$hid and interface_2 ='$arr[4]' and ifindex_2=$arr[5] ORDER BY start_time_2 DESC LIMIT 1) result where result.eid_2 = $eid";
print "sql=".$sql."\n";
$sth = $dbh->prepare($sql);
$sth->execute || die "Could not execute SQL statement ... maybe invalid? \n\n $sql \n";
#row=$sth->fetchrow_array;
$id=#row[0];
$sql = "update secresult set end_time_2 = '$arr[2]' where id = '$id'";
print $sql."\n";
$dbh->do($sql);
print "updated it.\n";
}
}
}
my $sth = $dbh->prepare("SELECT * FROM secresult"); $sth->execute(); while (my $ref = $sth->fetchrow_hashref()) {
print "Found a row: id = $ref->{'id'}, line = $ref->{'textline'}\n"; }
$sth->finish();
$dbh->disconnect();
exit;
i can insert into to database by the script,but when i execute the script to listening , after few minute get data from fifo ,the script will be shown the error message "DBD::mysql::st execute failed: MySQL server has gone away at ./Db_code.pl line 66, line 5"
the line 66 is " $sth->execute || die "Could not execute SQL statement ... maybe invalid? \n\n $sql \n";"
Just make sure dbh is still connected (ping) before any DB operations and reconnect (or clone)
while (<FIFO>)
{
if ( ! $dbh->ping ) {
$dbh = $dbh->clone() or die "cannot connect to db";
}
...
} #end FIFO
See also http://www.perlmonks.org/?node_id=497849
As an alternative you can use the mysql auto reconnect feature.
$dbh->{mysql_auto_reconnect} = 1;
The main reason that could result in this error is that the client is not able to reach the server for some reason. It can occurs after the server has timed out and closed the connection.
In such case you have to gather some statistic to check if your MySQL server is slow or not and to check your SQL statement.
Here you can refer to the error documentation from official Mysql docs: MySQL Server has gone away.
Please I am having problem tracking down the problem with this code I have been trying for hours . it gives me the error DBD::mysql::st fetchrow_hashref failed: fetch() without execute() at line 15
sub Split_Into_Words
{
#### Connection parameters ############################
my $dsn = "dbi:mysql:malware:localhost:3306";
my $user = 'root';
my $passwd = 'sxxxs';
########################################################
my $domain ;
my $countDir = 0 ;
my $file = shift ;
my $labelID = (split(/[.]/ , $file))[1] ; ### Split and get the middle value since format is temporay.
#### Query String ############################################################################
my $InsertIntoHostTable_QS = "INSERT INTO TB_host(HostName , UrlID , ExtID) Values (? , ? , ? ) ; ";
my $InsertIntoDomainTable_QS = "INSERT IGNORE INTO TB_Domain(Domain) values (?) ;" ;
my $InsertIntoArgVal_QS = "INSERT INTO TB_Arg_Value(Arg, URL_ID) VALUES (? , ? ) ; " ;
my $InsertIntoDirectory_QS = "INSERT INTO TB_Directory(DIRNAME , DEPTH , URLID) VALUES (? , ? , ? )" ;
my $InsertIntoExtension_QS = "INSERT IGNORE INTO TB_Extension (Extension) values ( ? ) ; ";
my $InsertIntoExtensionNULL_QS = "INSERT IGNORE INTO TB_Extension (ID , Extension) values (? , ? ) ; ";
my $SelectString = " Select URL , ID from TB_URL where LabelID = '" . $labelID."';";
my $InsertIntoFileName_QS = "INSERT IGNORE INTO TB_FileName( filename) VALUES (?) ; " ;
###################################################################################################
my $DBIConnect = DBI->connect($dsn , $user , $passwd) or die("Cannot connect to datadbase $DBI::errstr\n");
print ("Splitting Into Words \n");
######Initialization of a default DB value #################
my $sth = $DBIConnect->prepare( $InsertIntoExtensionNULL_QS);
$sth->execute(1 , 'null') or die("Error Executing the Insertion" . $sth->errstr );
$sth->finish();
#############################################################
$sth = $DBIConnect ->prepare($SelectString);
sleep(10);
open (FH , '<' , $file); # Open file to be read from disk
my $i = 0;
$sth->execute() or die("Error Executing the Insertion" . $sth->errstr );
->line 15 while(my $hash_ref = $sth->fetchrow_hashref )
{
my $extensionID = "1";
my $intialURL = $hash_ref->{URL} ;
my $initialID = $hash_ref->{ID};
}
}
I'm not sure if this is the issue, but you may not need the finish after the insert. From the DBI doc:
Indicate that no more data will be fetched from this statement handle
before it is either executed again or destroyed. You almost certainly
do not need to call this method.
Adding calls to finish after loop that fetches all rows is a common
mistake, don't do it, it can mask genuine problems like uncaught fetch
errors.
If that is the problem, you may want to create a second statement handler for the select call.
Apart from the annoyingly long SQL variable names, $SelectString should contain a "?", in case $labelID contains something that could break the query or cause an injection.
prepare() doesn't absolutely require a "?", but if execute has parameters, then there must be a matching number of "?" in the query string.
First $sth->finish() is not needed because the query is an insert and doesn't return any rows.
Second 'die' should be "Error executing query", because it executing $SelectString
Note SQL convention is to write all in uppercase, and for extra safety enclose field names in backticks. Queries do not end with semicolon. Also note that "my" variables are local to that between braces, { } so that my variables in the while loop will be unavailable afterwards.
Suggest formatting thus:
sub Split_Into_Words {
#### Connection parameters ############################
my $dsn = "dbi:mysql:malware:localhost:3306";
my $user = 'root';
my $passwd = 'sxxxs';
########################################################
my $domain ;
my $countDir = 0 ;
my $file = shift ;
my $labelID = (split(/[.]/ , $file))[1] ; ### Split and get the middle value since format is temporary.
#### Query String ############################################################################
my $InsertIntoHostTable_QS = "INSERT INTO `TB_host` (`HostName`,`UrlID`,`ExtID`) VALUES (?,?,?)";
my $InsertIntoDomainTable_QS = "INSERT IGNORE INTO `TB_Domain` (`Domain`) VALUES (?)";
my $InsertIntoArgVal_QS = "INSERT INTO `TB_Arg_Value` (`Arg`,`URL_ID`) VALUES (?,?)";.
my $InsertIntoDirectory_QS = "INSERT INTO `TB_Directory` (`DIRNAME`,`DEPTH`,`URLID`) VALUES (?,?,?)";
my $InsertIntoExtension_QS = "INSERT IGNORE INTO `TB_Extension` (`Extension`) VALUES (?)";
my $InsertIntoExtensionNULL_QS= "INSERT IGNORE INTO `TB_Extension` (`ID`,`Extension`) VALUES (?,?)";
my $SelectString = "SELECT `URL`,`ID` FROM `TB_URL` WHERE `LabelID`=?";
my $InsertIntoFileName_QS = "INSERT IGNORE INTO `TB_FileName` (`filename`) VALUES (?)";
###################################################################################################
my $DBIConnect = DBI->connect($dsn , $user , $passwd) or die("Cannot connect to datadbase $DBI::errstr\n");
print ("Splitting Into Words \n");
######Initialization of a default DB value #################
my $sth = $DBIConnect->prepare( $InsertIntoExtensionNULL_QS);
$sth->execute(1 , 'null') or die("Error executing the Insertion: " . $sth->errstr );
# $sth->finish(); # not needed because it's an insert
#############################################################
$sth = $DBIConnect->prepare($SelectString);
sleep(10);
open (FH , "<$file"); # Open file to be read from disk
my $i = 0;
$sth->execute($labelID) or die("Error executing query: " . $sth->errstr );
while(my $hash_ref = $sth->fetchrow_hashref ) {
my $extensionID = "1";
my $intialURL = $hash_ref->{URL};
my $initialID = $hash_ref->{ID};
}