source: trunk/forum/includes/db/mssql_odbc.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.1 KB
Line 
1<?php
2/**
3*
4* @package dbal
5* @version $Id: mssql_odbc.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* Unified ODBC functions
23* Unified ODBC functions support any database having ODBC driver, for example Adabas D, IBM DB2, iODBC, Solid, Sybase SQL Anywhere...
24* Here we only support MSSQL Server 2000+ because of the provided schema
25*
26* @note number of bytes returned for returning data depends on odbc.defaultlrl php.ini setting.
27* If it is limited to 4K for example only 4K of data is returned max, resulting in incomplete theme data for example.
28* @note odbc.defaultbinmode may affect UTF8 characters
29*
30* @package dbal
31*/
32class dbal_mssql_odbc extends dbal
33{
34 var $last_query_text = '';
35
36 /**
37 * Connect to server
38 */
39 function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
40 {
41 $this->persistency = $persistency;
42 $this->user = $sqluser;
43 $this->dbname = $database;
44
45 $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':';
46 $this->server = $sqlserver . (($port) ? $port_delimiter . $port : '');
47
48 $max_size = @ini_get('odbc.defaultlrl');
49 if (!empty($max_size))
50 {
51 $unit = strtolower(substr($max_size, -1, 1));
52 $max_size = (int) $max_size;
53
54 if ($unit == 'k')
55 {
56 $max_size = floor($max_size / 1024);
57 }
58 else if ($unit == 'g')
59 {
60 $max_size *= 1024;
61 }
62 else if (is_numeric($unit))
63 {
64 $max_size = floor((int) ($max_size . $unit) / 1048576);
65 }
66 $max_size = max(8, $max_size) . 'M';
67
68 @ini_set('odbc.defaultlrl', $max_size);
69 }
70
71 $this->db_connect_id = ($this->persistency) ? @odbc_pconnect($this->server, $this->user, $sqlpassword) : @odbc_connect($this->server, $this->user, $sqlpassword);
72
73 return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
74 }
75
76 /**
77 * Version information about used database
78 * @param bool $raw if true, only return the fetched sql_server_version
79 * @return string sql server version
80 */
81 function sql_server_info($raw = false)
82 {
83 global $cache;
84
85 if (empty($cache) || ($this->sql_server_version = $cache->get('mssqlodbc_version')) === false)
86 {
87 $result_id = @odbc_exec($this->db_connect_id, "SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY('productlevel'), SERVERPROPERTY('edition')");
88
89 $row = false;
90 if ($result_id)
91 {
92 $row = @odbc_fetch_array($result_id);
93 @odbc_free_result($result_id);
94 }
95
96 $this->sql_server_version = ($row) ? trim(implode(' ', $row)) : 0;
97
98 if (!empty($cache))
99 {
100 $cache->put('mssqlodbc_version', $this->sql_server_version);
101 }
102 }
103
104 if ($raw)
105 {
106 return $this->sql_server_version;
107 }
108
109 return ($this->sql_server_version) ? 'MSSQL (ODBC)<br />' . $this->sql_server_version : 'MSSQL (ODBC)';
110 }
111
112 /**
113 * SQL Transaction
114 * @access private
115 */
116 function _sql_transaction($status = 'begin')
117 {
118 switch ($status)
119 {
120 case 'begin':
121 return @odbc_exec($this->db_connect_id, 'BEGIN TRANSACTION');
122 break;
123
124 case 'commit':
125 return @odbc_exec($this->db_connect_id, 'COMMIT TRANSACTION');
126 break;
127
128 case 'rollback':
129 return @odbc_exec($this->db_connect_id, 'ROLLBACK TRANSACTION');
130 break;
131 }
132
133 return true;
134 }
135
136 /**
137 * Base query method
138 *
139 * @param string $query Contains the SQL query which shall be executed
140 * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache
141 * @return mixed When casted to bool the returned value returns true on success and false on failure
142 *
143 * @access public
144 */
145 function sql_query($query = '', $cache_ttl = 0)
146 {
147 if ($query != '')
148 {
149 global $cache;
150
151 // EXPLAIN only in extra debug mode
152 if (defined('DEBUG_EXTRA'))
153 {
154 $this->sql_report('start', $query);
155 }
156
157 $this->last_query_text = $query;
158 $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false;
159 $this->sql_add_num_queries($this->query_result);
160
161 if ($this->query_result === false)
162 {
163 if (($this->query_result = @odbc_exec($this->db_connect_id, $query)) === false)
164 {
165 $this->sql_error($query);
166 }
167
168 if (defined('DEBUG_EXTRA'))
169 {
170 $this->sql_report('stop', $query);
171 }
172
173 if ($cache_ttl && method_exists($cache, 'sql_save'))
174 {
175 $this->open_queries[(int) $this->query_result] = $this->query_result;
176 $cache->sql_save($query, $this->query_result, $cache_ttl);
177 }
178 else if (strpos($query, 'SELECT') === 0 && $this->query_result)
179 {
180 $this->open_queries[(int) $this->query_result] = $this->query_result;
181 }
182 }
183 else if (defined('DEBUG_EXTRA'))
184 {
185 $this->sql_report('fromcache', $query);
186 }
187 }
188 else
189 {
190 return false;
191 }
192
193 return $this->query_result;
194 }
195
196 /**
197 * Build LIMIT query
198 */
199 function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
200 {
201 $this->query_result = false;
202
203 // Since TOP is only returning a set number of rows we won't need it if total is set to 0 (return all rows)
204 if ($total)
205 {
206 // We need to grab the total number of rows + the offset number of rows to get the correct result
207 if (strpos($query, 'SELECT DISTINCT') === 0)
208 {
209 $query = 'SELECT DISTINCT TOP ' . ($total + $offset) . ' ' . substr($query, 15);
210 }
211 else
212 {
213 $query = 'SELECT TOP ' . ($total + $offset) . ' ' . substr($query, 6);
214 }
215 }
216
217 $result = $this->sql_query($query, $cache_ttl);
218
219 // Seek by $offset rows
220 if ($offset)
221 {
222 $this->sql_rowseek($offset, $result);
223 }
224
225 return $result;
226 }
227
228 /**
229 * Return number of affected rows
230 */
231 function sql_affectedrows()
232 {
233 return ($this->db_connect_id) ? @odbc_num_rows($this->query_result) : false;
234 }
235
236 /**
237 * Fetch current row
238 * @note number of bytes returned depends on odbc.defaultlrl php.ini setting. If it is limited to 4K for example only 4K of data is returned max.
239 */
240 function sql_fetchrow($query_id = false, $debug = false)
241 {
242 global $cache;
243
244 if ($query_id === false)
245 {
246 $query_id = $this->query_result;
247 }
248
249 if (isset($cache->sql_rowset[$query_id]))
250 {
251 return $cache->sql_fetchrow($query_id);
252 }
253
254 return ($query_id !== false) ? @odbc_fetch_array($query_id) : false;
255 }
256
257 /**
258 * Seek to given row number
259 * rownum is zero-based
260 */
261 function sql_rowseek($rownum, &$query_id)
262 {
263 global $cache;
264
265 if ($query_id === false)
266 {
267 $query_id = $this->query_result;
268 }
269
270 if (isset($cache->sql_rowset[$query_id]))
271 {
272 return $cache->sql_rowseek($rownum, $query_id);
273 }
274
275 if ($query_id === false)
276 {
277 return false;
278 }
279
280 $this->sql_freeresult($query_id);
281 $query_id = $this->sql_query($this->last_query_text);
282
283 if ($query_id === false)
284 {
285 return false;
286 }
287
288 // We do not fetch the row for rownum == 0 because then the next resultset would be the second row
289 for ($i = 0; $i < $rownum; $i++)
290 {
291 if (!$this->sql_fetchrow($query_id))
292 {
293 return false;
294 }
295 }
296
297 return true;
298 }
299
300 /**
301 * Get last inserted id after insert statement
302 */
303 function sql_nextid()
304 {
305 $result_id = @odbc_exec($this->db_connect_id, 'SELECT @@IDENTITY');
306
307 if ($result_id)
308 {
309 if (@odbc_fetch_array($result_id))
310 {
311 $id = @odbc_result($result_id, 1);
312 @odbc_free_result($result_id);
313 return $id;
314 }
315 @odbc_free_result($result_id);
316 }
317
318 return false;
319 }
320
321 /**
322 * Free sql result
323 */
324 function sql_freeresult($query_id = false)
325 {
326 global $cache;
327
328 if ($query_id === false)
329 {
330 $query_id = $this->query_result;
331 }
332
333 if (isset($cache->sql_rowset[$query_id]))
334 {
335 return $cache->sql_freeresult($query_id);
336 }
337
338 if (isset($this->open_queries[(int) $query_id]))
339 {
340 unset($this->open_queries[(int) $query_id]);
341 return @odbc_free_result($query_id);
342 }
343
344 return false;
345 }
346
347 /**
348 * Escape string used in sql query
349 */
350 function sql_escape($msg)
351 {
352 return str_replace(array("'", "\0"), array("''", ''), $msg);
353 }
354
355 /**
356 * Build LIKE expression
357 * @access private
358 */
359 function _sql_like_expression($expression)
360 {
361 return $expression . " ESCAPE '\\'";
362 }
363
364 /**
365 * Build db-specific query data
366 * @access private
367 */
368 function _sql_custom_build($stage, $data)
369 {
370 return $data;
371 }
372
373 /**
374 * return sql error array
375 * @access private
376 */
377 function _sql_error()
378 {
379 return array(
380 'message' => @odbc_errormsg(),
381 'code' => @odbc_error()
382 );
383 }
384
385 /**
386 * Close sql connection
387 * @access private
388 */
389 function _sql_close()
390 {
391 return @odbc_close($this->db_connect_id);
392 }
393
394 /**
395 * Build db-specific report
396 * @access private
397 */
398 function _sql_report($mode, $query = '')
399 {
400 switch ($mode)
401 {
402 case 'start':
403 break;
404
405 case 'fromcache':
406 $endtime = explode(' ', microtime());
407 $endtime = $endtime[0] + $endtime[1];
408
409 $result = @odbc_exec($this->db_connect_id, $query);
410 while ($void = @odbc_fetch_array($result))
411 {
412 // Take the time spent on parsing rows into account
413 }
414 @odbc_free_result($result);
415
416 $splittime = explode(' ', microtime());
417 $splittime = $splittime[0] + $splittime[1];
418
419 $this->sql_report('record_fromcache', $query, $endtime, $splittime);
420
421 break;
422 }
423 }
424}
425
426?>
Note: See TracBrowser for help on using the repository browser.