Prepared statement with PHP and MSSQL - php

I have an odd scenario about pdos. With prepared statements I get 0 results from database. But hardcoded I get normal results. This is a sql query for mssql (< 2012) to get limited results.
Prepared Statement (just do not wonder about the top and offset variable. I'm setting those in the function just for testing purpose. Also $conn is edited for stackoverflow. The prepare function is reachable from the function, so there is no problem):
public function myFunction($top, $offset) {
try {
$top = 20;
$offset = 1;
$sql = "SELECT TOP :top * FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS t1
FROM myTable) AS nU WHERE t1 >= :offset";
$statement = $conn->prepare($sql);
$statement->execute(array(':top' => $top, ':offset' => $offset));
return $statement->fetchAll();
} catch (Exception $e) {
echo $e->getMessage();
}
}
Result is an array with 0 elements.
But with this it works perfectly:
public function myFunction($top, $offset) {
try {
$top = 20;
$offset = 1;
$sql = "SELECT TOP 20 * FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS t1
FROM myTable) AS nU WHERE t1 >= 1";
$statement = $conn->prepare($sql);
$statement->execute();
return $statement->fetchAll();
} catch (Exception $e) {
echo $e->getMessage();
}
}
With this I get results correctly.
How this is possible? What's wrong with the prepared statement? I have a lot of prepared statements and it worked fine before.
Thanks for answers.
#EDIT - updated code - still not working:
public function myFunction($top, $offset) {
try {
$top = 20;
$offset = 1;
$sql = "SELECT TOP :top * FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS t1
FROM myTable) AS nU WHERE t1 >= :offset";
$statement = $conn->prepare($sql);
$statement->bindParam(':top', $top, PDO::PARAM_INT);
$statement->bindParam(':offset', $offset, PDO::PARAM_INT);
$statement->execute();
return $statement->fetchAll();
} catch (Exception $e) {
echo $e->getMessage();
}
}

It's not allowed to use parameter bindings in PDO for SELECT and FROM part of a sql query.
I replaced the whole query with another one where I don't have to set TOP

Related

mysql query LIMIT use attribute :variable [duplicate]

