PHP PDO Parameter Queries Fail When they contain Subquery - php

I'm using PDO with ODBC from PHP7.4 to SQLServer 12 with this Connection String:
$conn = new PDO('odbc:DRIVER={SQL Server};SERVER=MyServer,1433;Database=MyDatabase;', 'MyUser', 'MyPass');
A regular query with an Integer parameter returns data:
$SQL = <<<EOL
Select
[10-Digit Groups].[Area Code],
[10-Digit Groups].[Group]
From
[10-Digit Groups]
Where
[10-Digit Groups].[Area Code] = ?
EOL;
$stmt = $conn->prepare($SQL);
$ac1 = 602;
$success = $stmt->bindParam(1, $ac1);
$success = $stmt->execute();
foreach($stmt as $row){
var_dump($row);
}
So I add a subquery (Ctr1):
$SQL = <<<EOL
Select
[10-Digit Groups].[Area Code],
(Select Count(*) From [10-Digit Groups]) Ctr1,
[10-Digit Groups].[Group]
From
[10-Digit Groups]
Where
[10-Digit Groups].[Area Code] = ?
EOL;
$stmt = $conn->prepare($SQL);
$ac1 = 602;
$success = $stmt->bindParam(1, $ac1);
$success = $stmt->execute();
foreach($stmt as $row){
var_dump($row);
}
And it fails with:
//Uncaught PDOException: SQLSTATE[22018]: Invalid character value for cast specification: 206 [Microsoft][ODBC SQL Server Driver][SQL Server]Operand type clash: text is incompatible with int (SQLExecute[206] at ext\pdo_odbc\odbc_stmt.c:259)
I can perform similar queries with STRING parameters, but they fail with this error:
//Uncaught PDOException: SQLSTATE[42000]: Syntax error or access violation: 402 [Microsoft][ODBC SQL Server Driver][SQL Server]The data types nvarchar and text are incompatible in the equal to operator. (SQLExecute[402] at ext\pdo_odbc\odbc_stmt.c:259)
I've tried setting and unsetting these:
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
And I've tried setting the DataType in PDO:
$success = $stmt->bindParam(1, $a1, PDO::PARAM_STR); //Or PDO::PARAM_INT where appropriate
I've also hard-coded the parameter values into the SQL to ensure they work.
I've also tried passing the parameters in the 'execute' statement:
PDO->execute([602])
I've also tried converting both sides of the WHERE clause to nvarchar or int.
Everything works as normal with no subquery, but once it's there, the Prepared Statement fails.
Any suggestions to try (Driver String, Subquery Nesting Strategies, other PDO Attribute adjustments, etc.)?

I fixed this with 2 actions:
Install "ODBC Driver 11 for SQL Server" from Microsoft (search for it)
And change
DRIVER={SQL Server};
to
DRIVER={ODBC Driver 11 for SQL Server};
It caused a couple of rewrites, but for the most part was a direct replacement.
It allows for multiple parameters alongside subqueries.
All examples above work fine with this change.
P.S. This change also works for non-PDO odbc commands in PHP.

Related

PDO prepared statement against dB2 Database Failed when execute more than once in Ubuntu Server

I have PDO prepared statement as follows :
$db2 = new PDO($dsn,$user_db, $pass_db);
$db2->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db2->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_TO_STRING);
$stm = $db2->prepare(" SELECT COLUMN1, COLUMN2 from LIBRARY.TABLE1 where COLUMN3 = :col3 ");
#first execution
$stm->bindParam(":col3", "JOHN" );
$stm->execute();
$result = $stm->fetch();
#second execution
$stm->bindParam(":col3", "LAURENCE");
$stm->execute();
$result = $stm->fetch();
The first execution is successful, but the second execution I get the error below :
SQLSTATE[HY010]: Function sequence error: 0 [unixODBC][Driver Manager]Function sequence error (SQLExecute[0] at \/build\/php7.0-AbaziF\/php7.0-7.0.33\/ext\/pdo_odbc\/odbc_stmt.c:260)
Any help and advice would be much appreciated.
Environment :
PHP Version 7.0.33-0ubuntu0.16.04.16

Php - odbc Select Where X IN (Select...)

