-1

I have stored procedures written in CLR (C#) that are sitting in SQL Server DB. When I run those procedures I get return value as well as output. Procedure code is:

using(SqlConnection conn = new SqlConnection("context connection=true"))
        {
            SqlPipe pipe = SqlContext.Pipe;

                conn.Open();


                string table = tableName.ToString();
                string columns = columnList.ToString();
                string values = valueList.ToString();
                string types = typeList.ToString();

                cmd.Connection = conn;

                cmd.CommandText = @"
INSERT INTO " + table + " (" + columns + ") VALUES(" + values + ");SELECT SCOPE_IDENTITY();";
                pipe.ExecuteAndSend(cmd);
return 48;

Now when I run this code in SQL Management I get:

enter image description here

now in PHP app I want to access either SCOPE_IDENTITY() value sent to output or custom return value (both will work in my case).

$params = array(
                            array(&FW::$session->requestUniqueId, SQLSRV_PARAM_IN),
                            array(&$this->rootTable, SQLSRV_PARAM_IN),
                            array(&$columns, SQLSRV_PARAM_IN),
                            array(&$values, SQLSRV_PARAM_IN),
                            array(&$types, SQLSRV_PARAM_IN)
                        );

$sql="EXEC sp_data_insert @requestId=?, @tableName=?, @columnList=?, @valueList=?, @typeList=?";

$prep=sqlsrv_prepare($this->conn,$sql,$params);
if($prep!==false)
{
    $res=sqlsrv_execute($prep);
    if($res)
    {
            //HOW TO ACCESS RETURN VALUE OR OUTPUT VALUE YIELD BY SQL PROCEDURE HERE ?
    }
}

Can anyone tell me how to access return value 48 returned by CLR stored procedure or/and output value (SCOPE_IDENTITY)?

I know I can add output paramter but this would be a pain, since I would have hundrets of procedures to change. I need to access these values without changing SQL CLR.

Problem is that I cannot make this work in PHP. What can be wrong? This code does execute the stored procedure (I see data in DB changed), but I cannot access return value in PHP:

$sql="DECLARE @ret int EXEC @ret=$stored_procedure; SELECT @ret";
$prep=sqlsrv_prepare($this->conn,$sql,$params);
if($prep!==false)
{
    $res=sqlsrv_execute($prep);
    if($res)
    {
        while($row=sqlsrv_fetch_array($prep))
        {
            print('row='.print_r($row,true));
        }
    }
}
  • Why is your code exposing DML statements. SQL injection is a thing – clifton_h Jun 24 '17 at 04:40
  • Thanks for your time, can you tell me how you get return value using php sqlsrv_prepare and sqlsrv_execute methods? – Romain Byrd Jun 24 '17 at 19:33
  • Most likely you need to reference `$res` in the `fetch_array` instead of `$prep`. Then you need to add in the other piece from my answer: the table variable for the `INSERT...EXEC`. – Solomon Rutzky Jun 25 '17 at 22:54
  • this doesn't work. $res is boolean in this case (sqlsrv_execute returns bool), $prep is resource but can't be fetched (no rows). Also using INSERT EXEC doesn't work. This seems to be strictly PHP question... – Romain Byrd Jun 26 '17 at 01:15
  • @RomainByrd I understand that this is about PHP, I was just expecting it to be more like the MySQL interface. Are you following the PHP documentation for this? And why do you say that the `INSERT...EXEC` doesn't work? I don't even see it in your code. – Solomon Rutzky Jun 26 '17 at 01:57
  • I didn't update my question, but it doesn't work. I have tried it and it doesn't work. Also SELECT @return doesn't return any rows. – Romain Byrd Jun 26 '17 at 02:27
  • @RomainByrd If `SELECT @return` doesn't return any rows then that part is purely a PHP issue with how you are trying to get the rows. But as far as the SQL Server part of this goes, that part is covered completely in my answer. Now you just need to figure out how to accept a result set from SQL Server in PHP. Also, now that more than 1 person other than the O.P. has left comments, you need to use the `@` login name in your comment so that the person is notified. The poster of the question or answer is always notified of comments. And you can only use 1 `@` login name in a comment, just FYI. – Solomon Rutzky Jun 26 '17 at 16:55

1 Answers1

2

You don't need to change the SQLCLR stored procedure, you need to get rid of it entirely. It is absolutely pointless in this usage. Not only do you gain nothing, but you now have a system that is far more convoluted and harder (i.e. costlier) to maintain than the already convoluted nature of the yet-another-generic-query-mechanism.

You could do all of this in T-SQL with sp_executesql (though still not a great idea) and it would be clearer as to how to get the SCOPE_IDENTITY() value.

You already know how to get the return value as you are doing it in the SSMS screen shot. You just need to re-SELECT that variable after the EXEC so that it will be a result set $res.

You might could capture the SCOPE_IDENTITY() by creating a local temporary table (or table variable) with a single INT column and then doing INSERT INTO #tmp ([ID]) EXEC proc;, similar to:

GO
CREATE PROC #ttt
AS
SELECT 1
UNION ALL
SELECT 56788;

RETURN 55;
GO

DECLARE @T TABLE (Col1 INT);
DECLARE @Y INT;

INSERT INTO @T ([Col1])
 EXEC @Y = #ttt;

SELECT @Y, *
FROM @t;
Solomon Rutzky
  • 46,688
  • 9
  • 128
  • 171
  • OK, let's forget about changing CLR for TSQ etc. As I said, I can't do that. Question is about PHP what to use to achive the same effect as I did in SQL Studio ??? – Romain Byrd Jun 24 '17 at 19:19
  • @RomainByrd Understood, which is why I provided example code to do exactly that. Just work it into your `$sql` variable. Obviously you don't need the temporary stored procedure, that was just for me to duplicate your setup. – Solomon Rutzky Jun 24 '17 at 20:13
  • +1 for this answer. CLR is itself a security risk. It is meant for actions that T-SQL cannot self do, such as file manipulation, routing of HTTP protocols and so on. To use CLR without regard to it's unsafe nature can be perilous to your career and legal safety. – clifton_h Jun 25 '17 at 21:53
  • @clifton_h Thanks, but your statement "_CLR is itself a security risk_" is entirely false. That is an unfortunate commonly accepted myth / misunderstanding. The problem with it here is merely that it is additional complication for no additional benefit. For more info on SQLCLR, please see the series of articles I am writing on this topic on SQL Server Central: [Stairway to SQLCLR](http://www.sqlservercentral.com/stairway/105855/) (free registration required). Levels 3 and 4 deal with security, and Level 1 deals with what it is / appropriate usage. – Solomon Rutzky Jun 26 '17 at 19:56
  • Wow. have you ever written anything in CLR? Microsoft thought so much of this "safe" CLR that they REMOVED the options of declaring CLR as SAFE and EXTERNAL ACESS due to their abandonment of the security behind it. Furthermore, you forget that unlike TSQL, where it has set boundaries, CLR is an outside program written by amateurs to professionals who may or may not be proficient at proofing and securing their code. [CREATE ASSEMBLY](https://docs.microsoft.com/en-us/sql/t-sql/statements/create-assembly-transact-sql) It operates as if it is a regular query, which is implicitly dangerous. – clifton_h Jun 26 '17 at 22:28
  • This is not the place to fully explain it, but if you think that a custom library, published outside Microsoft, which is fully capable of running any library that works with the .NET Framework, is "safe" or not implicitly dangerous, then you are living dangerously. I do not think you grasp fully the implications of what you wrote. – clifton_h Jun 26 '17 at 22:36