This question already has answers here:
How to apply bindValue method in LIMIT clause?
(11 answers)
Closed 5 years ago.
i am getting a Syntax error or access violation, when i use the below format in the query.
$limit = $request->getAttribute('limit');
$sql = "SELECT * FROM users WHERE status = 1 ORDER BY date DESC LIMIT :limit";
try{
$db = new db();
$db = $db->connect();
$stmt = $db->query($sql);
$stmt->bindParam(":limit", $limit);
$users = $stmt->fetchAll(PDO::FETCH_OBJ);
$db = null;
if(empty($users)) {
$response->getBody()->write
('
{
"error":
{
"message":"Invalid Request"
}
}');
} else {
$response->getBody()->write(json_encode($users));
}
} catch(PDOException $e) {}
how can i call the attribute for the limit within the query ?
You need do it like below (changes are commented):-
$limit = $request->getAttribute('limit');
$sql = "SELECT * FROM users WHERE status = 1 ORDER BY date DESC LIMIT :limit";
try{
$db = new db();
$db = $db->connect();
$stmt = $db->prepare($sql); //prepare sql first
$stmt->bindValue(':limit',(int)$limit,PDO::PARAM_INT);//tell value is integer
$users = $stmt->fetchAll(PDO::FETCH_OBJ);
if(count($users) ==0) {
$response->getBody()->write('{"error":{"message":"No More Users Exist"}}');
} else {
$response->getBody()->write(json_encode($users));
}
$db = null;
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
The syntax error you see occurs because when you bindParam(), PDO by default inserts your parameter as a string, so the DB engine sees something like LIMIT "10".
So you have 2 choices: you could tell PDO to insert the value as an integer (see #Alive to Die answer) or, more simply, you can cast it to an integer and put it right in the query. Since you're casting first, there is no risk of SQL injection:
$limit = (int) $request->getAttribute('limit');
$sql = "SELECT * FROM users WHERE status = 1 ORDER BY date DESC LIMIT $limit";
Symply put your $limit variable in query
$limit = $request->getAttribute('limit');
$sql = "SELECT * FROM users WHERE status = 1 ORDER BY date DESC LIMIT $limit";
In PDO define it as an INT
$stmt->bindParam(':limit', $limit, PDO::PARAM_INT);
It's better to use prepare and execute statement like :
$limit=10
$req=$db->prepare('SELECT * FROM users WHERE status = ? ORDER BY date DESC LIMIT ?');
$req->execute(array(1, $limit));
I never use bindParam statement.

Getting correct Total Row count and Row Numbers for Pagination

Now I have done this easily with PDO and SQL server however I am struggling getting this working correctly for any general Query. Since I do want this to be reusable by our MySQL tables over any project I am turning here for help.
So the way I used it for PDO and SQL server
function pagedQuery($dbh,$q,$sort,$offset,$limit,$params = array()) {
$limit = preg_replace("/[^0-9]]/","",$limit);
$offset = preg_replace("/[^0-9]]/","",$offset);
$q = preg_replace("/^[^\w]*SELECT/i","SELECT COUNT(*) OVER() as num_rows, ROW_NUMBER() OVER(ORDER BY $sort) AS rownum,",$q);
$q = "SELECT * FROM (".$q.") as pagingTable WHERE rownum > $offset AND rownum <= ($offset+$limit)";
## Prepare Query
$stmt = $dbh->prepare($q);
try {
$stmt->execute($params);
} catch(PDOException $e) {
print $e->getMessage();
}
## Return Results
return $stmt->fetchAll();
Now obviously the OVER functionality does not exist and MySQL and this has to be modified. Here is my attempt at a new version:
function mysqlPagedQuery($dbh,$q,$table,$sort,$offset,$limit,$params = array()) {
$limit = preg_replace("/[^0-9]]/","",$limit);
$offset = preg_replace("/[^0-9]]/","",$offset);
$q = preg_replace("/^[^\w]*SELECT/i","SELECT (SELECT COUNT(*) as num_rows FROM ".$table.") AS num_rows, #rowN := #rowN + 1 AS rownum,",$q);
$q = "SELECT * FROM (".$q.") as pagingTable WHERE rownum > $offset AND rownum <= ($offset+$limit)";
## Prepare Query
$stmt = $dbh->prepare($q);
try {
$query = $dbh->query("set #rowN = 0;");
$stmt->execute($params);
} catch(PDOException $e) {
print $e->getMessage();
}
## Return Results
return $stmt->fetchAll();
Now this will "work" given that you give it a table but I soon realized that the num_rows will not return the correct value unless given all of the WHERE clause of the query sent into it. I would have to parse that in an inefficient manner and I feel there is a much easier way to do this than I am making it out to be.
I ended up with this thanks to bobkingof12vs posted link. Can't give answer credit to him directly because it was not posted here :(
function mysqlPagedQuery($dbh,$q,$sort,$offset,$limit,$params = array()){
$limit = preg_replace("/[^0-9]]/","",$limit);
$offset = preg_replace("/[^0-9]]/","",$offset);
//need to use the original query a few times to create paged
$tempQuery = $q;
//replaces query's select with a count to get numrows
$q1 = "SELECT sql_calc_found_rows * FROM (".$tempQuery.") AS tempTable";
## Prepare Query
$stmt1 = $dbh->prepare($q1);
$q2 = preg_replace("/^[^\w]*SELECT/i","SELECT FOUND_ROWS() as num_rows,",$tempQuery);
$q2 .= " ORDER BY ".$sort;
$q2 .= " LIMIT ".$offset.",".$limit;
//print $q2;
## Prepare Query
$stmt2 = $dbh->prepare($q2);
try{
$stmt1->execute();
$stmt2->execute($params);
}
catch(PDOException $e){
print $e->getMessage();
}
## Return Results
return $stmt2->fetchAll();
}

"SELECT * ..." mysqli parametrized query - how to store results without binding?

I want to store mysqli query results to array.
My code so far looks like this:
function get_nearby_users($Id, $MaxDistance, $RowLimit, $RowLimitOffset)
{
try
{
$query = "SELECT
others.*,
Distance(me.Latitude, me.Longitude, others.Latitude, others.Longitude) as Distance
from
Users me
join
Users others
where
me.Id = ?
and
others.Id != ?
having Distance < ?
limit ?,?
";
$stmt = $this->link->prepare($query);
$stmt->bind_param('iiiii', $Id, $Id, $MaxDistance, $RowLimitOffset, $RowLimit);
$stmt->execute();
// how to fill $rows_array?
}
catch(Exception $exc)
{
// ...
}
return $rows_array;
}
How can I put my results to array when my SQL contains something like "SELECT *"?
All tutorials with parametrized queries use bind_result function, but I don't want to create variables for all fields and bind them. There is no other way?
You do not need to use bind_result to store the record set.
Just use fetchAll() to store result set rows as an array.
$rows_array = $stmt->fetchAll();
I have modified your code. Use this:
function get_nearby_users($Id, $MaxDistance, $RowLimit, $RowLimitOffset)
{
try
{
$query = "SELECT
others.*,
Distance(me.Latitude, me.Longitude, others.Latitude, others.Longitude) as Distance
from
Users me
join
Users others
where
me.Id = ?
and
others.Id != ?
having Distance < ?
limit ?,?
";
$stmt = $this->link->prepare($query);
$stmt->bind_param('iiiii', $Id, $Id, $MaxDistance, $RowLimitOffset, $RowLimit);
$stmt->execute();
$rows_array = $stmt->fetchAll(); // store result set rows as an array
}
catch(Exception $exc)
{
// ...
}
return $rows_array;
}

PDO BindValue doesn't work - execute returns nothing

I got a big issue with pdo, noone seems to be able to help me with - so I decided to ask you guys :-)
try {
$links = $database->prepare("SELECT * FROM aTable WHERE visible=:visible AND access<=:access AND category=:category ORDER BY orderNum ASC");
$links->bindValue(':visible',$first,PDO::PARAM_INT);
$links->bindValue(':access',$second,PDO::PARAM_INT);
$links->bindValue(':category',$third,PDO::PARAM_STR);
$links->execute();
print_r($asdf);
print_r($database->errorInfo());
print_r($links->errorInfo());
while($row = $links->fetch(PDO::FETCH_ASSOC)){
print_r($row);
}
} catch (PDOException $e) {
echo $e->getMessage();
}
Database-Connection works perfectly, the errorInfo()'s both return:
Array
(
[0] => 00000
[1] =>
[2] =>
)
Now, this code somehow doesn't get any $row's. But if I would replace the prepare statement with the following lines:
$sql = "SELECT * FROM woody_sidebar WHERE visible=$first AND access<=$second AND category=$third ORDER BY orderNum ASC";
$links = $database->prepare($sql);
(and remove the bindValue-statements) the code works like charm!
I have no clue what I'm doing wrong, because there is no error thrown at all - does anybody of you know anything I could try?
Thanks
Change this:
$links = $database->prepare("SELECT * FROM aTable WHERE visible=:visible AND access<=:access AND category=:category ORDER BY orderNum ASC");
$links->bindValue(':visible',$first,PDO::PARAM_INT);
$links->bindValue(':access',$second,PDO::PARAM_INT);
$links->bindValue(':category',$third,PDO::PARAM_STR);
to this:
In the second query your table name is woody_sidebar but you have aTable and $third is a INT and can be passed as a PDO::PARAM_INT
$links = $database->prepare("SELECT * FROM woody_sidebar WHERE visible=:visible AND access<=:access AND category=:category ORDER BY orderNum ASC");
$links->bindValue(':visible',$first,PDO::PARAM_INT);
$links->bindValue(':access',$second,PDO::PARAM_INT);
$links->bindValue(':category',$third,PDO::PARAM_INT);
The only problem I see is your table name.
Try this instead
try {
$sql = "SELECT * FROM woody_sidebar WHERE visible=:visible AND access<=:access AND category=:category ORDER BY orderNum ASC";
$links = $database->prepare($sql);
$links->bindValue(':visible', $first, PDO::PARAM_INT); // assuming this is an integer
$links->bindValue(':access', $second, PDO::PARAM_INT); // assuming this is an integer
$links->bindValue(':category', $third, PDO::PARAM_STR); // assuming this is an text string or date
$links->execute();
print_r($asdf);
print_r($database->errorInfo());
print_r($links->errorInfo());
while($row = $links->fetch(PDO::FETCH_ASSOC)){
print_r($row);
}
} catch (PDOException $e) {
echo $e->getMessage();
}

PDO bindParam not allowing statement to return results

I have a pdo statement to select rows and return them in an array. I am using pagination to display 12 results per page. If I directly input LIMIT 12, 12 , instead of LIMIT ?, ? the statement works correctly.
What am I doing wrong with the bindParam for both variables?
Both variables contain the correct data.
Heres the function I'm using:
// Retrieve active posts
function retrieve_active_posts(){
//test the connection
try{
//connect to the database
$dbh = new PDO("mysql:host=db2940.oneandone.co.uk;dbname=db348699391","xxx", "xxx");
//if there is an error catch it here
} catch( PDOException $e ) {
//display the error
echo $e->getMessage();
}
// Get all the posts
$stmt = $dbh->prepare(" SELECT p.post_id, post_year, post_desc, post_title, post_date, img_file_name, p.cat_id
FROM mjbox_posts p
JOIN mjbox_images i
ON i.post_id = p.post_id
AND i.cat_id = p.cat_id
AND i.img_is_thumb = 1
AND post_active = 1
ORDER BY post_date
DESC
LIMIT ?,?");
$stmt->bindParam(1, $limit);
$stmt->bindParam(2, $offset);
$stmt->execute();
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$resultarray[] = $row;
}
return $resultarray;
}
Many thanks
Make sure that the type of $limit and $offset is set to PDO::PARAM_INT:
$limit = 20;
$offset = 0;
$stmt->bindParam(1, $limit, PDO::PARAM_INT);
$stmt->bindParam(2, $offset, PDO::PARAM_INT);
Right after connect to the database, insert the following line of code:
$conn->setAttribute( PDO::ATTR_EMULATE_PREPARES, false);
Source: https://www.php.net/manual/en/pdo.setattribute.php

Categories