Perl DBI select providing wrong values using bind_columns - mysql

I have this Perl code:
my $cmd = "
SELECT COUNT(id)
FROM tblUsers
WHERE UPPER(username) = UPPER(?) AND password = ?
";
db_connect();
my $sql = $dbh->prepare($cmd);
my $count = 2;
$sql->execute(
$args{login_username},
crypt($args{login_password}, $args{login_username})
) or die "SQL Error: ".$sql->errstr;
$sql->bind_columns(\$count);
$sql->fetch;
which is returning 0, but should be returning a 1
If I output the following:
$msg = "wrong username/password: $count;$args{login_username};$args{login_password};" . crypt($args{login_password}, $args{login_username});
I get:
wrong username/password: 0;skeniver;password;skh9dtk2bCasY
and the crypt part is exactly what I have in the database. Running the same values in MySQL returns a count of 1.
I really can't figure out what's going wrong here.
Does anyone else see something I'm missing?

Assuming your select returns a non 0 value and assuming that the column password in tblUsers has skh9dtk2bCasY for username=skeniver, Try
$sql->execute($args{login_username}, crypt($args{login_password},$args{login_username}))
or die "SQL Error: ".$sql->errstr;
$count = $sql->fetchrow_array();
Or, if there is a possibility that the query returns multiple rows then-
$sql->execute($args{login_username}, crypt($args{login_password},$args{login_username}))
or die "SQL Error: ".$sql->errstr;
while (($count) = $sql->fetchrow_array()){
print "Count is: $count\n";
}

Related

Multi-line MySQL in Perl

