为什么PDO第一次不执行整个语句?

时间:2016-10-10 17:23:07

标签: php sql-server pdo

我有一个DDL脚本,它将创建一堆表,我使用this script在两次测试之间清理数据库。

第一次运行此脚本时,它会像创建的那样创建所有表。

CleanMsSQLdb($pdo);

$ddl = file_get_contents(__DIR__.'/ddl.sql');

$pdo->exec($ddl);

enter image description here

但是由于一些奇怪的原因,如果我第二次尝试运行该脚本,我会收到一个错误,因为它没有丢弃所有表格。

  

PHP致命错误:未捕获PDOException:SQLSTATE [42S01]:基表或视图已存在:2714 [Microsoft] [SQL Server的ODBC驱动程序13] [SQL Server] 已有一个名为'tmpDataRecordSAMPLE'的对象在数据库中。(SQLExecDirect [2714] at /build/php7.0-41GaEn/php7.0-7.0.8/ext/pdo_odbc/odbc_driver.c:247)

enter image description here

真正让我感到不安的是,如果我只是连续两次运行干净的脚本,那么它会丢弃所有内容并且工作正常。

CleanMsSQLdb($pdo);
CleanMsSQLdb($pdo);

$ddl = file_get_contents(__DIR__.'/ddl.sql');

$pdo->exec($ddl);

为什么不在第一次通过时丢弃所有表?

尝试删除表时,我没有收到任何错误。

如果我在Microsoft SQL Server Management Studio中运行该语句,那么它会在第一次传递时删除所有表,那么为什么不从PDO中删除呢?

关于我

我正在运行Ubuntu Linux 16.04.1,PHP 7.0.8-0ubuntu0.16.04.3(cli)(NTS)连接到Microsoft SQL Server 2012(SP3)(KB3072779) - 11.0.6020.0(X64)使用Microsoft® ODBC Driver 13 (Preview) for SQL Server®

$hostname = 'sql.example.com';
$database = 'mydb';
$username = 'db_owner';
$password = 'P@55w0rd';
$driver   = 'ODBC Driver 13 for SQL Server';

$pdo = new PDO("odbc:Driver=$driver;
    Server=$hostname;
    Database=$database",
    $username,
    $password
);
$pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

ddl.sql

很抱歉大数据转储,但是我无法重现这个较小的脚本,所以特别对这些表格感到好奇。

CREATE TABLE [tmpData] (
    [date] datetime,
    jpetl_id int IDENTITY PRIMARY KEY
);

CREATE TABLE [tmpDataRecord] (
    jpetl_pid int,
    CONSTRAINT fk_tmpDataRecord
        FOREIGN KEY (jpetl_pid)
        REFERENCES [tmpData](jpetl_id),
    [id] tinyint,
    jpetl_id int IDENTITY PRIMARY KEY
);

CREATE TABLE [tmpDataRecordSAMPLE] (
    jpetl_pid int,
    CONSTRAINT fk_tmpDataRecordSAMPLE
        FOREIGN KEY (jpetl_pid)
        REFERENCES [tmpDataRecord](jpetl_id),
    [id] tinyint,
    [created] datetime,
    [CONTRACT_TERM] varchar(8),
    [PRICE] decimal(6,3),
    [ABSTRACT] varchar(100),
    jpetl_id int IDENTITY PRIMARY KEY
);

CREATE TABLE [tmpDataRecordSAMPLEADMIN_DEP] (
    jpetl_pid int,
    CONSTRAINT fk_tmpDataRecordSAMPLEADMIN_DEP
        FOREIGN KEY (jpetl_pid)
        REFERENCES [tmpDataRecordSAMPLE](jpetl_id),
    [id] bigint,
    [primaryKey] varchar(10),
    [DEP] varchar(10),
    jpetl_id int IDENTITY PRIMARY KEY
);

