views:

146

answers:

3

short version: the sqlsrv driver (Native Client wrapper) "eats" constraint violation errors generated from triggers; the mssql driver (ntwdlib wrapper) reports them just fine.

  • SQL Server 2005
  • PHP 5.3.1
  • SQL Server Driver for PHP 1.1

fixture:

CREATE TABLE t (
  t INT NOT NULL PRIMARY KEY
);
CREATE VIEW v AS
  SELECT CURRENT_TIMESTAMP AS v
;
CREATE TRIGGER vt ON v
INSTEAD OF INSERT
AS BEGIN
BEGIN TRY
  INSERT INTO t SELECT 1 UNION ALL SELECT 1;
END TRY
BEGIN CATCH
  RAISERROR('fubar!', 17, 0);
END CATCH
END;

running INSERT INTO v SELECT CURRENT_TIMESTAMP; through Management Studio yields

(0 row(s) affected)
Msg 3616, Level 16, State 1, Line 1
Transaction doomed in trigger. Batch has been aborted.
Msg 50000, Level 17, State 0, Procedure vt, Line 8
fubar!

no error is reported when I run it through sqlsrv_query:

$conn = sqlsrv_connect(...);
var_dump(sqlsrv_query($conn, 'INSERT INTO v SELECT CURRENT_TIMESTAMP'));
var_dump(sqlsrv_errors());

outputs

resource(11) of type (SQL Server Statement)
NULL

the application has (it seems) no way to find out that the trigger failed other than through later statements failing.

The question: What's up? Do you use this PHP driver? Do you use views with DML triggers? Does the driver report doomed transactions?

edit 2010-02-17 11:50: the first version of the question incorrectly claimed that I saw the artifact with the trigger containing a simple INSERT. well, it only happens when the constraint-violating DML is inside a TRY block. sorry for the confusion.

edit 2010-03-03: just so that you guys don't get too attached to the severity level in RAISERROR, the real code tries to rethrow the caught error with ERROR_NUMBER, ERROR_SEVERITY and ERROR_STATE.

furthermore, please pay attention to the questions asked:

The question: What's up? Do you use this PHP driver? Do you use views with DML triggers? Does the driver report doomed transactions?

please don't try to harvest the bounty without having firsthand experience with the situation described here.

A: 

I have run into this problem in the past, it is not just PHP that intricacy. For some reason, that I can't figure out and find in any documentation, you need the specify the severity to it's max of 18 for non-sysadmins. Try this:

CREATE TABLE t (
  t INT NOT NULL PRIMARY KEY
);
CREATE VIEW v AS
  SELECT CURRENT_TIMESTAMP AS v
;
CREATE TRIGGER vt ON v
INSTEAD OF INSERT
AS BEGIN
BEGIN TRY
  INSERT INTO t SELECT 1 UNION ALL SELECT 1;
END TRY
BEGIN CATCH
  RAISERROR('fubar!', 18, 0);
END CATCH
END;

note: I have only changed the severity from 17 to 18 in the code above.

Nick Berardi
Severity Level 18 is " Nonfatal Internal Error Detected" - These messages indicate that there is some type of internal software problem, but the statement finishes, and the connection to SQL Server is maintained. For example, a severity level 18 message occurs when the SQL Server query processor detects an internal error during query optimization. The system administrator should be informed every time a severity level 18 message occurs.
Mitch Wheat
doesn't help. do *you* see any difference between 17 and 18 when you run the PHP snippet that's part of the question?
just somebody
A: 

A Severity Level of 17 indicates "Insufficient Resources". Try using 16 instead. (Error Message Severity Levels)

From the canonical reference: Error Handling in SQL 2000 – a Background

Severity level – a number from 0 to 25. The stort story is that if the severity level is in the range 0-10, the message is informational or a warning, and not an error. Errors resulting from programming errors in your SQL code have a severity level in the range 11-16. Severity levels 17-25 indicate resource problems, hardware problems or internal problems in SQL Server, and if the severity is 20 or higher, the connection is terminated. For the long story, see the section More on Severity Levels for some interesting tidbits. For system messages you can find the severity level in master..sysmessages, but for some messages SQL Server employs a different severity level than what's in sysmessages.