I am trying to pass a command to my database (MariaDB/MySQLi) but Perl's DBI is giving me an error, whatever I try. The thing is that I can execute the MySQL fine in phpMyAdmin without fault. The error that I receive is:
DBD::mysql::st execute failed: 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 SELECT DISTINCT t.bf FROM wrpec t JOIN wrpec r ON t.path LIKE r.path || '%' at line 2 at
retrieve-includes.pl line 20.
DBD::mysql::st fetchrow_array failed:
fetch() without execute() at retrieve-includes.pl line 22.
The full test file (fake database obviously) is as below.
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use Data::Dumper;
my $dsn = "DBI:mysql:database=mydatabase;host=machine";
my $dbh = DBI->connect($dsn, 'root', '') or die "Couldn't connect to database: " . DBI->errstr;;
my $request_includes = "
SET sql_mode = PIPES_AS_CONCAT;
SELECT DISTINCT t.bf
FROM `wrpec` t
JOIN `wrpec` r
ON t.path LIKE r.path || '%'
WHERE r.bf = 'WRPECsmain\%hd' AND t.has_tree;";
my $sth = $dbh->prepare($request_includes) or die "Couldn't prepare statement: " . $dbh->errstr;
$sth->execute();
while (my #row = $sth->fetchrow_array()) {
print Dumper(\#row);
}
$sth->finish();
I have also tried some ideas I found online: using a clean-up sub that replaces all white-space characters by hard spaces to make sure you're passing a string, and I also tried this notation (I forgot the name) but it doesn't work either (same error).
my $request_includes = <<"REQUEST_INCLUDES";
SET sql_mode = PIPES_AS_CONCAT;
SELECT DISTINCT t.bf
FROM `wrpec` t
JOIN `wrpec` r
ON t.path LIKE r.path || '%'
WHERE r.bf = 'WRPECsmain\%hd' AND t.has_tree;
REQUEST_INCLUDES
You're getting a SQL syntax error because by default, DBD::mysql doesn't allow you to execute multiple statements at once. You should run two separate DBI commands instead:
$dbh->do( q{SET sql_mode = 'PIPES_AS_CONCAT'} );
my $sth = $dbh->prepare(q{
SELECT DISTINCT t.bf
FROM `wrpec` t
JOIN `wrpec` r
ON t.path LIKE r.path || '%'
WHERE r.bf = 'WRPECsmain\%hd' AND t.has_tree
});
I was trying to create a script that works on MySQL as wel as PostgreSQL without changes.
Enable MySQL's ANSI mode and double quote your identifiers:
$dbh->do( q{SET sql_mode = 'ANSI'} ) if $mysql;
my $sth = $dbh->prepare(q{
SELECT DISTINCT t.bf
FROM "wrpec" t
JOIN "wrpec" r
ON t.path LIKE r.path || '%'
WHERE r.bf = 'WRPECsmain\%hd' AND t.has_tree
});
There are a couple other issues, though:
unescaped _ and % in r.path will be interpreted as wildcards
'foo' LIKE 'foo%' is true
To only fetch rows where the t.path is a prefix of r.path, but they're not equal, do:
SELECT DISTINCT t.bf
FROM "wrpec" t
JOIN "wrpec" r
ON POSITION(t.path IN r.path) = 1
AND t.path != r.path
WHERE r.bf = 'WRPECsmain\%hd'
AND t.has_tree

check if_null statement don't work

I simply want to check, if a query give me 'NULL' as the result.
$check = ' SELECT some_data FROM user
WHERE condition = my_condition LIMIT 1';
if ( is_null($check) )
{
echo "yep, it's null";
}
But i don't get the echo. The query definitly gives me the result 'NULL'. Whats wrong?
Just execute the query and fetch a row of results.

DQL And Equivalent SQL Not Returning Same Number Of Result Set

Here is my doctrine query running code:
$queryString = "SELECT ct, count(ct.id), IDENTITY(a.service) "
. "FROM ConnectionTriple ct "
. "JOIN ct.account_connection ac "
. "JOIN Account a WITH (a = ac.account_1 OR a = ac.account_2) "
. "GROUP BY a.service, ct.property, ct.value";
$query = $em->createQuery($queryString);
//echo $query->getSQL();
$results = $query->getResult();
echo count($results);
This above code is returning 2 results(final two from below screenshot) instead of 4(expected). But, when I run the equivalent SQL(got by $query->getSQL()) on phpmyadmin, it returns expected 4 rows which is as below:
Equivalent SQL Query:
SELECT u0_.id AS id0, u0_.value AS value1, u0_.status AS status2, u0_.flag AS flag3, count(u0_.id) AS sclr4, u1_.service_id AS sclr5, u0_.property_id AS property_id6, u0_.account_connection_id AS account_connection_id7 FROM usc_connection_triple u0_ INNER JOIN usc_account_connection u2_ ON u0_.account_connection_id = u2_.id AND (u2_.status = 1) INNER JOIN usc_service_subscriber u1_ ON ((u1_.id = u2_.account_1_id OR u1_.id = u2_.account_2_id)) WHERE (u0_.status = 1) AND (u1_.status = 1) GROUP BY u1_.service_id, u0_.property_id, u0_.value
PHPMyAdmin Result:
So, I guess, there is something wrong in result to object hydration by doctrine, I guess. Anyone has any idea why this might happen/possible solution?
My Doctrine version are:
"doctrine/dbal": "2.3.2",
"doctrine/orm": "2.3.2",
Update: I am certain about the hydration issue. Because, I tried with individual column retrieving and using scalar hydration:
$results = $query->getResult(\Doctrine\ORM\Query::HYDRATE_SCALAR);
This is returning perfectly. Which is expected number of rows, 4 and data as well.
I would say this is totally normal.
As you pointed it out, doctrine (default) hydration mode would represent the result set as an object graph.
An object graph always have a root object (in your case ConnectionTriple ct).
There are 2 ct in your result set (with id 1 and 2).
Doctrine object hydrator will be smart enough to return you and array
of 2 ConnectionTriple objects, each line containing the related data.
The scalar hydrator, howerver will simply return the raw resultset, without building a graph from it.

mysql: issue with the demonstration of sql injection

according to this tutorial:http://www.tizag.com/mysqlTutorial/mysql-php-sql-injection.php
Below codes will demonstrate SQL Injection:
<?php
// a good user's name
$name = "timmy";
$query = "SELECT * FROM customers WHERE username = '$name'";
echo "Normal: " . $query . "<br />";
// user input that uses SQL Injection
$name_bad = "' OR 1'";
// our MySQL query builder, however, not a very safe one
$query_bad = "SELECT * FROM customers WHERE username = '$name_bad'";
// display what the new query will look like, with injection
echo "Injection: " . $query_bad;
In front end, it shows:
Injection: SELECT * FROM customers WHERE username = '' OR 1''
So I just did a test, in phpmyadmin->sql, I run below codes:
SELECT * FROM users WHERE fname = '' OR 1''
And it shows:
#1064 - 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 ''' LIMIT 0, 30' at line 1
Qustion:
supposed it will show every single entry in the "users" table, but not, why? if I want to demonstrate sql injection, how to do it?
A more typical SQL injection would be: $name_bad = "' OR 1=1 -- ";. This would lead to the following SQL:
SELECT * FROM customers WHERE username = '' OR 1=1 -- '
SELECT * FROM users WHERE fname = '' OR 1 = 1
is likely what they meant
edit just looked
SELECT * FROM users WHERE fname = '' OR 1
1 evaluates to true, so just remove the '' after it
also that link is way out of date, Look at mysqli or pdo instead

Executing procedural queries in perl

I have a query like this
set #valid_total:=0;
set #invalid_total:=0;
select week as weekno, measured_week,project_id as project,
role_category_id as role_category,
valid_count,valid_tickets,
(#valid_total := #valid_total + valid_count) as valid_total,
invalid_count,invalid_tickets,
(#invalid_total := #invalid_total + invalid_count) as invalid_total
from metric_fault_bug_project
where measured_week = yearweek(curdate())
and role_category_id = 1 and project_id = 11;
it executes fine in heidi (MySQL client) but when it comes to perl, it gives me this error
DBD::mysql::st execute failed: You have an error in your SQL syntax; check the m
anual that corresponds to your MySQL server version for the right syntax to use
near ':=0;
set :=0;
select week as weekno, measured_week,project_id
as project' at line 1 at D:\Mx\scripts\test.pl line 35.
Can't execute SQL statement: You have an error in your SQL syntax; check the man
ual that corresponds to your MySQL server version for the right syntax to use ne
ar ':=0;
set :=0;
select week as weekno, measured_week,project_id
as project' at line 1
The problem seem to be in the set #valid_total := 0; line.
I am fairly new to Perl. Can anyone help?
this is the complete perl code
#!/usr/bin/perl
#use lib '/x01/home/kalpag/libs';
use DBI;
use strict;
use warnings;
my $sid = 'issues';
my $user = 'root';
my $passwd = 'kalpa';
my $connection = "DBI:mysql:database=$sid;host=localhost";
my $dbhh = DBI->connect( $connection, $user, $passwd) ||
die "Database connection not made: $DBI::errstr";
my $sql_query = 'set #valid_total:=0;
set #invalid_total:=0;
select week as weekno, measured_week,project_id,
role_category_id as role_category,
valid_count,valid_tickets,
(#valid_total := #valid_total + valid_count) as valid_total,
invalid_count,invalid_tickets,
(#invalid_total := #invalid_total + invalid_count) as invalid_total
from metric_fault_bug_project
where measured_week = yearweek(curdate())
and role_category_id = 1 and project_id = 11';
my $sth = $dbhh->prepare($sql_query) or die "Can't prepare SQL statement: $DBI::errstr\n";
$sth->execute() or die "Can't execute SQL statement: $DBI::errstr\n";
while ( my #memory = $sth->fetchrow() )
{
print "#memory \n";
}
You are probably using a double quoted string for your query string, in which case perl looks for the variables #valid_total and #invalid_total. This would imply that you are not using
use strict;
use warnings;
Because otherwise you would already know the error. The result is that perl replaces the variables with nothing, which is reflected in your error.
What you need to do is single quote the string:
my $query = 'set #valid_total:=0;
set #invalid_total:=0;
select week as weekno, measured_week,project_id as project,
role_category_id as role_category,
valid_count,valid_tickets,
(#valid_total := #valid_total + valid_count) as valid_total,
invalid_count,invalid_tickets,
(#invalid_total := #invalid_total + invalid_count) as invalid_total
from metric_fault_bug_project
where measured_week = yearweek(curdate())
and role_category_id = 1 and project_id = 11';
Please always use strict and warnings. if you don't have a variable #valid_total, warnings would then warn you
Possible unintended interpolation of #valid_total in string
and strict would even die.
In double quoted strings you must escape # signs:
"set \#valid_total:=0;"
and if you don't need interpolation at all, better use single quotes.
edit: after I can see the perl code:
rather then doing
my $sql_query = 'set #valid_total:=0;
set #invalid_total:=0;
...';
my $sth = $dbhh->prepare($sql_query)
you should do:
my $sql_query = 'set #valid_total:=0';
my $sth = $dbhh->prepare($sql_query);
$sth->execute;
$sth->finish;
$sql_query = 'set #invalid_total:=0'
$sth = $dbhh->prepare($sql_query);
$sth->execute;
$sth->finish;
...
you cannot execute more than one statement in one query.