- finally removed sql_numrows
[phpbb.git] / phpBB / includes / db / mssql.php
blob19bc3709d67f9193bccd3ba71b67bd3cc6304faa
1 <?php
2 /**
4 * @package dbal
5 * @version $Id$
6 * @copyright (c) 2005 phpBB Group
7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
9 */
11 /**
13 if (!defined('IN_PHPBB'))
15 exit;
18 /**
19 * @ignore
21 if (!defined('SQL_LAYER'))
24 define('SQL_LAYER', 'mssql');
25 include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx);
27 /**
28 * MSSQL Database Abstraction Layer
29 * Minimum Requirement is MSSQL 2000+
30 * @package dbal
32 class dbal_mssql extends dbal
34 /**
35 * Connect to server
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);
51 return false;
55 return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
58 /**
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);
65 $row = false;
66 if ($result_id)
68 $row = @mssql_fetch_assoc($result_id);
69 @mssql_free_result($result_id);
72 if ($row)
74 return 'MSSQL<br />' . implode(' ', $row);
77 return 'MSSQL';
80 /**
81 * SQL Transaction
82 * @access private
84 function _sql_transaction($status = 'begin')
86 switch ($status)
88 case 'begin':
89 return @mssql_query('BEGIN TRANSACTION', $this->db_connect_id);
90 break;
92 case 'commit':
93 return @mssql_query('commit', $this->db_connect_id);
94 break;
96 case 'rollback':
97 return @mssql_query('ROLLBACK', $this->db_connect_id);
98 break;
101 return true;
105 * Base query method
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
111 * @access public
113 function sql_query($query = '', $cache_ttl = 0)
115 if ($query != '')
117 global $cache;
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);
158 else
160 return false;
163 return ($this->query_result) ? $this->query_result : false;
167 * Build LIMIT query
169 function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
171 if ($query != '')
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)
176 if ($total)
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);
183 else
185 $query = 'SELECT TOP ' . ($total + $offset) . ' ' . substr($query, 6);
189 $result = $this->sql_query($query, $cache_ttl);
191 // Seek by $offset rows
192 if ($offset)
194 $this->sql_rowseek($offset, $result);
197 return $result;
199 else
201 return false;
206 * Return number of affected rows
208 function sql_affectedrows()
210 return ($this->db_connect_id) ? @mssql_rows_affected($this->db_connect_id) : false;
214 * Fetch current row
216 function sql_fetchrow($query_id = false)
218 global $cache;
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)
232 return 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
238 if ($row)
240 foreach ($row as $key => $value)
242 $row[$key] = ($value === ' ') ? '' : $value;
246 return $row;
250 * Seek to given row number
251 * rownum is zero-based
253 function sql_rowseek($rownum, $query_id = false)
255 global $cache;
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);
276 if ($result_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);
286 return false;
290 * Free sql result
292 function sql_freeresult($query_id = false)
294 global $cache;
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);
312 return false;
316 * Escape string used in sql query
318 function sql_escape($msg)
320 return str_replace("'", "''", $msg);
324 * return sql error array
325 * @access private
327 function _sql_error()
329 $error = array(
330 'message' => @mssql_get_last_message($this->db_connect_id),
331 'code' => ''
334 // Get error code number
335 $result_id = @mssql_query('SELECT @@ERROR as code', $this->db_connect_id);
336 if ($result_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);
349 if ($result_id)
351 $row = @mssql_fetch_assoc($result_id);
352 if (!empty($row['message']))
354 $error['message'] .= '<br />' . $row['message'];
356 @mssql_free_result($result_id);
359 return $error;
363 * Build db-specific query data
364 * @access private
366 function _sql_custom_build($stage, $data)
368 return $data;
372 * Close sql connection
373 * @access private
375 function _sql_close()
377 return @mssql_close($this->db_connect_id);
381 * Build db-specific report
382 * @access private
384 function _sql_report($mode, $query = '')
386 switch ($mode)
388 case 'start':
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))
401 $html_table = false;
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);
414 if ($html_table)
416 $this->html_hold .= '</table>';
419 break;
421 case 'fromcache':
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);
437 break;
443 } // if ... define