I have the following code
$stmt = odbc_prepare($conn, 'SELECT tpedidos.*, users.nome FROM tpedidos, users WHERE CODCLI IN (SELECT idCliente FROM ligacoes WHERE idGest =?) AND tpedidos.estado =? AND users.id=tpedidos.CODCLI');
$success = odbc_execute($stmt, array($gestor, $estado));
My problem is that the $gestor is not being well read in the query and if i put a value instead of the '?' it works.
What can i do?
Thanks in advance!
EDIT 1:
Warning: odbc_execute(): SQL error: [Microsoft][ODBC SQL Server Driver]Syntax error or access violation, SQL state 37000 in SQLDescribeParameter in C:****\file.php on line 720
To reply your last comment regarding an alternative query, you could try with PDO prepared statement:
$sth = $conn->prepare("SELECT tpedidos.*, users.nome
FROM tpedidos, users
WHERE CODCLI IN
(SELECT idCliente FROM ligacoes WHERE idGest = :idGest)
AND tpedidos.estado = :estado
AND users.id = tpedidos.CODCLI");
$sth->bindParam(':idGest', $gestor, PDO::PARAM_INT);
$sth->bindParam(':estado', $estado, PDO::PARAM_STR);
$sth->execute();
P.S: I assumed $estado is a string. If it is an integer replace PDO::PARAM_STR with PDO::PARAM_INT.

How to bind ISO8601 TSQL DATETIME parameter with PDO?

It seems that PDO has a problem with ISO 8601 formatted timestamps.
I'm connecting from 64-bit Ubuntu 16.04 running PHP 7.0.8 using the Microsoft® ODBC Driver 13 (Preview) for SQL Server®
Here's my simple table:
CREATE TABLE dtest (
"stamp" DATETIME
);
Works:
$pdoDB = new PDO('odbc:Driver=ODBC Driver 13 for SQL Server;
Server='.DATABASE_SERVER.';
Database='.DATABASE_NAME,
DATABASE_USERNAME,
DATABASE_PASSWORD
);
$pdoDB->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$sql = "INSERT INTO dtest (stamp) VALUES ('2011-03-15T10:23:01')";
$stmt = $pdoDB->prepare($sql);
$params = [];
$stmt->execute($params);
Does not work:
$sql = "INSERT INTO dtest (stamp) VALUES (?)";
$stmt = $pdoDB->prepare($sql);
$params = ['2011-03-15T10:23:01'];
$stmt->execute($params);
Fatal error: Uncaught PDOException: SQLSTATE[22018]: Invalid character value for cast specification: 0 [Microsoft][ODBC Driver 13 for SQL Server]Invalid character value for cast specification (SQLExecute[0] at /build/php7.0-lPMnpS/php7.0-7.0.8/ext/pdo_odbc/odbc_stmt.c:260)
This works if I delete the T so '2011-03-15T10:23:01' becomes '2011-03-15 10:23:01'
$sql = "INSERT INTO dtest (stamp) VALUES (?)";
$stmt = $pdoDB->prepare($sql);
$params = ['2011-03-15 10:23:01'];
$stmt->execute($params);
But I'm writing a script that runs nightly on about 2 million records, so I'd really rather not bear the overhead of running millions of str_replace('T', ' ', $param)
I've also tried using bindParam, but it gives the same error:
$sql = "INSERT INTO dtest (stamp) VALUES (:tdate)";
$stmt = $pdoDB->prepare($sql);
$date = '2011-03-15T10:23:01';
$stmt->bindParam(':tdate',$date,PDO::PARAM_STR);
$stmt->execute();
Is there anyway to bind and execute this parameter as is? I'm a little dubious of the error message because it appears to be coming from SQL Server as if PDO did its job fine, but that doesn't make sense since it's able to handle the type conversion without parameterization.
I've also tried SQL conversion:
Works:
$sql = "INSERT INTO dtest (stamp) VALUES (CONVERT(DATETIME, '2011-03-15T10:23:02', 126))";
$stmt = $pdoDB->prepare($sql);
$params = [];
$stmt->execute($params);
Does not Work:
$sql = "INSERT INTO dtest (stamp) VALUES (CONVERT(DATETIME, ?, 126))";
$stmt = $pdoDB->prepare($sql);
$params = ['2011-03-15T10:23:02'];
$stmt->execute($params);
You will need to use SQL Server's built-in convert() function and specify the format (126) which you are giving it:
$sql = "INSERT INTO dtest (stamp) VALUES (CONVERT(DATETIME, '2011-03-15T10:23:01', 126))";
The documentation mentions :mmm at the end of your string so you might need to manually add :000 at the end of your date string for this to work.
After half a day spent trying to resolve the same issue, I ended up dropping odbc and using dblib instead. I installed php7.0-sybase package, adapted the data source name of my PDO connection and resolved once for all.
Now every bind is working.

Drupal 8 PDO Prepared Statements bindValue error

I am having trouble with this query. This query results in the following error.
PDOException: SQLSTATE[HY093]: Invalid parameter number: no parameters were bound
$sql = "INSERT IGNORE table SET user_id = :uid";
if ($con = $connection->prepare($sql)) {
$con->bindValue(':uid', intval($this->uid), PDO::PARAM_INT);
$con->debugDumpParams();
$con->execute();
}
Parameters
Params: 1
Key: Name: [4] :uid
paramno=-1
name=[4] ":uid"
is_param=1
param_type=1
Query That works.
$sql = "INSERT IGNORE table SET user_id = :uid";
if ($con = $connection->prepare($sql)) {
$con->execute([':uid' => intval($this->uid)]);
}
Question Why can't I bind any parameter or value to the PDO prepared statement?
I am using Drupal 8 and I believe that their connections replace the PDO default driver.
Drupal 8 replaces the default PDO driver with a custom driver that Drupal uses to insert, update, prepare statements, ect... These drivers override the default operations. So if you want a complete customize query you will need to set up your own connection separate from Drupal and use that.
$dsn = 'mysql:host=localhost;dbname=drupal';
$username = 'username';
$password = 'password';
$connection = new PDO($dsn, $username, $password);
Then using the custom queries will work. and you won't get the no parameters were bound error

MySQLi query in PHP isn't working right, is there a way to get the exact query?

Is there a way to get the query after MySQLi prepares it? My query is messing up:
$query = "UPDATE event SET group=?, boxed=?, name=?, location=?, time=?, day=?, type=? WHERE id=? LIMIT 1";
if($stmt = $db -> prepare($query))
{
$stmt -> bind_param("iisssssi", $group, $boxed, $name, $location, $time, $day, $etype, $id);
$stmt -> execute();
$stmt -> close();
}
else
Error message:
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 'group=?, boxed=?, name=?, location=?, time=?, day=?, type=? WHERE id=? LIMIT 1' at line 1
Variable group is an int, boxed is an int, the rest are strings, and id is an int.
You're using the SQL reserved word "group" as one of the column names.
No, there is no way to get the query after MySQLi prepares it, because there is no query in the usual sense. The string goes to the server as you wrote it - with question marks. That's an annoying disadvantage of the prepared statements.

Categories