From 5c5b0fc4beeb51288e3ec83f6b253f1d4134f50d Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Mon, 25 Oct 2010 03:27:38 +0200 Subject: [PATCH] [ticket/9686] Fix mssqlnative database data export We require version 1.1 of the sqlsrv extension anyway so the regular sqlsrv_num_rows can be used instead of buffering the result. The result buffer (class result_mssqlnative) should never automatically free the resource it receives - we consistently close resources using sql_freeresult(). PHPBB3-9686 --- phpBB/includes/acp/acp_database.php | 54 +++++++++++++++++------------ phpBB/includes/db/mssqlnative.php | 20 ++++++++--- 2 files changed, 46 insertions(+), 28 deletions(-) diff --git a/phpBB/includes/acp/acp_database.php b/phpBB/includes/acp/acp_database.php index 0582d6204e..193dd001c0 100644 --- a/phpBB/includes/acp/acp_database.php +++ b/phpBB/includes/acp/acp_database.php @@ -1619,41 +1619,48 @@ class mssql_extractor extends base_extractor function write_data_mssqlnative($table_name) { global $db; - $ary_type = $ary_name = $meta_array = array(); + $ary_type = $ary_name = array(); $ident_set = false; $sql_data = ''; // Grab all of the data from current table. $sql = "SELECT * FROM $table_name"; + $db->mssqlnative_set_query_options(array('Scrollable' => SQLSRV_CURSOR_STATIC)); $result = $db->sql_query($sql); - $retrieved_data = $db->mssqlnative_num_rows($result); + $retrieved_data = $db->mssqlnative_num_rows($result); - $meta_array = sqlsrv_field_metadata($result); - $i_num_fields = sqlsrv_num_fields($result); - + if (!$retrieved_data) + { + $db->sql_freeresult($result); + return; + } + + $sql = "SELECT * FROM $table_name"; + $result_fields = $db->sql_query_limit($sql, 1); + + $row = new result_mssqlnative($result_fields); + $i_num_fields = $row->num_fields(); + for ($i = 0; $i < $i_num_fields; $i++) { - $info = $db->mssqlnative_fieldInfo($table_name, $meta_array[$i]['Name']); - $ary_type[$i] = $info->type(); - $ary_name[$i] = $info->name(); + $ary_type[$i] = $row->field_type($i); + $ary_name[$i] = $row->field_name($i); } + $db->sql_freeresult($result_fields); + + $sql = "SELECT 1 as has_identity + FROM INFORMATION_SCHEMA.COLUMNS + WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1"; + $result2 = $db->sql_query($sql); + $row2 = $db->sql_fetchrow($result2); - if ($retrieved_data) + if (!empty($row2['has_identity'])) { - $sql = "SELECT 1 as has_identity - FROM INFORMATION_SCHEMA.COLUMNS - WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1"; - $result2 = $db->sql_query($sql); - $row2 = $db->sql_fetchrow($result2); - - if (!empty($row2['has_identity'])) - { - $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n"; - $ident_set = true; - } - $db->sql_freeresult($result2); + $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n"; + $ident_set = true; } + $db->sql_freeresult($result2); while ($row = $db->sql_fetchrow($result)) { @@ -1664,7 +1671,8 @@ class mssql_extractor extends base_extractor { $str_val = $row[$ary_name[$i]]; - if (preg_match('#char|text|bool|varbinary#i', $ary_type[$i])) + // defaults to type number - better quote just to be safe, so check for is_int too + if (is_int($ary_type[$i]) || preg_match('#char|text|bool|varbinary#i', $ary_type[$i])) { $str_quote = ''; $str_empty = "''"; @@ -1705,7 +1713,7 @@ class mssql_extractor extends base_extractor } $db->sql_freeresult($result); - if ($retrieved_data && $ident_set) + if ($ident_set) { $sql_data .= "\nSET IDENTITY_INSERT $table_name OFF\nGO\n"; } diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php index 44d5722e4f..d6ac3b3acc 100644 --- a/phpBB/includes/db/mssqlnative.php +++ b/phpBB/includes/db/mssqlnative.php @@ -51,7 +51,6 @@ class result_mssqlnative } $this->m_row_count = count($this->m_rows); - sqlsrv_free_stmt($queryresult); } private function array_to_obj($array, &$obj) @@ -199,6 +198,7 @@ class dbal_mssqlnative extends dbal { var $m_insert_id = NULL; var $last_query_text = ''; + var $query_options = array(); /** * Connect to server @@ -308,10 +308,12 @@ class dbal_mssqlnative extends dbal if ($this->query_result === false) { - if (($this->query_result = @sqlsrv_query($this->db_connect_id, $query)) === false) + if (($this->query_result = @sqlsrv_query($this->db_connect_id, $query, array(), $this->query_options)) === false) { $this->sql_error($query); } + // reset options for next query + $this->query_options = array(); if (defined('DEBUG_EXTRA')) { @@ -598,20 +600,28 @@ class dbal_mssqlnative extends dbal * Utility method used to retrieve number of rows * Emulates mysql_num_rows * Used in acp_database.php -> write_data_mssqlnative() + * Requires a static or keyset cursor to be definde via + * mssqlnative_set_query_options() */ function mssqlnative_num_rows($res) { if ($res !== false) { - $row = new result_mssqlnative($res); - $num_rows = $row->num_rows(); - return $num_rows; + return sqlsrv_num_rows($res); } else { return false; } } + + /** + * Allows setting mssqlnative specific query options passed to sqlsrv_query as 4th parameter. + */ + function mssqlnative_set_query_options($options) + { + $this->query_options = $options; + } } ?> \ No newline at end of file