source: trunk/forum/includes/db/mssql.php

Last change on this file was 400, checked in by george, 16 years ago
  • Přidáno: Nové forum phpBB 3.
File size: 9.7 KB
Line 
1<?php
2/**
3*
4* @package dbal
5* @version $Id: mssql.php 8967 2008-10-02 12:04:12Z acydburn $
6* @copyright (c) 2005 phpBB Group
7* @license http://opensource.org/licenses/gpl-license.php GNU Public License
8*
9*/
10
11/**
12* @ignore
13*/
14if (!defined('IN_PHPBB'))
15{
16 exit;
17}
18
19include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx);
20
21/**
22* MSSQL Database Abstraction Layer
23* Minimum Requirement is MSSQL 2000+
24* @package dbal
25*/
26class dbal_mssql extends dbal
27{
28 /**
29 * Connect to server
30 */
31 function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
32 {
33 $this->persistency = $persistency;
34 $this->user = $sqluser;
35 $this->dbname = $database;
36
37 $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':';
38 $this->server = $sqlserver . (($port) ? $port_delimiter . $port : '');
39
40 @ini_set('mssql.charset', 'UTF-8');
41 @ini_set('mssql.textlimit', 2147483647);
42 @ini_set('mssql.textsize', 2147483647);
43
44 if (version_compare(PHP_VERSION, '5.1.0', '>=') || (version_compare(PHP_VERSION, '5.0.0-dev', '<=') && version_compare(PHP_VERSION, '4.4.1', '>=')))
45 {
46 $this->db_connect_id = ($this->persistency) ? @mssql_pconnect($this->server, $this->user, $sqlpassword, $new_link) : @mssql_connect($this->server, $this->user, $sqlpassword, $new_link);
47 }
48 else
49 {
50 $this->db_connect_id = ($this->persistency) ? @mssql_pconnect($this->server, $this->user, $sqlpassword) : @mssql_connect($this->server, $this->user, $sqlpassword);
51 }
52
53 if ($this->db_connect_id && $this->dbname != '')
54 {
55 if (!@mssql_select_db($this->dbname, $this->db_connect_id))
56 {
57 @mssql_close($this->db_connect_id);
58 return false;
59 }
60 }
61
62 return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
63 }
64
65 /**
66 * Version information about used database
67 * @param bool $raw if true, only return the fetched sql_server_version
68 * @return string sql server version
69 */
70 function sql_server_info($raw = false)
71 {
72 global $cache;
73
74 if (empty($cache) || ($this->sql_server_version = $cache->get('mssql_version')) === false)
75 {
76 $result_id = @mssql_query("SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY('productlevel'), SERVERPROPERTY('edition')", $this->db_connect_id);
77
78 $row = false;
79 if ($result_id)
80 {
81 $row = @mssql_fetch_assoc($result_id);
82 @mssql_free_result($result_id);
83 }
84
85 $this->sql_server_version = ($row) ? trim(implode(' ', $row)) : 0;
86
87 if (!empty($cache))
88 {
89 $cache->put('mssql_version', $this->sql_server_version);
90 }
91 }
92
93 if ($raw)
94 {
95 return $this->sql_server_version;
96 }
97
98 return ($this->sql_server_version) ? 'MSSQL<br />' . $this->sql_server_version : 'MSSQL';
99 }
100
101 /**
102 * SQL Transaction
103 * @access private
104 */
105 function _sql_transaction($status = 'begin')
106 {
107 switch ($status)
108 {
109 case 'begin':
110 return @mssql_query('BEGIN TRANSACTION', $this->db_connect_id);
111 break;
112
113 case 'commit':
114 return @mssql_query('COMMIT TRANSACTION', $this->db_connect_id);
115 break;
116
117 case 'rollback':
118 return @mssql_query('ROLLBACK TRANSACTION', $this->db_connect_id);
119 break;
120 }
121
122 return true;
123 }
124
125 /**
126 * Base query method
127 *
128 * @param string $query Contains the SQL query which shall be executed
129 * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache
130 * @return mixed When casted to bool the returned value returns true on success and false on failure
131 *
132 * @access public
133 */
134 function sql_query($query = '', $cache_ttl = 0)
135 {
136 if ($query != '')
137 {
138 global $cache;
139
140 // EXPLAIN only in extra debug mode
141 if (defined('DEBUG_EXTRA'))
142 {
143 $this->sql_report('start', $query);
144 }
145
146 $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false;
147 $this->sql_add_num_queries($this->query_result);
148
149 if ($this->query_result === false)
150 {
151 if (($this->query_result = @mssql_query($query, $this->db_connect_id)) === false)
152 {
153 $this->sql_error($query);
154 }
155
156 if (defined('DEBUG_EXTRA'))
157 {
158 $this->sql_report('stop', $query);
159 }
160
161 if ($cache_ttl && method_exists($cache, 'sql_save'))
162 {
163 $this->open_queries[(int) $this->query_result] = $this->query_result;
164 $cache->sql_save($query, $this->query_result, $cache_ttl);
165 }
166 else if (strpos($query, 'SELECT') === 0 && $this->query_result)
167 {
168 $this->open_queries[(int) $this->query_result] = $this->query_result;
169 }
170 }
171 else if (defined('DEBUG_EXTRA'))
172 {
173 $this->sql_report('fromcache', $query);
174 }
175 }
176 else
177 {
178 return false;
179 }
180
181 return $this->query_result;
182 }
183
184 /**
185 * Build LIMIT query
186 */
187 function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
188 {
189 $this->query_result = false;
190
191 // Since TOP is only returning a set number of rows we won't need it if total is set to 0 (return all rows)
192 if ($total)
193 {
194 // We need to grab the total number of rows + the offset number of rows to get the correct result
195 if (strpos($query, 'SELECT DISTINCT') === 0)
196 {
197 $query = 'SELECT DISTINCT TOP ' . ($total + $offset) . ' ' . substr($query, 15);
198 }
199 else
200 {
201 $query = 'SELECT TOP ' . ($total + $offset) . ' ' . substr($query, 6);
202 }
203 }
204
205 $result = $this->sql_query($query, $cache_ttl);
206
207 // Seek by $offset rows
208 if ($offset)
209 {
210 $this->sql_rowseek($offset, $result);
211 }
212
213 return $result;
214 }
215
216 /**
217 * Return number of affected rows
218 */
219 function sql_affectedrows()
220 {
221 return ($this->db_connect_id) ? @mssql_rows_affected($this->db_connect_id) : false;
222 }
223
224 /**
225 * Fetch current row
226 */
227 function sql_fetchrow($query_id = false)
228 {
229 global $cache;
230
231 if ($query_id === false)
232 {
233 $query_id = $this->query_result;
234 }
235
236 if (isset($cache->sql_rowset[$query_id]))
237 {
238 return $cache->sql_fetchrow($query_id);
239 }
240
241 if ($query_id === false)
242 {
243 return false;
244 }
245
246 $row = @mssql_fetch_assoc($query_id);
247
248 // I hope i am able to remove this later... hopefully only a PHP or MSSQL bug
249 if ($row)
250 {
251 foreach ($row as $key => $value)
252 {
253 $row[$key] = ($value === ' ' || $value === NULL) ? '' : $value;
254 }
255 }
256
257 return $row;
258 }
259
260 /**
261 * Seek to given row number
262 * rownum is zero-based
263 */
264 function sql_rowseek($rownum, &$query_id)
265 {
266 global $cache;
267
268 if ($query_id === false)
269 {
270 $query_id = $this->query_result;
271 }
272
273 if (isset($cache->sql_rowset[$query_id]))
274 {
275 return $cache->sql_rowseek($rownum, $query_id);
276 }
277
278 return ($query_id !== false) ? @mssql_data_seek($query_id, $rownum) : false;
279 }
280
281 /**
282 * Get last inserted id after insert statement
283 */
284 function sql_nextid()
285 {
286 $result_id = @mssql_query('SELECT SCOPE_IDENTITY()', $this->db_connect_id);
287 if ($result_id)
288 {
289 if ($row = @mssql_fetch_assoc($result_id))
290 {
291 @mssql_free_result($result_id);
292 return $row['computed'];
293 }
294 @mssql_free_result($result_id);
295 }
296
297 return false;
298 }
299
300 /**
301 * Free sql result
302 */
303 function sql_freeresult($query_id = false)
304 {
305 global $cache;
306
307 if ($query_id === false)
308 {
309 $query_id = $this->query_result;
310 }
311
312 if (isset($cache->sql_rowset[$query_id]))
313 {
314 return $cache->sql_freeresult($query_id);
315 }
316
317 if (isset($this->open_queries[$query_id]))
318 {
319 unset($this->open_queries[$query_id]);
320 return @mssql_free_result($query_id);
321 }
322
323 return false;
324 }
325
326 /**
327 * Escape string used in sql query
328 */
329 function sql_escape($msg)
330 {
331 return str_replace(array("'", "\0"), array("''", ''), $msg);
332 }
333
334 /**
335 * Build LIKE expression
336 * @access private
337 */
338 function _sql_like_expression($expression)
339 {
340 return $expression . " ESCAPE '\\'";
341 }
342
343 /**
344 * return sql error array
345 * @access private
346 */
347 function _sql_error()
348 {
349 $error = array(
350 'message' => @mssql_get_last_message(),
351 'code' => ''
352 );
353
354 // Get error code number
355 $result_id = @mssql_query('SELECT @@ERROR as code', $this->db_connect_id);
356 if ($result_id)
357 {
358 $row = @mssql_fetch_assoc($result_id);
359 $error['code'] = $row['code'];
360 @mssql_free_result($result_id);
361 }
362
363 // Get full error message if possible
364 $sql = 'SELECT CAST(description as varchar(255)) as message
365 FROM master.dbo.sysmessages
366 WHERE error = ' . $error['code'];
367 $result_id = @mssql_query($sql);
368
369 if ($result_id)
370 {
371 $row = @mssql_fetch_assoc($result_id);
372 if (!empty($row['message']))
373 {
374 $error['message'] .= '<br />' . $row['message'];
375 }
376 @mssql_free_result($result_id);
377 }
378
379 return $error;
380 }
381
382 /**
383 * Build db-specific query data
384 * @access private
385 */
386 function _sql_custom_build($stage, $data)
387 {
388 return $data;
389 }
390
391 /**
392 * Close sql connection
393 * @access private
394 */
395 function _sql_close()
396 {
397 return @mssql_close($this->db_connect_id);
398 }
399
400 /**
401 * Build db-specific report
402 * @access private
403 */
404 function _sql_report($mode, $query = '')
405 {
406 switch ($mode)
407 {
408 case 'start':
409 $html_table = false;
410 @mssql_query('SET SHOWPLAN_TEXT ON;', $this->db_connect_id);
411 if ($result = @mssql_query($query, $this->db_connect_id))
412 {
413 @mssql_next_result($result);
414 while ($row = @mssql_fetch_row($result))
415 {
416 $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
417 }
418 }
419 @mssql_query('SET SHOWPLAN_TEXT OFF;', $this->db_connect_id);
420 @mssql_free_result($result);
421
422 if ($html_table)
423 {
424 $this->html_hold .= '</table>';
425 }
426 break;
427
428 case 'fromcache':
429 $endtime = explode(' ', microtime());
430 $endtime = $endtime[0] + $endtime[1];
431
432 $result = @mssql_query($query, $this->db_connect_id);
433 while ($void = @mssql_fetch_assoc($result))
434 {
435 // Take the time spent on parsing rows into account
436 }
437 @mssql_free_result($result);
438
439 $splittime = explode(' ', microtime());
440 $splittime = $splittime[0] + $splittime[1];
441
442 $this->sql_report('record_fromcache', $query, $endtime, $splittime);
443
444 break;
445 }
446 }
447}
448
449?>
Note: See TracBrowser for help on using the repository browser.