CREATE TABLE [tmpDataRecordSAMPLESUPP_DEP] (
    jpetl_pid int,
    CONSTRAINT fk_tmpDataRecordSAMPLESUPP_DEP
        FOREIGN KEY (jpetl_pid)
        REFERENCES [tmpDataRecordSAMPLE](jpetl_id),
    [id] bigint,
    [primaryKey] varchar(19),
    jpetl_id int IDENTITY PRIMARY KEY
);

CREATE TABLE [tmpDataRecordSAMPLESUPP_DEPDEP] (
    jpetl_pid int,
    CONSTRAINT fk_tmpDataRecordSAMPLESUPP_DEPDEP
        FOREIGN KEY (jpetl_pid)
        REFERENCES [tmpDataRecordSAMPLESUPP_DEP](jpetl_id),
    [DEP] varchar(19),
    jpetl_id int IDENTITY PRIMARY KEY
);

CREATE TABLE [tmpDataRecordSAMPLETITLE] (
    jpetl_pid int,
    CONSTRAINT fk_tmpDataRecordSAMPLETITLE
        FOREIGN KEY (jpetl_pid)
        REFERENCES [tmpDataRecordSAMPLE](jpetl_id),
    [TITLE] varchar(19),
    jpetl_id int IDENTITY PRIMARY KEY
);

CREATE TABLE [tmpDataRecordSAMPLESAMPLE_AUTH] (
    jpetl_pid int,
    CONSTRAINT fk_tmpDataRecordSAMPLESAMPLE_AUTH
        FOREIGN KEY (jpetl_pid)
        REFERENCES [tmpDataRecordSAMPLE](jpetl_id),
    [id] tinyint,
    [FACULTY_NAME] smallint,
    [FACULTY_NAMEfid] smallint,
    [FNAME] varchar(4),
    [MNAME] varchar(100),
    [LNAME] varchar(3),
    [ISSTUDENT] varchar(100),
    [DISPLAY] varchar(2),
    [INITIATION] datetime,
    jpetl_id int IDENTITY PRIMARY KEY
);

CREATE TABLE [tmpDataRecordSAMPLESAMPLE_EDITOR] (
    jpetl_pid int,
    CONSTRAINT fk_tmpDataRecordSAMPLESAMPLE_EDITOR
        FOREIGN KEY (jpetl_pid)
        REFERENCES [tmpDataRecordSAMPLE](jpetl_id),
    [id] tinyint,
    [FACULTY_NAME] varchar(100),
    [FNAME] varchar(100),
    [MNAME] varchar(100),
    [LNAME] varchar(100),
    [DISPLAY] varchar(100),
    jpetl_id int IDENTITY PRIMARY KEY
);

CREATE TABLE [Data] (
    [date] datetime,
    jpetl_id int  PRIMARY KEY
);

CREATE TABLE [DataRecord] (
    jpetl_pid int,
    CONSTRAINT fk_DataRecord
        FOREIGN KEY (jpetl_pid)
        REFERENCES [Data](jpetl_id),
    [id] tinyint,
    jpetl_id int  PRIMARY KEY
);

CREATE TABLE [DataRecordSAMPLE] (
    jpetl_pid int,
    CONSTRAINT fk_DataRecordSAMPLE
        FOREIGN KEY (jpetl_pid)
        REFERENCES [DataRecord](jpetl_id),
    [id] tinyint,
    [created] datetime,
    [CONTRACT_TERM] varchar(8),
    [PRICE] decimal(6,3),
    [ABSTRACT] varchar(100),
    jpetl_id int  PRIMARY KEY
);

CREATE TABLE [DataRecordSAMPLEADMIN_DEP] (
    jpetl_pid int,
    CONSTRAINT fk_DataRecordSAMPLEADMIN_DEP
        FOREIGN KEY (jpetl_pid)
        REFERENCES [DataRecordSAMPLE](jpetl_id),
    [id] bigint,
    [primaryKey] varchar(10),
    [DEP] varchar(10),
    jpetl_id int  PRIMARY KEY
);

