Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
First post. Please bear with me if formatting isn't one-hundred per-cent. Thanks.
I'm in the process of migrating from an older centos server to one with a more up-to-date Debian 9 operating system and I've run into several program incompatibilities... but it hasn't been all bad. I have the full LAMP stack working and "several databases and their pages" up and running just fine. Unfortunately, I've run into a snag. I'll walk through it...
In my www-accessible perl script, I don't include login details in a publically accessible location. I initiate MySQL like so...
use DBI ;
require "connect.cgi" ;
&my_connect();
In the connection file, I have like this...
sub my_connect {
$dsn = "DBI:mysql:dbmydatabase:localhost" ;
$user_name = 'uMyUser';
$user_pass = 'pMyPassword';
$dbh = DBI->connect($dsn, $user_name, $user_pass, { RaiseError => 1} ) ;
return $dbh;
}
So far, so good. I've checked the connection like so...
if(!$dbh){
die "failed to connect to MySQL database DBI->errstr()";
}else{
print("Connected to MySQL server successfully.\n");
}
... and all appears fine and dandy.
I also call for execution from the connection file, like so...
sub Do_SQL {
$sth = $dbh->prepare($SQL);
$rv = $sth->execute;
return $sth;
}
And for the task -- I want to check for the existence of a record in a database. So I set it up and run it...
$SQL = qq/ SELECT EXISTS(SELECT 1 FROM `table1` WHERE `col1` = '$col1') /;
&Do_SQL;
Trouble is, I'm getting an empty query message.
DBD::mysql::st execute failed: Query was empty at connect.cgi line 54.
I have tried a few variations on the query. For example...
$SQL = qq/ SELECT count(*) FROM `table1` WHERE `col1` = '$col1') /;
$SQL = qq/ SELECT `id` FROM `table1` WHERE `col1` = '$col1') /;
$SQL = qq/ SELECT * FROM `table1` /;
... but the result is the same.
I might be tempted to suggest there is some sort of version incompatibility between old and new set up but I have several other pages with similar configuration working fine. A difference might be that the stuff I have working was backed up and restored from previous databases. Whereas this current problem is the first new database I've created from scratch on the new server.
Interestingly, the queries I note above work on the command line. They do not work within the perl script. I've done several searches but can find nothing to point toward a solution. So here I am seeking the benefit and wisdom of more experience than my own.
Thanks for your insights.
Related
Throughout some testings; a little question popped up. When I usually code database updates; I usually do this via callbacks which I code in PHP; to which I simply pass a given mysqli connection object as function argument. Executing all queries of for example three queries across the same single connection proved to be much faster than if closing and reopening a DB connection for each query of a given query sequence. This also works easily with SQL transactions, the connection can be passed along to callbacks without any issues.
My question is; can you also do this with prepared statement objects ? What I mean is, considering we successfully established a $conn object, representing the mysqli connection, is stuff like this legit? :
function select_users( $users_id, $stmt ) {
$sql = "SELECT username FROM users where ID = ?";
mysqli_stmt_prepare( $stmt, $sql );
mysqli_stmt_bind_param( $stmt, "i", $users_id );
mysqli_stmt_execute( $stmt );
return mysqli_stmt_get_result( $stmt );
}
function select_labels( $artist, $stmt ) {
$sql = "SELECT label FROM labels where artist = ?";
mysqli_stmt_prepare( $stmt, $sql );
mysqli_stmt_bind_param( $stmt, "s", $artist );
mysqli_stmt_execute( $stmt );
return mysqli_stmt_get_result( $stmt );
}
$stmt = mysqli_stmt_init( $conn );
$users = select_users( 1, $stmt );
$rappers = select_labels( "rapperxyz", $stmt );
or is it bad practice; and you should rather use:
$stmt_users = mysqli_stmt_init( $conn );
$stmt_rappers = mysqli_stmt_init( $conn );
$users = select_users( 1, $stmt_users );
$rappers = select_labels( "rapperxyz", $stmt_rappers );
During the testing; I noticed that the method by using a single statement object passed along callbacks works for server calls where I call like 4 not too complicated DB queries via the 4 according callbacks in a row.
When I however do a server call with like 10 different queries, sometimes (yes, only sometimes; for pretty much the same data used across the different executions; so this seems to be weird behavior to me) I get the error "Commands out of sync; you can't run this command now" and some other weird errors I've never experienced, like the amount of variables not matching the amount of parameters; although they prefectly do after checking them all. The only way to fix this I found after some research was indeed by using different statement objects for each callback. So, I just wondered; should you actually ALWAYS use ONE prepared statement object for ONE query, which you then may execute N times in a row?
Yes.
The "commands out of sync" error is because MySQL protocol is not like http. You can't send requests any time you want. There is state on the server-side (i.e. mysqld) that is expecting a certain sequence of requests. This is what's known as a stateful protocol.
Compare with a protocol like ftp. You can do an ls in an ftp client, but the list of files you get back depends on the current working directory. If you were sharing that ftp client connection among multiple functions in your app, you don't know that another function hasn't changed the working directory. So you can't be sure the file list you get from ls represents the directory you thought you were in.
In MySQL too, there's state on the server-side. You can only have one transaction open at a time. You can only have one query executing at a time. The MySQL client does not allow you to execute a new query where there are still rows to be fetched from an in-progress query. See Commands out of sync in the MySQL doc on common errors.
So if you pass your statement handle around to some callback functions, how can that function know it's safe to execute the statement?
IMO, the only safe way to use a statement is to use it immediately.
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
I have a MySQL Database but my function is not working. I want to know how many results I get for my database query, but I just get nothing back, not even 0. I also tried $values->num_rows; same result. Do not get back a number... just nothing
My Code:
$values = $database->query("SELECT * FROM `wp_all_import_xml` WHERE name = '$title' AND price = '$price' AND shop = '$shop' AND link = '$link'");
$count_values = mysqli_num_rows($values);
echo "ERROR by detecting Product (More than 1 Row return by SQL!): " .$title. " Preis: " .$price. " Shop: " .$shop. " Link: " .$link. "\t num_rows: " .$count_values. "\n";
How can I get the amount of rows I get returned?
Greetings
The mysqli_num_rows function does work.
The most likely explanation for the observed behavior is an error is occurring and being ignored.
For debugging this, start with making sure error reporting is enabled.
Modify the code to check the return from the query. Verify that it's not returning FALSE, by performing a conditional test.
if ($values = $mysqli->query(...) ) {
// query returned a resultset
} else {
// query returned FALSE
}
If all we need to retrieve is the number of rows, then we can use COUNT(*) in the SELECT list.
if ( $res = $mysqli->query("SELECT COUNT(*) AS cnt FROM ... ") ) {
If the query is successful, then we get a row back, even if the count is zero. And we can easily process the result like we process results from other queries, without the need to muck with num_rows, and worrying about whether the query is buffered or unbuffered, etc.
We're going to assume that $database is a mysqli connection, and not a PDO connection, since the code includes a call to the mysqli_num_rows function. If it's PDO connection, then "num_rows doesn't work".
The code in the question follows the pattern frequently seen in code that is vulnerable to SQL Injection. (In this excerpt, we can't determine if the values of the variables being included in the SQL text are potentially unsafe, so we can't tell if it's vulnerable or not.)
If this was a prepared statement with bind placeholders, then we could tell.
Use prepared statements with bind placeholders. It isn't hard.
This question already has answers here:
Perl DBI - run SQL Script with multiple statements
(4 answers)
Closed 8 years ago.
At the moment, I am running multiple statements on MYSQL as below;
my $sth1 = $dbh->prepare("ALTER TABLE whatever....");
my $sth2 = $dbh->prepare("UPDATE whatever....");
my $sth3 = $dbh->prepare("ALTER TABLE whatever....");
my $sth4 = $dbh->prepare("DROP TABLE whatever....");
my $sth5 = $dbh->prepare("DROP TABLE whatever....");
$sth1->execute;
$sth1->finish;
$sth2->execute;
$sth2->finish;
$sth3->execute;
$sth3->finish;
$sth4->execute;
$sth4->finish;
$sth5->execute;
$sth5->finish;
This code works fine.
However, I have about more than 50 such queries. So you can imagine the magnitude of above lines. What I pasted above is just 5 queries.
Question:
Is there a better elegant way of running multiple MySQL queries/Statements using Perl DBI ?
At the very least, you should just iterate of your sql strings. Also would be a good idea to add or die to your execute methods:
my #sql = (
q{ALTER TABLE whatever....},
q{UPDATE whatever....},
q{ALTER TABLE whatever....},
q{DROP TABLE whatever....},
q{DROP TABLE whatever....},
);
for (#sql) {
my $sth = $dbh->prepare($_);
$sth->execute or die $dbh->errstr;
}
DBD::mysql has a parameter mysql_multi_statements:
As of MySQL 4.1, support for multiple statements separated by a semicolon (;) may be enabled by using this option. Enabling this option may cause problems if server-side prepared statements are also enabled.
Full error:
Fatal Error: Uncaught exception 'PDOException' with message
'SQLSTATE[HY000]: General error -1 from storage engine'
in C:\MyApacheDir\MyPHPFile.php:33
Line 33 is the ->execute() of my PDO prepared statement. This behaviour does not always occur; when performing the exact same action, it might not happen.
My query:
// Make new permissions
$sql = "INSERT INTO permissions (
doc_id,
user_id,
write_access
) VALUES (
:doc_id,
:user_id,
:write_access
);";
$stmt = $dbConn->prepare($sql);
ForEach ($permitArr as $permit) {
$stmt->bindValue(":doc_id", $_POST['doc_id'], PDO::PARAM_INT);
$stmt->bindValue(":user_id", $permit[0], PDO::PARAM_INT);
$stmt->bindValue(":write_access", $permit[1], PDO::PARAM_INT);
$stmt->execute();
}
where permitArr contains an array of permissions of the form Array[index][info] where [info] is either 0 or 1 corresponding to user and access level respectively.
As stated, this error only occurs sometimes; other iterations of the exact same query (literally, identical information is passed) work fine.
Does anybody know what the -1 error code is caused from? Maybe it's just inferior search skills, but I couldn't find it anywhere.
I'm working off of an Apache 2.2 localhost with MySQL 5.6 in IE8.
Seems fishy. I can't find an error with that number, so that normally means there is an outside factor at play. I would try the following:
1.) Create a new table and try the code on the new table.
2.) Create a new schema with a new table and try the code again.
3.) Run chkdsk on your drive to make sure there aren't any cluster problems.
4.) Reboot.
I have looked all day for an answer and tried all my thoughts as well.
What I am doing is seemingly easy but, VERY difficult for me.
I must do this without installing additional Perl Modules.
I am trying to select a list of names that were entered between two dates.
I know these examples are obviously not strict or safe but, I am just trying to figure out.
I will fix all that later once I get the means to my required result figured out.
The incoming data example for the $to and $from:
$to= '2013-03-01 00:00:01';
$from= '2013-03-01 23:23:59';
The entered column in the database is in that format as well.
I tried:
$names = DBI->connect("$sdb","$user","$password");
$getnames = $names->prepare(qq{SELECT DISTINCT `name`
FROM `users`
WHERE `entered`
BETWEEN UNIX_TIMESTAMP($from)
AND UNIX_TIMESTAMP($to)
AND `active` = ?
AND `confirmed` = ?
ORDER BY `entered` DESC});
$getnames->execute($active,$confirmed);
And I tried:
$names = DBI->connect("$sdb","$user","$password");
$getnames = $names->prepare(qq{SELECT DISTINCT `name`
FROM `users`
WHERE `entered` BETWEEN ?
AND ?
AND `active` = ?
AND `confirmed` = ?
ORDER BY `entered` DESC});
$getnames->execute($from,$to,$active,$confirmed);
I also tried many variations of the above two but, I keep getting:
Can't call method "prepare" on an undefined value at users-by-date.pl line 120 even when I hard code the variables.
Can someone show me how to do this? My query executes fine in phpmyadmin but, I need the result printed to a page using Perl. I believe it has something to do with the dates format. NO, I cannot change the dates format in the database.
Thanks so much.
$names = DBI->connect("$sdb","$user","$password");
should be
$names = DBI->connect($sdb, $user, $password) or die "Couldn't connect to database: $!";
Adding the or die... part will serve two purposes:
1) It will stop your program immediately, preventing you from getting spurious errors later when you try to use the database handle, when the real problem is that it failed to connect to the database.
2) It will tell you why the database connection failed. (The database's error message will be in $!.)
I also removed the double quotes around the variables because they're not needed.