Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
SET options are not effective over multiple queries in the same connection #385
When you issue SET queries like
Steps to Reproduce:
Steps to Reproduce II:
<?php /* CREATE TABLE mytable ( id int IDENTITY(1,1) ); */ // Should work, but errors out: $connection = new PDO('sqlsrv:DSN here', 'user', 'password'); $connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $connection->query("SET IDENTITY_INSERT mytable ON"); $connection->query("INSERT INTO mytable(id) VALUES(1)"); // PHP Fatal error: Uncaught PDOException: SQLSTATE: [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Cannot insert explicit value for identity column in table 'mytable' when IDENTITY_INSERT is set to OFF. // This actually does work: $connection->query("SET IDENTITY_INSERT mytable ON; INSERT INTO mytable(id) VALUES(1)"); ?>
Repro Script 2
<?php $connection = new PDO('sqlsrv:DSN here', 'user', 'password'); $connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Should throw exception, but works: $connection->query('SET QUOTED_IDENTIFIER OFF'); $connection->query('SELECT * FROM "mytable"'); // Actually throws expected exception: $connection->query('SET QUOTED_IDENTIFIER OFF; SELECT * FROM "mytable"'); // PHP Fatal error: Uncaught PDOException: SQLSTATE: [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Incorrect syntax near 'mytable'. ?>
Hi @mathieuk ,
After some investigation, I determined that, this is not a problem in the driver.
This is not always true.
Note that, you are preparing and executing( default behavior ) the statement by using
Prepared statements result in RPCs ( Remote Procedure Calls ) in SQL Server, which are run in different processes. If you execute the following lines directly on SQL Server, you will get the same exception.
You can read more about RPCs here: https://technet.microsoft.com/en-us/library/cc738291(v=ws.10).aspx
As you mentioned above, you can include
You can also use
I will keep the issue open for a while more, in case if you need any further clarifications.
@ulvii that's a thorough investigation, thanks for that!
You mention that, by default, all queries are executed as prepared statements and that each prepared statement is ran in its own little unique context. I also understand these contexts will have their own 'settings' active.
I have mostly worked with MySQL so, sorry if this is an obvious question to you: as PHP applications typically work in a Share Nothing configuration; does SQL Server save execution plans/compilation results for prepared statements cross connection? As in, if I prepare a statement in Connection#1 would a new Connection #2 reap the benefit of that extra work it performed? If not, it seems wasteful to default to prepared statements.
Regardless, this default mode where settings are not shared across all queries in that connection is quite confusing. Even if you were to set the SQLSRV_ATTR_DIRECT_QUERY attribute it would be weird to suddenly lose your settings when you'd switch to using a prepared statement somewhere in your code.
It also complicates certain use-cases. See for instance this issue regarding running seeders on MSSQL in Laravel. Projects with ORMs (like Eloquent in Laravel) typically do not, and probably should not, provide a way of modifying queries sent to the actual database, so it would be hard to get that IDENTITY_INSERT option activated properly.
Perhaps interestingly, setting IDENTITY_INSERT and performing a query in 2 separate calls does work as expected (for me) when I use DBLIB as the method of connection to SQL Server.
So I guess the question is: is (and/or: should) this really the intended behaviour?
Hi @mathieuk ,
This applies to
PDO provides a data-access abstraction layer, which means that, regardless of which database you're using, you use the same functions to issue queries and fetch data. A PHP extension that implements PDO interface does not have a control over the interface functions, it provides database specific functions.
So in case of
Ok so, the documentation you referenced earlier mentions this and I missed that:
So, it's known and intended behaviour. Sorry for the noise.
Based on your suggestions I've enumerated what effect different methods of querying have. Maybe it'll help someone reading this later on. In all cases I'm executing
@ulvii in case 4, would PDO now use pseudo prepared-statements?