如何使用PDO在PHP中创建包含DELIMITER的存储过程?

aut*_*tix 1 php mysql pdo stored-procedures delimiter

在我的模型中,我定义了一些程序.代码(由MySQL Workbench生成)包含DELIMITER定义,因此过程如下所示:

-- schema
CREATE DATABASE ...
CREATE TABLE foo ...
-- procedures
DELIMITER $$
...
  BEGIN
    DECLARE ... ;
    OPEN ... ;
    SET ... ;
    ... ;
  END$$
DELIMITER ;
Run Code Online (Sandbox Code Playgroud)

现在我需要通过PDO将SQL"导入"到数据库.我试图传递它作为输入PDO#exec(...),但注意到,执行停止在第一个DELIMITER定义的行上.

我不想删除这些DELIMITER陈述.所以SQL代码应该保持不变.

如何使用PDO执行包含DELIMITER语句的SQL代码?

Mic*_*bot 5

来自评论:

我不想删除这些DELIMITER陈述.实际上,我想让它在没有手动执行每个语句的情况下工作

这不是它的工作原理.

要了解原因,您需要了解mysqlCLI - 以及可以读取和执行此类转储文件的任何其他程序 - 实际上如何处理它.

DELIMITER 不是服务器理解的东西.

DELIMITER用于告诉客户端解析器当前语句分隔符应该是什么,以便客户端解析器可以正确地拆分语句并一次一个地传递给服务器执行.

来自文档.请注意mysql,每次在此处使用时,都指的是mysql 客户端实用程序 - 而不是服务器.

如果使用mysql客户端程序定义包含分号字符的存储程序,则会出现问题.默认情况下,mysql它本身将分号识别为语句分隔符,因此必须临时重新定义分隔符以使mysql整个存储的程序定义传递给服务器.

要重新定义mysql分隔符,请使用该delimiter命令.[...]分隔符更改为//使整个定义能够作为单个语句传递给服务器,然后;在调用过程之前恢复到该定义.这使得;过程体中使用的定界符能够传递到服务器,而不是由mysql它自己解释.

https://dev.mysql.com/doc/refman/5.7/en/stored-programs-defining.html

因此,要处理这样的文件,你需要一个客户端解析器,做同样的事情mysql呢?在这里,你正在写的代码是(必须)客户端声明解析器.所以你是那个需要编写逻辑来处理分隔符的人.

要执行您想要的操作,您必须解释DELIMITER语句,使用它们来跟踪当前语句分隔符,但不要将它们发送到服务器.

然后,您必须一次读取输入一行,缓冲您已读取的内容,直到在行尾找到指定的分隔符,并将结果语句发送到服务器 - 不包括实际的语句分隔符从你发送的内容...所以,例如,你不会$$在程序体之后发送结尾(除非当前的语句分隔符是;,你可以发送或不发送 - 服务器不关心.)然后为空缓冲区并再次开始读取,直到您看到分隔符的另一个实例(并将语句发送到服务器)或匹配DELIMITER语句并设置代码的当前分隔符变量以匹配它,以便您正确识别下一个语句的结尾.