6 * @copyright (c) 2005 phpBB Group
7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
13 if (!defined('IN_PHPBB'))
21 if (!defined('SQL_LAYER'))
24 define('SQL_LAYER', 'mssql');
25 include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx);
28 * MSSQL Database Abstraction Layer
29 * Minimum Requirement is MSSQL 2000+
32 class dbal_mssql
extends dbal
37 function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false)
39 $this->persistency
= $persistency;
40 $this->user
= $sqluser;
41 $this->server
= $sqlserver . (($port) ?
':' . $port : '');
42 $this->dbname
= $database;
44 $this->db_connect_id
= ($this->persistency
) ? @mssql_pconnect
($this->server
, $this->user
, $sqlpassword) : @mssql_connect
($this->server
, $this->user
, $sqlpassword);
46 if ($this->db_connect_id
&& $this->dbname
!= '')
48 if (!@mssql_select_db
($this->dbname
, $this->db_connect_id
))
50 @mssql_close
($this->db_connect_id
);
55 return ($this->db_connect_id
) ?
$this->db_connect_id
: $this->sql_error('');
59 * Version information about used database
61 function sql_server_info()
63 $result_id = @mssql_query
("SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY('productlevel'), SERVERPROPERTY('edition')", $this->db_connect_id
);
68 $row = @mssql_fetch_assoc
($result_id);
69 @mssql_free_result
($result_id);
74 return 'MSSQL<br />' . implode(' ', $row);
84 function _sql_transaction($status = 'begin')
89 return @mssql_query
('BEGIN TRANSACTION', $this->db_connect_id
);
93 return @mssql_query
('commit', $this->db_connect_id
);
97 return @mssql_query
('ROLLBACK', $this->db_connect_id
);
107 * @param string $query Contains the SQL query which shall be executed
108 * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache
109 * @return mixed When casted to bool the returned value returns true on success and false on failure
113 function sql_query($query = '', $cache_ttl = 0)
119 // EXPLAIN only in extra debug mode
120 if (defined('DEBUG_EXTRA'))
122 $this->sql_report('start', $query);
125 // For now, MSSQL has no real UTF-8 support
126 $query = utf8_decode($query);
128 $this->query_result
= ($cache_ttl && method_exists($cache, 'sql_load')) ?
$cache->sql_load($query) : false;
129 $this->sql_add_num_queries($this->query_result
);
131 if ($this->query_result
=== false)
133 if (($this->query_result
= @mssql_query
($query, $this->db_connect_id
)) === false)
135 $this->sql_error($query);
138 if (defined('DEBUG_EXTRA'))
140 $this->sql_report('stop', $query);
143 if ($cache_ttl && method_exists($cache, 'sql_save'))
145 $this->open_queries
[(int) $this->query_result
] = $this->query_result
;
146 $cache->sql_save($query, $this->query_result
, $cache_ttl);
148 else if (strpos($query, 'SELECT') === 0 && $this->query_result
)
150 $this->open_queries
[(int) $this->query_result
] = $this->query_result
;
153 else if (defined('DEBUG_EXTRA'))
155 $this->sql_report('fromcache', $query);
163 return ($this->query_result
) ?
$this->query_result
: false;
169 function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
173 $this->query_result
= false;
175 // Since TOP is only returning a set number of rows we won't need it if total is set to 0 (return all rows)
178 // We need to grab the total number of rows + the offset number of rows to get the correct result
179 if (strpos($query, 'SELECT DISTINCT') === 0)
181 $query = 'SELECT DISTINCT TOP ' . ($total +
$offset) . ' ' . substr($query, 15);
185 $query = 'SELECT TOP ' . ($total +
$offset) . ' ' . substr($query, 6);
189 $result = $this->sql_query($query, $cache_ttl);
191 // Seek by $offset rows
194 $this->sql_rowseek($offset, $result);
206 * Return number of affected rows
208 function sql_affectedrows()
210 return ($this->db_connect_id
) ? @mssql_rows_affected
($this->db_connect_id
) : false;
216 function sql_fetchrow($query_id = false)
220 if ($query_id === false)
222 $query_id = $this->query_result
;
225 if (isset($cache->sql_rowset
[$query_id]))
227 return $cache->sql_fetchrow($query_id);
230 if ($query_id === false)
235 $row = @mssql_fetch_assoc
($query_id);
237 // I hope i am able to remove this later... hopefully only a PHP or MSSQL bug
240 foreach ($row as $key => $value)
242 $row[$key] = ($value === ' ') ?
'' : $value;
250 * Seek to given row number
251 * rownum is zero-based
253 function sql_rowseek($rownum, $query_id = false)
257 if ($query_id === false)
259 $query_id = $this->query_result
;
262 if (isset($cache->sql_rowset
[$query_id]))
264 return $cache->sql_rowseek($rownum, $query_id);
267 return ($query_id !== false) ? @mssql_data_seek
($query_id, $rownum) : false;
271 * Get last inserted id after insert statement
273 function sql_nextid()
275 $result_id = @mssql_query
('SELECT @@IDENTITY', $this->db_connect_id
);
278 if ($row = @mssql_fetch_assoc
($result_id))
280 @mssql_free_result
($result_id);
281 return $row['computed'];
283 @mssql_free_result
($result_id);
292 function sql_freeresult($query_id = false)
296 if ($query_id === false)
298 $query_id = $this->query_result
;
301 if (isset($cache->sql_rowset
[$query_id]))
303 return $cache->sql_freeresult($query_id);
306 if (isset($this->open_queries
[$query_id]))
308 unset($this->open_queries
[$query_id]);
309 return @mssql_free_result
($query_id);
316 * Escape string used in sql query
318 function sql_escape($msg)
320 return str_replace("'", "''", $msg);
324 * return sql error array
327 function _sql_error()
330 'message' => @mssql_get_last_message
($this->db_connect_id
),
334 // Get error code number
335 $result_id = @mssql_query
('SELECT @@ERROR as code', $this->db_connect_id
);
338 $row = @mssql_fetch_assoc
($result_id);
339 $error['code'] = $row['code'];
340 @mssql_free_result
($result_id);
343 // Get full error message if possible
344 $sql = 'SELECT CAST(description as varchar(255)) as message
345 FROM master.dbo.sysmessages
346 WHERE error = ' . $error['code'];
347 $result_id = @mssql_query
($sql);
351 $row = @mssql_fetch_assoc
($result_id);
352 if (!empty($row['message']))
354 $error['message'] .= '<br />' . $row['message'];
356 @mssql_free_result
($result_id);
363 * Build db-specific query data
366 function _sql_custom_build($stage, $data)
372 * Close sql connection
375 function _sql_close()
377 return @mssql_close
($this->db_connect_id
);
381 * Build db-specific report
384 function _sql_report($mode, $query = '')
389 $explain_query = $query;
390 if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
392 $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
394 else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
396 $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
399 if (preg_match('/^SELECT/', $explain_query))
402 @mssql_query
("SET SHOWPLAN_TEXT ON;", $this->db_connect_id
);
403 if ($result = @mssql_query
($explain_query, $this->db_connect_id
))
405 @mssql_next_result
($result);
406 while ($row = @mssql_fetch_row
($result))
408 $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
411 @mssql_query
("SET SHOWPLAN_TEXT OFF;", $this->db_connect_id
);
412 @mssql_free_result
($result);
416 $this->html_hold
.= '</table>';
422 $endtime = explode(' ', microtime());
423 $endtime = $endtime[0] +
$endtime[1];
425 $result = @mssql_query
($query, $this->db_connect_id
);
426 while ($void = @mssql_fetch_assoc
($result))
428 // Take the time spent on parsing rows into account
430 @mssql_free_result
($result);
432 $splittime = explode(' ', microtime());
433 $splittime = $splittime[0] +
$splittime[1];
435 $this->sql_report('record_fromcache', $query, $endtime, $splittime);