#7424
[phpbb.git] / phpBB / includes / db / oracle.php
blob860c7a3614466c25cec9b08146955a0fc8278e16
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 /**
12 * @ignore
14 if (!defined('IN_PHPBB'))
16 exit;
19 include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx);
21 /**
22 * Oracle Database Abstraction Layer
23 * @package dbal
25 class dbal_oracle extends dbal
27 var $last_query_text = '';
29 /**
30 * Connect to server
32 function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false)
34 $this->persistency = $persistency;
35 $this->user = $sqluser;
36 $this->server = $sqlserver . (($port) ? ':' . $port : '');
37 $this->dbname = $database;
39 $this->db_connect_id = ($this->persistency) ? @ociplogon($this->user, $sqlpassword, $this->server, 'UTF8') : @ocinlogon($this->user, $sqlpassword, $this->server, 'UTF8');
41 return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
44 /**
45 * Version information about used database
47 function sql_server_info()
49 return @ociserverversion($this->db_connect_id);
52 /**
53 * SQL Transaction
54 * @access private
56 function _sql_transaction($status = 'begin')
58 switch ($status)
60 case 'begin':
61 return true;
62 break;
64 case 'commit':
65 return @ocicommit($this->db_connect_id);
66 break;
68 case 'rollback':
69 return @ocirollback($this->db_connect_id);
70 break;
73 return true;
76 /**
77 * Base query method
79 * @param string $query Contains the SQL query which shall be executed
80 * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache
81 * @return mixed When casted to bool the returned value returns true on success and false on failure
83 * @access public
85 function sql_query($query = '', $cache_ttl = 0)
87 if ($query != '')
89 global $cache;
91 // EXPLAIN only in extra debug mode
92 if (defined('DEBUG_EXTRA'))
94 $this->sql_report('start', $query);
97 $this->last_query_text = $query;
98 $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false;
99 $this->sql_add_num_queries($this->query_result);
101 if ($this->query_result === false)
103 $in_transaction = false;
104 if (!$this->transaction)
106 $this->sql_transaction('begin');
108 else
110 $in_transaction = true;
113 $array = array();
115 // We overcome Oracle's 4000 char limit by binding vars
116 if (preg_match('/^(INSERT INTO[^(]+)\\(([^()]+)\\) VALUES[^(]+\\(([^()]+)\\)$/', $query, $regs))
118 if (strlen($regs[3]) > 4000)
120 $cols = explode(', ', $regs[2]);
121 $vals = explode(', ', $regs[3]);
122 foreach ($vals as $key => $value)
124 if (strlen($value) > 4002) // check to see if this thing is greater than the max + 'x2
126 $vals[$key] = ':' . strtoupper($cols[$key]);
127 $array[$vals[$key]] = substr($value, 1, -1);
130 $query = $regs[1] . '(' . implode(', ', $cols) . ') VALUES (' . implode(', ', $vals) . ')';
133 else if (preg_match('/^(UPDATE.*?)SET (.*)(\\sWHERE.*)$/s', $query, $regs))
135 if (strlen($regs[2]) > 4000)
137 $args = explode(', ', $regs[2]);
138 $cols = array();
139 foreach ($args as $value)
141 $temp_array = explode('=', $value);
142 $cols[$temp_array[0]] = $temp_array[1];
145 foreach ($cols as $col => $val)
147 if (strlen($val) > 4003) // check to see if this thing is greater than the max + 'x2 + a space
149 $cols[$col] = ' :' . strtoupper(rtrim($col));
150 $array[ltrim($cols[$col])] = substr(trim($val), 2, -1);
154 $art = array();
155 foreach ($cols as $col => $val)
157 $art[] = $col . '=' . $val;
159 $query = $regs[1] . 'SET ' . implode(', ', $art) . $regs[3];
163 $this->query_result = @ociparse($this->db_connect_id, $query);
165 foreach ($array as $key => $value)
167 @ocibindbyname($this->query_result, $key, $array[$key], -1);
170 $success = @ociexecute($this->query_result, OCI_DEFAULT);
172 if (!$success)
174 $this->sql_error($query);
175 $this->query_result = false;
177 else
179 if (!$in_transaction)
181 $this->sql_transaction('commit');
185 if (defined('DEBUG_EXTRA'))
187 $this->sql_report('stop', $query);
190 if ($cache_ttl && method_exists($cache, 'sql_save'))
192 $this->open_queries[(int) $this->query_result] = $this->query_result;
193 $cache->sql_save($query, $this->query_result, $cache_ttl);
195 else if (strpos($query, 'SELECT') === 0 && $this->query_result)
197 $this->open_queries[(int) $this->query_result] = $this->query_result;
200 else if (defined('DEBUG_EXTRA'))
202 $this->sql_report('fromcache', $query);
205 else
207 return false;
210 return ($this->query_result) ? $this->query_result : false;
214 * Build LIMIT query
216 function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
218 $this->query_result = false;
220 $query = 'SELECT * FROM (SELECT /*+ FIRST_ROWS */ rownum AS xrownum, a.* FROM (' . $query . ') a WHERE rownum <= ' . ($offset + $total) . ') WHERE xrownum >= ' . $offset;
222 return $this->sql_query($query, $cache_ttl);
226 * Return number of affected rows
228 function sql_affectedrows()
230 return ($this->query_result) ? @ocirowcount($this->query_result) : false;
234 * Fetch current row
236 function sql_fetchrow($query_id = false)
238 global $cache;
240 if ($query_id === false)
242 $query_id = $this->query_result;
245 if (isset($cache->sql_rowset[$query_id]))
247 return $cache->sql_fetchrow($query_id);
250 if ($query_id !== false)
252 $row = array();
253 $result = @ocifetchinto($query_id, $row, OCI_ASSOC + OCI_RETURN_NULLS);
255 if (!$result || !$row)
257 return false;
260 $result_row = array();
261 foreach ($row as $key => $value)
263 // OCI->CLOB?
264 if (is_object($value))
266 $value = $value->load();
269 $result_row[strtolower($key)] = $value;
272 return $result_row;
275 return false;
279 * Seek to given row number
280 * rownum is zero-based
282 function sql_rowseek($rownum, $query_id = false)
284 global $cache;
286 if ($query_id === false)
288 $query_id = $this->query_result;
291 if (isset($cache->sql_rowset[$query_id]))
293 return $cache->sql_rowseek($rownum, $query_id);
296 if ($query_id === false)
298 return false;
301 // Reset internal pointer
302 @ociexecute($query_id, OCI_DEFAULT);
304 // We do not fetch the row for rownum == 0 because then the next resultset would be the second row
305 for ($i = 0; $i < $rownum; $i++)
307 if (!$this->sql_fetchrow($query_id))
309 return false;
313 return true;
317 * Get last inserted id after insert statement
319 function sql_nextid()
321 $query_id = $this->query_result;
323 if ($query_id !== false && $this->last_query_text != '')
325 if (preg_match('#^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)#is', $this->last_query_text, $tablename))
327 $query = 'SELECT ' . $tablename[1] . '_seq.currval FROM DUAL';
328 $stmt = @ociparse($this->db_connect_id, $query);
329 @ociexecute($stmt, OCI_DEFAULT);
331 $temp_result = @ocifetchinto($stmt, $temp_array, OCI_ASSOC + OCI_RETURN_NULLS);
332 @ocifreestatement($stmt);
334 if ($temp_result)
336 return $temp_array['CURRVAL'];
338 else
340 return false;
345 return false;
349 * Free sql result
351 function sql_freeresult($query_id = false)
353 global $cache;
355 if ($query_id === false)
357 $query_id = $this->query_result;
360 if (isset($cache->sql_rowset[$query_id]))
362 return $cache->sql_freeresult($query_id);
365 if (isset($this->open_queries[(int) $query_id]))
367 unset($this->open_queries[(int) $query_id]);
368 return @ocifreestatement($query_id);
371 return false;
375 * Escape string used in sql query
377 function sql_escape($msg)
379 return str_replace("'", "''", $msg);
382 function _sql_custom_build($stage, $data)
384 return $data;
388 * return sql error array
389 * @access private
391 function _sql_error()
393 $error = @ocierror();
394 $error = (!$error) ? @ocierror($this->query_result) : $error;
395 $error = (!$error) ? @ocierror($this->db_connect_id) : $error;
397 if ($error)
399 $this->last_error_result = $error;
401 else
403 $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array();
406 return $error;
410 * Close sql connection
411 * @access private
413 function _sql_close()
415 return @ocilogoff($this->db_connect_id);
419 * Build db-specific report
420 * @access private
422 function _sql_report($mode, $query = '')
424 switch ($mode)
426 case 'start':
427 break;
429 case 'fromcache':
430 $endtime = explode(' ', microtime());
431 $endtime = $endtime[0] + $endtime[1];
433 $result = @ociparse($this->db_connect_id, $query);
434 $success = @ociexecute($result, OCI_DEFAULT);
435 $row = array();
437 while (@ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS))
439 // Take the time spent on parsing rows into account
441 @ocifreestatement($result);
443 $splittime = explode(' ', microtime());
444 $splittime = $splittime[0] + $splittime[1];
446 $this->sql_report('record_fromcache', $query, $endtime, $splittime);
448 break;