Also see: Error Handling in SQL 2005 and Later

Mitch Wheat
nope, doesn't help
just somebody
Would the downvoter please leave a comment. Thanks.
Mitch Wheat
"nope, doesn't help" - That's a helpful response. Mind describing why?
Mitch Wheat
the downvote is mine. as to "why": no change in behavior. i was looking for insight, not random stabs at the dark. plus, you didn't answer my questions at all, and those were: *Do you use this PHP driver? Do you use views with DML triggers? Does the driver report doomed transactions?*
just somebody
@just somebody: hardly random stabs. Myself and Nick Berardi were trying to help you; downvoting is probably not a big incentive to helping you further.
Mitch Wheat
@Mitch Wheat, totally agree with you. It also didn't help the @just somebody didn't provide the actual code that was giving him the problem, he provided some example. I think the problem was in the root of his code, and nothing to do with the driver, because I have successfully used this exact PHP driver to fetch errors many times.
Nick Berardi
@Nick Berardi: the question is explicit enough, if you can't be bothered to *read* it, I don't know how I could help you.
just somebody
@Nick Berardi: oh, and you *obviously* didn't run the code I provided, neither as-is, nor with your proposed "fix".
just somebody
@just somebody, I was on the road, I will helping you troubleshoot the problem. If you need somebody to hold you hand, buy an MSDN license and call Microsoft for the help, or pay the $400.00 US for the support call. If neither of those are options you are going to have to take what you get, we are just here to help. I didn't jump on this question, because I wanted rep. I jumped on because I thought I could help you. You attitude has really made that hard.
Nick Berardi
A: 

Have you tried a severity of 10 or below? By the way I have always had good luck with the SQL Driver and PHP. On 2005 and 2008. If this doesn't work, try a different server to make sure it isn't your server config.

Nick Berardi
If the severity level is in the range 0-10, the message is informational or a warning, and not an error
Mitch Wheat
@Nick Berandi: did you notice the questions asked here at all? Please post suggestions which don't answer the question as comments.
just somebody
-1 You've got attached to an artificial example. the real code goes like `BEGIN TRY ... END TRY BEGIN CATCH RAISERROR(ERROR_NUMBER(), ERROR_SEVERITY(), ERROR_CODE()) END CATCH` (or so, you get the idea); the caught error may be anything and needs to leave the sqlsrv driver. also, I wrote that the same trigger reports errors when I use php_mssql.dll in PHP. did you read the question? just ignore the specific severity already, the problem is obviously elsewhere.
just somebody
@just somebody, maybe that is what you should have posted instead of trying to be cryptic with an example. The problem could have been in your code and by the very fact of you turning actual code in to an example might have made the been the root of your issue. Because you eliminated the error.
Nick Berardi
Nick Berardi: the root cause of the sqlsrv driver failing would be my example? nope, first there was production code that works through php_mssql.dll but fails with php_sqlsrv.dll, *then* there was a simplified example that exhibits the same behavior. you simply ignored my questions; sorry to be harsh, but it surely looks like you hoped to reap the bounty through potshot luck.
just somebody
@just somebody: on the other hand, maybe Nick was just trying to help? It's true that we all like getting rep, but underlying this is a desire to try and help others.
Mitch Wheat
@Mitch Wheat: if you check my other questions you'll see that i'm willing to compensate efforts (upvote) of anyone whose answer is correct and teaches me something new and relevant even if it doesn't really solve my problem. obviously, the bar is higher for a question with a bounty. however, no answer here so far has been even answering my questions!
just somebody
@just somebody if you cannot handle loosing the rep that you put up, don't put it up, you will get the same help either way on StackOverflow for the most part, and maybe you won't feel as cheated when people actually try to help you out and are wrong. I say with you current attitude stick to asking questions with out rep bonuses. You will sleep better at night.
Nick Berardi