Executing a bad PDO query does not yield an error [duplicate] - mysql

This question already has answers here:
Why does this PDO statement silently fail?
(2 answers)
Closed 5 years ago.
Here is an invalid SQL and I m expecting an error, but the PDO error seems always 00000, what did I do wrong?
<?php
run('select now()');
run('pls give me an error');
function run($sql) {
$pdo = new PDO('mysql:host=localhost;db=mydb', $user, $pass);
echo $sql . "<br>";
$sth = $pdo->prepare($sql);
$sth->execute();
$row = $sth->fetch(PDO::FETCH_ASSOC);
print_r($row);
print_r($pdo->errorInfo());
}
And here is the result:
select now()
Array
(
[now()] => 2017-10-03 02:58:09
)
Array
(
[0] => 00000
[1] =>
[2] =>
)
pls give me an error
Array
(
[0] => 00000
[1] =>
[2] =>
)
But I have another page running against the same db and get this error:
Err 1064: You have an error in your SQL syntax;
check the manual that corresponds to your MariaDB
server version for the right syntax to use near
'please give me an error' at line 1
updated
The other page is able to produce error is actually using the following:
$sth = $pdo->query($sql);
print_r($pdo->errorInfo());

For the syntactically or any other way incorrect prepared statements to throw you need to disable prepared statements emulation:
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
By default PDO is set up to emulate those, which honestly does not make much sense.
With emulated prepares disabled PDO::prepare() method creates a temporary server-side object that holds a prepared statement then executes it.
Additionally you may want to enable PDO exceptions, that way it's harder to not handle unexpected query failures:
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
References:
http://php.net/manual/en/pdo.setattribute.php

