ZF-7698: Cannot 'describeTables' with SQLServer 2000, using Zend_Db_Adapter_Sqlsrv

Description

Connecting to SQLServer 2000 using the latest Sqlsrv driver (1.1 CTP Aug 09 release), with the Microsoft SQL Server Native Client 2008, on a windows IIS server (6.0) using FastCGI and PHP v5.2.10

The describeTable function fails with the exception: 'The connection cannot process this operation because there is a statement with pending results. To make the connection available for other queries, either fetch all results or cancel or free the statement. For more information, see the product documentation about the MultipleActiveResultSets connection option'

Line 436 in Zend\Db\Adapter\SqlSrv.php executes a stored procedure, but the script cannot run the next stored procedure on line 455 without first clearing the statement.

I propose unsetting the first statement after the result set is returned:

Line 439: unset($stmt);

This will resolve the describeTable issue with SQLServer 2000.

Comments

Hi!

I face the same error as described here with Zend Framework 1.10.0. And suggested solution works for me too.

It's just one line - why not fix this? :)

Thanks!

Same on 1.10.1 and also with MSSQL2008.

Zend_Db_Statement_Sqlsrv_Exception: The connection cannot process this operation because there is a statement with pending results. To make the connection available for other queries, either fetch all results or cancel or free the statement. For more information, see the produc t documentation about the MultipleActiveResultSets connection option. in [...]\ZendFramework-1.10.1\library\Zend\Db\Statement\Sqlsrv.php o n line 206

This adapter is not supposed to be used in Sql server 2000 (http://msdn.microsoft.com/en-US/library/cc296172(v=SQL.90).aspx). I have added code to fix this though.

Fixed in r21882

Which adapter do you mean? zend, php_sqlsvr or native sql driver

Here http://msdn.microsoft.com/en-US/library/… is a response from Ashay Chaudhary and he writes: MSFT RESPONSE: Yes, it should work. SQL Server 2000 is the oldest version supported by this driver.

If you look into the driver documentation, you will also find that the sql2k server is supported.

but thats all for the native driver. i didnt found informations about php_sqlsvr, but it uses the native driver.

I just to a look on your fixed code.

Maybe, you also should free the second statment on/after line 467.

{{// Discover primary key column(s) for this table.}} {{$primaryKeysResult = $stmt->fetchAll(Zend_Db::FETCH_NUM);}}

Sqlsrv adapter uses sqlsrv driver, which requirements are here http://msdn.microsoft.com/en-US/library/cc296170(v=SQL.90).aspx But that comment now confused me as in all texts 2005 is referenced as lowest version supported.

Let me get back to you after I speak with Ashay.

isnt fixed in 1.10.7

my patch

public function describeTable($tableName, $schemaName = null) { /** * Discover metadata information about this table. */ $sql = "exec sp_columns @table_name = " . $this->quoteIdentifier($tableName, true); $stmt = $this->query($sql); $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); unset($stmt);

    $owner           = 1;
    $table_name      = 2;
    $column_name     = 3;
    $type_name       = 5;
    $precision       = 6;
    $length          = 7;
    $scale           = 8;
    $nullable        = 10;
    $column_def      = 12;
    $column_position = 16;

    /**
     * Discover primary key column(s) for this table.
     */
    $tableOwner = $result[0][$owner];
    $sql        = "exec sp_pkeys @table_owner = " . $tableOwner
                . ", @table_name = " . $this->quoteIdentifier($tableName, true);
    $stmt       = $this->query($sql);

unset($stmt);

    $primaryKeysResult = $stmt->fetchAll(Zend_Db::FETCH_NUM);
    $primaryKeyColumn  = array();

    // Per <a rel="nofollow" href="http://msdn.microsoft.com/en-us/library/ms189813.aspx">http://msdn.microsoft.com/en-us/library/&hellip;</a>,
    // results from sp_keys stored procedure are:
    // 0=TABLE_QUALIFIER 1=TABLE_OWNER 2=TABLE_NAME 3=COLUMN_NAME 4=KEY_SEQ 5=PK_NAME

    $pkey_column_name = 3;
    $pkey_key_seq     = 4;
    foreach ($primaryKeysResult as $pkeysRow) {
        $primaryKeyColumn[$pkeysRow[$pkey_column_name]] = $pkeysRow[$pkey_key_seq];
    }

    $desc = array();
    $p    = 1;
    foreach ($result as $key => $row) {
        $identity = false;
        $words    = explode(' ', $row[$type_name], 2);
        if (isset($words[0])) {
            $type = $words[0];
            if (isset($words[1])) {
                $identity = (bool) preg_match('/identity/', $words[1]);
            }
        }

        $isPrimary = array_key_exists($row[$column_name], $primaryKeyColumn);
        if ($isPrimary) {
            $primaryPosition = $primaryKeyColumn[$row[$column_name]];
        } else {
            $primaryPosition = null;
        }

        $desc[$this->foldCase($row[$column_name])] = array(
            'SCHEMA_NAME'      => null, // @todo
            'TABLE_NAME'       => $this->foldCase($row[$table_name]),
            'COLUMN_NAME'      => $this->foldCase($row[$column_name]),
            'COLUMN_POSITION'  => (int) $row[$column_position],
            'DATA_TYPE'        => $type,
            'DEFAULT'          => $row[$column_def],
            'NULLABLE'         => (bool) $row[$nullable],
            'LENGTH'           => $row[$length],
            'SCALE'            => $row[$scale],
            'PRECISION'        => $row[$precision],
            'UNSIGNED'         => null, // @todo
            'PRIMARY'          => $isPrimary,
            'PRIMARY_POSITION' => $primaryPosition,
            'IDENTITY'         => $identity,
        );
    }

    return $desc;
}