Perl + DBI + MySQL: How To Run Multiple Queries/Statements [duplicate] - mysql

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.

Related

Using placeholders in MySQL 'COOPERATIVE' LOCK queries [duplicate]

This question already has answers here:
How to include a PHP variable inside a MySQL statement
(5 answers)
Closed 2 years ago.
I have used the so-called cooperative LOCK successfully in MySQL in the past. I had custom functions in my PHP code that ACQUIRE LOCK, RELEASE LOCK and CHECK whether lock is in effect. For example, to lock, I did something like :
//code
"SELECT GET_LOCK( 'unique_string', -1 ) AS acquired"
// code
return ( $row['acquired'] == 1);
And to unlock, I did something like:
// code
"SELECT RELEASE_LOCK( 'unique_string' ) AS released"
// code
return ( $row['released'] == 1 );
And lastly, to check if lock is in effect, I did:
//code
"SELECT IS_USED_LOCK( 'unique_string' ) AS connection_id"
//code
return ( NULL != $row['connection_id'] );
In all these cases, I used PDO::query() method ( i.e. no prepared statement) since my SELECT statements do not contain any parameters
Now, there is a need to concatenate input from the user to unique_string. Is there a way to make the unique_string contain a placeholder so as to use PDO::prepare() and avoid possible SQL injection attack?
Thanks.
There should be no issue at all in using a prepared statement, just use
$statement = PDO::prepare("SELECT GET_LOCK( ?, -1 ) AS acquired");
$statement->execute([$uniqueString]);
You can also used named params, would recommend looking into PDO's prepared statements docs.

DBD::mysql::st execute failed: Query was empty [closed]

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.

I have a sample code, I need to know if it's PDO secure (MySQL) [duplicate]

This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 6 years ago.
$s = "Update member_date" [snip]
$p = $pdo->prepare($s, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$p->execute();
Is that considered a "prepared" statement to justify being secure from SQL injection-type attacks?
UPDATE:
$member_id= htmlspecialchars($_GET['member_id']);
s1 = "
update member_date
set member_date= now()
where member_id= $member_id";
OVERALL QUESTION: "Is this how I should format all my new SQL-related code? I'm just finally making the switch from old mysql statements after reading my (new) error logs. Do I need to add in the question mark placeholders for strings and such or is the format how I have it at the first line of code ok for security purposes? I know the SQL I need to get the tasks accomplished just not the PDO security parts."
No. You are not using a prepared statement as intended. What you should do is add your $id as a paramater, and so separate your content (id) from your code (sql).
While you can do safe SQL with filtering yourself, the absolute best way is to, as you put it:
add in the question mark placeholders for strings and such
You can say "this needs to be an int, and then it will never be something scary like a " or some code that does magic with your query.
PDO is the best way to avoid sql injection that may attack the server. The code looks fine though. But PHP PDO is the absolute right way to avoid sql injection.

I want to Auto add single quotes to my mysql queries

I have couple of mysql queries in perl but some of the values of the where clause contain space between words e.g. the gambia. When my scripts runs with the where clause arguments containing a space it ignore the second word.
I want to know how can I solve this problem i.e. if I type the gambia it should be treated the gambia not the.
If you are using DBI, you can use placeholders to send arbitrary data to database without need to care about escaping. The placeholder is question mark in prepare statement, actual value is given to execute:
use DBI;
$dbh = DBI->connect("DBI:mysql:....",$user,$pass)
or die("Connect error: $DBI::errstr");
my $sth = $dbh->prepare(qq{ SELECT something FROM table WHERE name = ? });
$sth->execute('the gambia');
# fetch data from $sth
$dbh->disconnect();
Edit: If you are composing the query (as you suggested in comments), you can utilize quote method:
my $country = "AND country = " . $dbh->quote('the gambia');
my $sth = $dbh->prepare(qq{ SELECT something FROM table WHERE name = ? $country});
Well, firstly, you should look at using something like DBIx::Class instead of raw SQL in your application.
But if you're stuck with raw SQL, then (assuming that you're, at least, using DBI) you should use bind points in your SQL statements. This will handle all of your quoting problems for you.
$sth = $dbh->prepare('select something from somewhere where country = ?');
$sth->execute('The Gambia');
See the DBI docs for more information about binding.

Perl: Update Multiple Rows with one MySQL Call

Seems that it may not be possible, but hey I might as well ask, I could be wrong. Was wondering if there's anyway for perl to update multiple rows using one MySQL call, I'm using DBI.
Any help or feedback would be greatly appreciated, this is possible in MSSQL through ASP and ASP.net so was wondering if also possible through perl on MySQL.
Thank you for your feedback!
First and most important, you absolutely should not interpolate variables directly into your SQL strings. That leaves open the possibility of SQL injection attacks. Even if those variables don't come from user input, it leaves open the possibility of dangerous bugs that can screw up your data.
The MySQL DBD driver does support multiple statements, though it's turned off by default as a safety feature. See mysql_multi_statements under the Class Methods section in the DBD::mysql documentation.
But a much better solution, which solves both problems at once and is more portable, is to use prepared statements and placeholder values.
my $sth = $dbh->prepare("UPDATE LOW_PRIORITY TableName SET E1=?,F1=? WHERE X=?");
Then, get your data in a loop of some sort:
while( $whatever) {
my ( $EC, $MR, $EM ) = get_the_data();
$sth->execute( $EC, $MR, $EM );
}
You only need to prepare the statement once, and the placeholder values are replaced (and guaranteed to be properly quoted) by the DBD driver.
Read more about placeholders in the DBI docs.
You don't need mysql_multi_statements, as friedo suggests.
You need turn off AutoCommit mode before you call the loop containing your UPDATE command:
**$dbh->{AutoCommit} = 0;**
while( $condition ) {
my $myParam = something();
...
$sth->execute( $myParam ); #your prepared UPDATE statement
...
}
**$dbh->commit();**