CREATE TABLE [DataRecordSAMPLESUPP_DEP] (
    jpetl_pid int,
    CONSTRAINT fk_DataRecordSAMPLESUPP_DEP
        FOREIGN KEY (jpetl_pid)
        REFERENCES [DataRecordSAMPLE](jpetl_id),
    [id] bigint,
    [primaryKey] varchar(19),
    jpetl_id int  PRIMARY KEY
);

CREATE TABLE [DataRecordSAMPLESUPP_DEPDEP] (
    jpetl_pid int,
    CONSTRAINT fk_DataRecordSAMPLESUPP_DEPDEP
        FOREIGN KEY (jpetl_pid)
        REFERENCES [DataRecordSAMPLESUPP_DEP](jpetl_id),
    [DEP] varchar(19),
    jpetl_id int  PRIMARY KEY
);

CREATE TABLE [DataRecordSAMPLETITLE] (
    jpetl_pid int,
    CONSTRAINT fk_DataRecordSAMPLETITLE
        FOREIGN KEY (jpetl_pid)
        REFERENCES [DataRecordSAMPLE](jpetl_id),
    [TITLE] varchar(19),
    jpetl_id int  PRIMARY KEY
);

CREATE TABLE [DataRecordSAMPLESAMPLE_AUTH] (
    jpetl_pid int,
    CONSTRAINT fk_DataRecordSAMPLESAMPLE_AUTH
        FOREIGN KEY (jpetl_pid)
        REFERENCES [DataRecordSAMPLE](jpetl_id),
    [id] tinyint,
    [FACULTY_NAME] smallint,
    [FACULTY_NAMEfid] smallint,
    [FNAME] varchar(4),
    [MNAME] varchar(100),
    [LNAME] varchar(3),
    [ISSTUDENT] varchar(100),
    [DISPLAY] varchar(2),
    [INITIATION] datetime,
    jpetl_id int  PRIMARY KEY
);

CREATE TABLE [DataRecordSAMPLESAMPLE_EDITOR] (
    jpetl_pid int,
    CONSTRAINT fk_DataRecordSAMPLESAMPLE_EDITOR
        FOREIGN KEY (jpetl_pid)
        REFERENCES [DataRecordSAMPLE](jpetl_id),
    [id] tinyint,
    [FACULTY_NAME] varchar(100),
    [FNAME] varchar(100),
    [MNAME] varchar(100),
    [LNAME] varchar(100),
    [DISPLAY] varchar(100),
    jpetl_id int  PRIMARY KEY
);

CleanMsSQLdb

这只是this script的复制粘贴,只是将批GO个语句分解为多个exec