I've no idea why errorInfo() sometimes doesn't work but I confirm he behavior.
Given that setting error mode to exceptions always works and given that exceptions are much more useful than manual error checking, this function is useless anyway.
So, change your function this way
function run($pdo, $sql, $params = null) {
$sth = $pdo->prepare($sql);
$sth->execute($params);
return $stmt;
}
$pdo = new PDO('mysql:host=localhost;db=mydb', $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
run($pdo, 'select now()');
run($pdo, 'pls give me an error');
and have your error message first class

Related

PERL - DBD::mysql::st execute failed: MySQL client ran out of memory

I've researched a bit and found that using mysql_use_result=1 is supposed to alleviate the memory issue. However, since I am new to this DBI module I don't understand what is happening here:
#!/usr/bin/perl -w
use strict;
use DBI;
my $dbh = DBI>connect('DBI:mysql:blah;host=blah.blah.blah.blah;mysql_use_result=1','blah','blah',{RaiseError => 1});
my $sth = $dbh->prepare('select * from TaqMinute where tradeDate<=\'2014-04-22\' and symbol<=\'AAPL\' ;') ;
if (defined($sth)) {
$sth->execute();
my #row;
while (#row = $sth-> fetchrow_array()) {
print "#row\n" ;
}
}
$sth->finish();
$dbh->disconnect
Before I added mysql_use_result=1, the script would fail after about 1.5 minutes complaining that it ran out of memory. After adding this my query arguments are ignored and I simply get all the data in the database.
Any ideas how to help me or how to use this switch properly? Btw, the database that I am querying is very large.
Thanks in advance!
Craig
Try to use parametized queries, maybe something wrong with your qoutes.
my $dbh = DBI>connect('DBI:mysql:blah;host=blah.blah.blah.blah','blah','blah',{RaiseError => 1});
my $sth = $dbh->prepare_cached('select * from TaqMinute where tradeDate<=? and symbol<=?') ;
die "sth undef!" if ! defined $sth;
$sth->execute('2014-04-22','AAPL');
while (my $rowref = $sth->fetchrow_arrayref()) {
print Dumper($rowref) ;
}
$sth->finish;

Update MySQL within Perl loop failing (fetchrow_array)

I've created a Perl script which is meant to loop through an array (a shortlist of customers who meet certain criteria), execute an external command using system() , then update a field within each row once the operation has completed.
It works on the first record (ie external command executes, customer record updates), however when it gets to the second record I receive this error:
DBD::mysql::st fetchrow_array failed: fetch() without execute() at customer_update.pl
Through some googling I added the $sth->finish(); command, however whether I include it or not (either inside the loop as shown, or straight afterward) I still get the same error.
Can anyone shed any light for me as to what I am doing wrong here?
Here's an extract:
# PERL MYSQL CONNECT()
$dbh = DBI->connect('dbi:mysql:signups', $user, $pw)
or die "Connection Error: $DBI::errstr\n";
# DEFINE A MySQL QUERY
$myquery = "SELECT * FROM accounts WHERE field3 = false";
$sth = $dbh->prepare($myquery);
# EXECUTE THE QUERY
$sth->execute
or die "SQL Error: $DBI::errstr\n";
#records = $sth->rows;
print "Amount of new customers: #records\n\n";
while ( my ($field1, $field2, $field3) = $sth->fetchrow_array() ) {
#execute external command via system();
$update_customer_status = "UPDATE accounts SET field3=true WHERE id=$id";
$sth = $dbh->prepare($update_customer_status);
$sth->execute
or die "SQL Error: $DBI::errstr\n";
print "Customer record modified & MySQL updated accordingly\n\n";
$sth->finish();
}
Building a SQL statement with variables and then prepare()ing it defeats the purpose of the prepare. You should build the SQL statement with a placeholder ? instead of $id, prepare() it, and then execute($id) it. As it is, you are leaving yourself open to SQL injection attacks.
Also, it seems that you are not using the warnings and strict pragmas. These two lines should be at the top of every program you write:
use warnings;
use strict;
They will save you much heartache and frustration in the future.
In your loop, you overwrite the handle over from which you are fetching. Use a different variable. (Changing $sth = ...; to my $sth = ...; will do.) While we're at it, let's move the prepare out of the loop.
my $sth_get = $dbh->prepare("SELECT * FROM accounts WHERE field3 = false");
my $sth_upd = $dbh->prepare("UPDATE accounts SET field3=true WHERE id = ?");
$sth_get->execute();
while ( my ($field1, $field2, $field3) = $sth_get->fetchrow_array() ) {
...
$sth_upd->execute($id);
}
You are stomping on your $sth variable when you execute this line ...
$sth = $dbh->prepare($update_customer_status);
Why not save off the result of $sth->fetchrow_array() to an array variable.
Something like ...
my #select_results_AoA = $sth->fetchrow_array();
... and then iterate over the array ...
for my #row ( #select_resilts_AoA ) {
... instead of ...
while ( my ($field1, $field2, $field3) = $sth->fetchrow_array() ) {

Slim MySQL Exception: SQLSTATE[42000]: Syntax error or access violation: 1064

I'm getting strange error in mysql syntax, non of the posts here helps me.
I'm tring to get next 3 items in table, so I made this function:
$app->get('/items/:id/:nOf', 'getNextItem');
function getNextItem($id,$nOf) {
$sql = "SELECT * FROM `items` WHERE `id` > :id ORDER BY `id` LIMIT :nOf";
try {
$db = getConnection();
$stmt = $db->prepare($sql);
$stmt->bindParam(":id", $id);
$stmt->bindParam(":nOf", $nOf);
$stmt->execute();
$item = $stmt->fetchObject();
$db = null;
echo json_encode($item);
} catch(PDOException $e) {
$result = array("status" => "error", "message" => 'Exception: ' . $e->getMessage(),"fnc"=>"getItems($id,$nOf)");
echo json_encode($result);
}
}
End the output is:
{"status":"error",
"message":"Exception: SQLSTATE[42000]: Syntax error or access violation: 1064
You have an error in your SQL syntax;check the manual that corresponds
to your MariaDB server version for the right syntax to use near ''3''
at line 1","fnc":"getItems(1,3)"}
I don't see anything wrong. Sql command is working fine in phpmyadmin. Original post on slim forum here.
Try to bind $nOf as an integer:
$stmt->bindParam(":nOf", $nOf, PDO::PARAM_INT);

perl eval throwing blank 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.

Perl web service : Using XML RPC

Something is wrong with this code.
#!/use/bin/perl
use strict;
use warnings;
use Frontier::Daemon;
use DBI;
sub credentials {
my ($username, $password) = #_;
my $tablename = "users";
my $user = "db_user";
my $pw = "db_pass";
$dbh = DBI->connect('DBI:mysql:database;host=localhost', $user, $pw, {RaiseError => 1});
$sql = "SELECT username, password FROM $tablename";
$sth = $dbh->prepare($sql);
$sth->execute or die "SQL Error: $DBI::errstr\n";
if ($sth->rows > 0) {
$login_response = "Login Successful";
} else {
$login_response = "Invalid Credentials";
return {'login' => $login_response};
die();
}
}
$methods = {'login.credentials' => \&credentials,};
Frontier::Daemon->new(LocalPort => 8080, methods => $methods)
or die "Couldn't start HTTP server: $!";
This is another problem with your code - you're not doing anything with the supplied username and password. You need to add a where clause to your SQL statement, so:
my $sql = 'SELECT * FROM users WHERE username = ? AND password = ? ';
my $sth = $dbh->prepare($sql);
$sth->execute($username, $password);
However, given that your example is selecting all records from the 'users' table, I'd have thought that credentials() would at least be returning some rows. However, I'm afraid that I've not used Frontier::Daemon in the past, so I'm not able to help on that front.
I also can't see how this code would work given that you are using strictures. $dbh, $sql, $sth and $login_response haven't been declared. So make sure that you're using 'my' in the right places - as per my example above.
To fix the problems you mentioned with returning the correct string - the logic in your if statement isn't quite right. You are returning the string 'Login Successful' when there's a successful login and the hashref { login => $login_response } when no user could be found.
I think the confusion arose from the layout of the braces. I must stress that you try and indent you code properly, which will make it much more readable to yourself and other developers when debugging and maintaining the code in the future.
The following logic should do the job.
if($sth->rows > 0){
return "Login Successful";
}
return "Invalid Credentials";