【问题标题】:PHP using SQL Server CLR Stored Procedure how to consume return valuePHP使用SQL Server CLR存储过程如何使用返回值
【发布时间】:2023-04-09 22:42:01
【问题描述】:

我有用 CLR (C#) 编写的存储过程,它们位于 SQL Server DB 中。当我运行这些程序时,我会得到返回值和输出。程序代码为:

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;

现在,当我在 SQL 管理中运行此代码时,我得到:

现在在 PHP 应用程序中,我想访问发送到输出的 SCOPE_IDENTITY() 值或自定义返回值(两者都适用于我的情况)。

$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 ?
    }
}

谁能告诉我如何访问 CLR 存储过程返回的返回值 48 或/和输出值 (SCOPE_IDENTITY)?

我知道我可以添加输出参数,但这会很痛苦,因为我需要更改数百个程序。我需要在不更改 SQL CLR 的情况下访问这些值。

问题是我无法在 PHP 中完成这项工作。有什么问题?此代码确实执行了存储过程(我看到 DB 中的数据已更改),但我无法访问 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));
        }
    }
}

【问题讨论】:

  • 为什么您的代码会暴露 DML 语句。 SQL注入是一回事
  • 感谢您的宝贵时间,您能告诉我您是如何使用 php sqlsrv_prepare 和 sqlsrv_execute 方法获得返回值的吗?
  • 您很可能需要在fetch_array 中引用$res 而不是$prep。然后您需要添加我的答案中的另一部分:INSERT...EXEC 的表变量。
  • 这不起作用。在这种情况下,$res 是布尔值(sqlsrv_execute 返回布尔值),$prep 是资源,但无法获取(无行)。也使用 INSERT EXEC 不起作用。这似乎是严格的 PHP 问题...
  • @RomainByrd 我知道这是关于 PHP 的,我只是希望它更像 MySQL 接口。您是否为此关注 PHP 文档?为什么你说INSERT...EXEC 不起作用?我什至没有在你的代码中看到它。

标签: php sql-server stored-procedures dynamic-sql sqlclr


【解决方案1】:

您不需要更改 SQLCLR 存储过程,您需要完全摆脱它。在这种用法中绝对没有意义。您不仅一无所获,而且您现在拥有的系统比另一种通用查询机制的本已复杂的性质更加复杂且难以维护(即成本更高)。

您可以在 T-SQL 中使用 sp_executesql 完成所有这些操作(尽管这仍然不是一个好主意),并且更清楚如何获得 SCOPE_IDENTITY() 值。

您已经知道如何在 SSMS 屏幕截图中获取返回值。你只需要在EXEC 之后重新SELECT 那个变量,这样它就会成为一个结果集$res

您可以通过创建具有单个INT 列的本地临时表(或表变量)然后执行INSERT INTO #tmp ([ID]) EXEC proc; 来捕获SCOPE_IDENTITY(),类似于:

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;

【讨论】:

  • 好吧,让我们忘记为 TSQ 等更改 CLR。​​正如我所说,我不能那样做。问题是关于 PHP 用什么来实现与我在 SQL Studio 中相同的效果???
  • @RomainByrd 明白了,这就是为什么我提供示例代码来做到这一点。只需将其放入您的 $sql 变量中即可。显然你不需要临时存储过程,那只是让我复制你的设置。
  • 这个答案+1。 CLR 本身就是一种安全风险。它适用于 T-SQL 无法自行执行的操作,例如文件操作、HTTP 协议的路由等。不考虑 CLR 的不安全性质而使用 CLR 可能会危及您的职业和法律安全。
  • @clifton_h 谢谢,但您的说法“CLR 本身就是一种安全风险”是完全错误的。这是一个不幸的普遍接受的神话/误解。这里的问题仅仅是它是额外的复杂性,没有额外的好处。有关 SQLCLR 的更多信息,请参阅我在 SQL Server Central 上撰写的关于此主题的系列文章:Stairway to SQLCLR(需要免费注册)。第 3 级和第 4 级处理安全性,第 1 级处理它是什么/适当的用法。
  • 哇。你有没有在 CLR 中写过任何东西? Microsoft 对这种“安全”CLR 的考虑太多,以至于他们取消了将 CLR 声明为 SAFE 和 EXTERNAL ACESS 的选项,因为他们放弃了其背后的安全性。此外,您忘记了与设置了界限的 TSQL 不同,CLR 是由业余爱好者编写的外部程序,这些程序可能会或可能不会精通验证和保护代码。 CREATE ASSEMBLY 就像是常规查询一样运行,这隐含着危险。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-31
相关资源
最近更新 更多