function CleanMsSQLdb(PDO $pdo){
    $sql = "
        /* Drop all non-system stored procs */
        DECLARE @name VARCHAR(128)
        DECLARE @SQL VARCHAR(254)

        SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'P' AND category = 0 ORDER BY [name])

        WHILE @name is not null
        BEGIN
            SELECT @SQL = 'DROP PROCEDURE [dbo].[' + RTRIM(@name) +']'
            EXEC (@SQL)
            PRINT 'Dropped Procedure: ' + @name
            SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'P' AND category = 0 AND [name] > @name ORDER BY [name])
        END
    ";
    $pdo->exec($sql);

    $sql = "
        /* Drop all views */
        DECLARE @name VARCHAR(128)
        DECLARE @SQL VARCHAR(254)

        SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'V' AND category = 0 ORDER BY [name])

        WHILE @name IS NOT NULL
        BEGIN
            SELECT @SQL = 'DROP VIEW [dbo].[' + RTRIM(@name) +']'
            EXEC (@SQL)
            PRINT 'Dropped View: ' + @name
            SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'V' AND category = 0 AND [name] > @name ORDER BY [name])
        END
    ";
    $pdo->exec($sql);

    $sql = "
        /* Drop all functions */
        DECLARE @name VARCHAR(128)
        DECLARE @SQL VARCHAR(254)

        SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] IN (N'FN', N'IF', N'TF', N'FS', N'FT') AND category = 0 ORDER BY [name])

        WHILE @name IS NOT NULL
        BEGIN
            SELECT @SQL = 'DROP FUNCTION [dbo].[' + RTRIM(@name) +']'
            EXEC (@SQL)
            PRINT 'Dropped Function: ' + @name
            SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] IN (N'FN', N'IF', N'TF', N'FS', N'FT') AND category = 0 AND [name] > @name ORDER BY [name])
        END
    ";
    $pdo->exec($sql);

    $sql = "
        /* Drop all Foreign Key constraints */
        DECLARE @name VARCHAR(128)
        DECLARE @constraint VARCHAR(254)
        DECLARE @SQL VARCHAR(254)

        SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME)

        WHILE @name is not null
        BEGIN
            SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
            WHILE @constraint IS NOT NULL
            BEGIN
                SELECT @SQL = 'ALTER TABLE [dbo].[' + RTRIM(@name) +'] DROP CONSTRAINT [' + RTRIM(@constraint) +']'
                EXEC (@SQL)
                PRINT 'Dropped FK Constraint: ' + @constraint + ' on ' + @name
                SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND CONSTRAINT_NAME <> @constraint AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
            END
        SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME)
        END
    ";
    $pdo->exec($sql);

    $sql = "
        /* Drop all Primary Key constraints */
        DECLARE @name VARCHAR(128)
        DECLARE @constraint VARCHAR(254)
        DECLARE @SQL VARCHAR(254)

        SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY TABLE_NAME)

        WHILE @name IS NOT NULL
        BEGIN
            SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
            WHILE @constraint is not null
            BEGIN
                SELECT @SQL = 'ALTER TABLE [dbo].[' + RTRIM(@name) +'] DROP CONSTRAINT [' + RTRIM(@constraint)+']'
                EXEC (@SQL)
                PRINT 'Dropped PK Constraint: ' + @constraint + ' on ' + @name
                SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND CONSTRAINT_NAME <> @constraint AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
            END
        SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY TABLE_NAME)
        END
    ";
    $pdo->exec($sql);

    $sql = "
        /* Drop all tables */
        DECLARE @name VARCHAR(128)
        DECLARE @SQL VARCHAR(254)

        SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 ORDER BY [name])

        WHILE @name IS NOT NULL
        BEGIN
            SELECT @SQL = 'DROP TABLE [dbo].[' + RTRIM(@name) +']'
            EXEC (@SQL)
            PRINT 'Dropped Table: ' + @name
            SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 AND [name] > @name ORDER BY [name])
        END
    ";
    $pdo->exec($sql);
}

1 个答案:

答案 0 :(得分:0)

结果是所有那些PRINT语句干扰了游标,但仅限于外键掉落。

有两种修复方法,可以删除所有PRINT语句,也可以删除close the cursor

使用后者,我改变了所有的exec行:

$pdo->exec($sql);

查询并关闭游标:

$pdo->query($sql)->closeCursor();

TL;博士

在每个批处理语句之后,我遍历结果集以查看如下错误消息:

$stmt = $pdo->prepare($sql);
$stmt->execute();
do {
    var_dump($stmt->errorInfo());
} while ($stmt->nextRowset());

我得到了一些奇怪的结果。首先,我得到其中的3个,这是有道理的,因为我没有触发器,视图或函数。

array(4) {
  [0] =>
  string(5) "00000"
  [1] =>
  int(0)
  [2] =>
  string(24) " ((null)[0] at (null):0)"
  [3] =>
  string(0) ""
}

然后我得到其中的16个。在18个表中,其中16个有外键,所以这也是有道理的。虽然,很奇怪为什么我只看到循环中的最后一个print语句(我希望{last = {1}}最后被丢弃)重复循环的每次迭代。我希望对于掉落的16个fk_constraints中的每一个,print语句都是不同的。

fk_DataRecord

然后我感到困惑的是这个问题不再存在了!

这让我在execute documentation

中发现了一个有用的注释
  

注意:
  某些驱动程序需要在执行下一个语句之前关闭游标。