blob: b90db4bd211fd1b629952cae5fa6e6170c8b05ca [file] [log] [blame]
Andrey Andreevc5536aa2012-11-01 17:33:58 +02001<?php
Derek Allard2067d1a2008-11-13 22:59:24 +00002/**
3 * CodeIgniter
4 *
Andrey Andreevfe9309d2015-01-09 17:48:58 +02005 * An open source application development framework for PHP
Derek Allard2067d1a2008-11-13 22:59:24 +00006 *
Andrey Andreevbdb96ca2014-10-28 00:13:31 +02007 * This content is released under the MIT License (MIT)
Andrey Andreev24abcb92012-01-05 20:40:15 +02008 *
Andrey Andreevcce6bd12018-01-09 11:32:02 +02009 * Copyright (c) 2014 - 2018, British Columbia Institute of Technology
Andrey Andreev24abcb92012-01-05 20:40:15 +020010 *
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020011 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
Derek Jonesf4a4bd82011-10-20 12:18:42 -050017 *
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020018 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 * THE SOFTWARE.
28 *
29 * @package CodeIgniter
30 * @author EllisLab Dev Team
Andrey Andreev1924e872016-01-11 12:55:34 +020031 * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
Andrey Andreevcce6bd12018-01-09 11:32:02 +020032 * @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020033 * @license http://opensource.org/licenses/MIT MIT License
Andrey Andreevbd202c92016-01-11 12:50:18 +020034 * @link https://codeigniter.com
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020035 * @since Version 1.4.1
Derek Allard2067d1a2008-11-13 22:59:24 +000036 * @filesource
37 */
Andrey Andreevc5536aa2012-11-01 17:33:58 +020038defined('BASEPATH') OR exit('No direct script access allowed');
Derek Allard2067d1a2008-11-13 22:59:24 +000039
Derek Allard2067d1a2008-11-13 22:59:24 +000040/**
41 * oci8 Database Adapter Class
42 *
43 * Note: _DB is an extender class that the app controller
Jamie Rumbelow7efad202012-02-19 12:37:00 +000044 * creates dynamically based on whether the query builder
Derek Allard2067d1a2008-11-13 22:59:24 +000045 * class is being used or not.
46 *
Barry Mienydd671972010-10-04 16:33:58 +020047 * @package CodeIgniter
Derek Jones4b9c6292011-07-01 17:40:48 -050048 * @subpackage Drivers
Derek Allard2067d1a2008-11-13 22:59:24 +000049 * @category Database
Derek Jonesf4a4bd82011-10-20 12:18:42 -050050 * @author EllisLab Dev Team
Andrey Andreevbd202c92016-01-11 12:50:18 +020051 * @link https://codeigniter.com/user_guide/database/
Derek Allard2067d1a2008-11-13 22:59:24 +000052 */
53
54/**
55 * oci8 Database Adapter Class
56 *
57 * This is a modification of the DB_driver class to
58 * permit access to oracle databases
59 *
Derek Jones4b9c6292011-07-01 17:40:48 -050060 * @author Kelly McArdle
Derek Allard2067d1a2008-11-13 22:59:24 +000061 */
Derek Allard2067d1a2008-11-13 22:59:24 +000062class CI_DB_oci8_driver extends CI_DB {
63
Andrey Andreeva24e52e2012-11-02 03:54:12 +020064 /**
65 * Database driver
66 *
67 * @var string
68 */
Andrey Andreev24abcb92012-01-05 20:40:15 +020069 public $dbdriver = 'oci8';
Barry Mienydd671972010-10-04 16:33:58 +020070
Andrey Andreeva24e52e2012-11-02 03:54:12 +020071 /**
72 * Statement ID
73 *
74 * @var resource
75 */
76 public $stmt_id;
Barry Mienydd671972010-10-04 16:33:58 +020077
Derek Allard2067d1a2008-11-13 22:59:24 +000078 /**
Andrey Andreeva24e52e2012-11-02 03:54:12 +020079 * Cursor ID
80 *
81 * @var resource
Derek Allard2067d1a2008-11-13 22:59:24 +000082 */
Andrey Andreev24abcb92012-01-05 20:40:15 +020083 public $curs_id;
Derek Allard2067d1a2008-11-13 22:59:24 +000084
Andrey Andreeva24e52e2012-11-02 03:54:12 +020085 /**
86 * Commit mode flag
87 *
88 * @var int
89 */
90 public $commit_mode = OCI_COMMIT_ON_SUCCESS;
Derek Allard2067d1a2008-11-13 22:59:24 +000091
Andrey Andreev5fd3ae82012-10-24 14:55:35 +030092 /**
Andrey Andreeva24e52e2012-11-02 03:54:12 +020093 * Limit used flag
94 *
95 * If we use LIMIT, we'll add a field that will
96 * throw off num_fields later.
97 *
98 * @var bool
99 */
Andrey Andreev6efd42e2018-03-15 16:24:42 +0200100 public $limit_used = FALSE;
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200101
102 // --------------------------------------------------------------------
103
104 /**
Andrey Andreev611e1fd2015-07-17 12:24:29 +0300105 * Reset $stmt_id flag
106 *
107 * Used by stored_procedure() to prevent _execute() from
108 * re-setting the statement ID.
109 */
110 protected $_reset_stmt_id = TRUE;
111
112 /**
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200113 * List of reserved identifiers
114 *
115 * Identifiers that must NOT be escaped.
116 *
117 * @var string[]
118 */
119 protected $_reserved_identifiers = array('*', 'rownum');
120
121 /**
122 * ORDER BY random keyword
123 *
Andrey Andreev98e46cf2012-11-13 03:01:42 +0200124 * @var array
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200125 */
Andrey Andreev98e46cf2012-11-13 03:01:42 +0200126 protected $_random_keyword = array('ASC', 'ASC'); // not currently supported
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200127
128 /**
129 * COUNT string
130 *
131 * @used-by CI_DB_driver::count_all()
132 * @used-by CI_DB_query_builder::count_all_results()
133 *
134 * @var string
135 */
136 protected $_count_string = 'SELECT COUNT(1) AS ';
137
138 // --------------------------------------------------------------------
139
140 /**
141 * Class constructor
Andrey Andreev5fd3ae82012-10-24 14:55:35 +0300142 *
143 * @param array $params
144 * @return void
145 */
Andrey Andreevdad61c22012-02-13 01:08:06 +0200146 public function __construct($params)
147 {
148 parent::__construct($params);
149
150 $valid_dsns = array(
Andrey Andreev1a61ba42014-03-24 16:53:16 +0200151 'tns' => '/^\(DESCRIPTION=(\(.+\)){2,}\)$/', // TNS
152 // Easy Connect string (Oracle 10g+)
153 'ec' => '/^(\/\/)?[a-z0-9.:_-]+(:[1-9][0-9]{0,4})?(\/[a-z0-9$_]+)?(:[^\/])?(\/[a-z0-9$_]+)?$/i',
154 'in' => '/^[a-z0-9$_]+$/i' // Instance name (defined in tnsnames.ora)
155 );
Andrey Andreevdad61c22012-02-13 01:08:06 +0200156
157 /* Space characters don't have any effect when actually
158 * connecting, but can be a hassle while validating the DSN.
159 */
160 $this->dsn = str_replace(array("\n", "\r", "\t", ' '), '', $this->dsn);
161
162 if ($this->dsn !== '')
163 {
164 foreach ($valid_dsns as $regexp)
165 {
166 if (preg_match($regexp, $this->dsn))
167 {
168 return;
169 }
170 }
171 }
172
173 // Legacy support for TNS in the hostname configuration field
174 $this->hostname = str_replace(array("\n", "\r", "\t", ' '), '', $this->hostname);
175 if (preg_match($valid_dsns['tns'], $this->hostname))
176 {
177 $this->dsn = $this->hostname;
178 return;
179 }
180 elseif ($this->hostname !== '' && strpos($this->hostname, '/') === FALSE && strpos($this->hostname, ':') === FALSE
181 && (( ! empty($this->port) && ctype_digit($this->port)) OR $this->database !== ''))
182 {
183 /* If the hostname field isn't empty, doesn't contain
184 * ':' and/or '/' and if port and/or database aren't
185 * empty, then the hostname field is most likely indeed
186 * just a hostname. Therefore we'll try and build an
187 * Easy Connect string from these 3 settings, assuming
188 * that the database field is a service name.
189 */
190 $this->dsn = $this->hostname
Andrey Andreev1a61ba42014-03-24 16:53:16 +0200191 .(( ! empty($this->port) && ctype_digit($this->port)) ? ':'.$this->port : '')
192 .($this->database !== '' ? '/'.ltrim($this->database, '/') : '');
Andrey Andreevdad61c22012-02-13 01:08:06 +0200193
194 if (preg_match($valid_dsns['ec'], $this->dsn))
195 {
196 return;
197 }
198 }
199
200 /* At this point, we can only try and validate the hostname and
201 * database fields separately as DSNs.
202 */
203 if (preg_match($valid_dsns['ec'], $this->hostname) OR preg_match($valid_dsns['in'], $this->hostname))
204 {
205 $this->dsn = $this->hostname;
206 return;
207 }
208
209 $this->database = str_replace(array("\n", "\r", "\t", ' '), '', $this->database);
210 foreach ($valid_dsns as $regexp)
211 {
212 if (preg_match($regexp, $this->database))
213 {
214 return;
215 }
216 }
217
218 /* Well - OK, an empty string should work as well.
219 * PHP will try to use environment variables to
220 * determine which Oracle instance to connect to.
221 */
222 $this->dsn = '';
223 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000224
Andrey Andreevd5809992012-06-28 14:06:54 +0300225 // --------------------------------------------------------------------
226
Derek Allard2067d1a2008-11-13 22:59:24 +0000227 /**
228 * Non-persistent database connection
229 *
Andrey Andreev2e171022014-02-25 15:21:41 +0200230 * @param bool $persistent
Andrey Andreevaa786c92012-01-16 12:14:45 +0200231 * @return resource
Derek Allard2067d1a2008-11-13 22:59:24 +0000232 */
Andrey Andreev2e171022014-02-25 15:21:41 +0200233 public function db_connect($persistent = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000234 {
Andrey Andreev2e171022014-02-25 15:21:41 +0200235 $func = ($persistent === TRUE) ? 'oci_pconnect' : 'oci_connect';
Andrey Andreevd5809992012-06-28 14:06:54 +0300236 return empty($this->char_set)
Andrey Andreev2e171022014-02-25 15:21:41 +0200237 ? $func($this->username, $this->password, $this->dsn)
238 : $func($this->username, $this->password, $this->dsn, $this->char_set);
Derek Allard2067d1a2008-11-13 22:59:24 +0000239 }
240
241 // --------------------------------------------------------------------
242
243 /**
Andrey Andreev08856b82012-03-03 03:19:28 +0200244 * Database version number
Derek Allard2067d1a2008-11-13 22:59:24 +0000245 *
Andrey Andreev08856b82012-03-03 03:19:28 +0200246 * @return string
Derek Allard2067d1a2008-11-13 22:59:24 +0000247 */
Andrey Andreev08856b82012-03-03 03:19:28 +0200248 public function version()
Derek Allard2067d1a2008-11-13 22:59:24 +0000249 {
Andrey Andreev2b730372012-11-05 17:01:11 +0200250 if (isset($this->data_cache['version']))
251 {
252 return $this->data_cache['version'];
253 }
Andrey Andreev2b730372012-11-05 17:01:11 +0200254
Andrey Andreevbc05b842015-12-14 16:22:33 +0200255 if ( ! $this->conn_id OR ($version_string = oci_server_version($this->conn_id)) === FALSE)
Andrey Andreev2b730372012-11-05 17:01:11 +0200256 {
257 return FALSE;
258 }
Andrey Andreevbc05b842015-12-14 16:22:33 +0200259 elseif (preg_match('#Release\s(\d+(?:\.\d+)+)#', $version_string, $match))
260 {
261 return $this->data_cache['version'] = $match[1];
262 }
Andrey Andreev2b730372012-11-05 17:01:11 +0200263
Andrey Andreevbc05b842015-12-14 16:22:33 +0200264 return FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000265 }
266
267 // --------------------------------------------------------------------
268
269 /**
270 * Execute the query
271 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200272 * @param string $sql an SQL query
Andrey Andreevaa786c92012-01-16 12:14:45 +0200273 * @return resource
Derek Allard2067d1a2008-11-13 22:59:24 +0000274 */
Andrey Andreevbc95e472011-10-20 09:44:48 +0300275 protected function _execute($sql)
Derek Allard2067d1a2008-11-13 22:59:24 +0000276 {
Andrey Andreev24abcb92012-01-05 20:40:15 +0200277 /* Oracle must parse the query before it is run. All of the actions with
278 * the query are based on the statement id returned by oci_parse().
279 */
Andrey Andreev611e1fd2015-07-17 12:24:29 +0300280 if ($this->_reset_stmt_id === TRUE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000281 {
Timothy Warrend2ff0bc2012-03-19 16:52:10 -0400282 $this->stmt_id = oci_parse($this->conn_id, $sql);
Derek Allard2067d1a2008-11-13 22:59:24 +0000283 }
Andrey Andreev611e1fd2015-07-17 12:24:29 +0300284
285 oci_set_prefetch($this->stmt_id, 1000);
286 return oci_execute($this->stmt_id, $this->commit_mode);
Derek Allard2067d1a2008-11-13 22:59:24 +0000287 }
288
289 // --------------------------------------------------------------------
290
291 /**
Andrey Andreevda123732012-03-20 22:27:40 +0200292 * Get cursor. Returns a cursor from the database
Derek Allard2067d1a2008-11-13 22:59:24 +0000293 *
Andrey Andreevd5809992012-06-28 14:06:54 +0300294 * @return resource
Derek Allard2067d1a2008-11-13 22:59:24 +0000295 */
Andrey Andreev5c3a2022011-10-07 21:04:58 +0300296 public function get_cursor()
Derek Allard2067d1a2008-11-13 22:59:24 +0000297 {
Andrey Andreevaa786c92012-01-16 12:14:45 +0200298 return $this->curs_id = oci_new_cursor($this->conn_id);
Derek Allard2067d1a2008-11-13 22:59:24 +0000299 }
300
301 // --------------------------------------------------------------------
302
303 /**
Derek Jones4b9c6292011-07-01 17:40:48 -0500304 * Stored Procedure. Executes a stored procedure
Derek Allard2067d1a2008-11-13 22:59:24 +0000305 *
Andrey Andreevaa786c92012-01-16 12:14:45 +0200306 * @param string package name in which the stored procedure is in
307 * @param string stored procedure name to execute
308 * @param array parameters
309 * @return mixed
Derek Allard2067d1a2008-11-13 22:59:24 +0000310 *
311 * params array keys
312 *
Andrey Andreev10fb7d12015-08-03 10:05:29 +0300313 * KEY OPTIONAL NOTES
314 * name no the name of the parameter should be in :<param_name> format
315 * value no the value of the parameter. If this is an OUT or IN OUT parameter,
316 * this should be a reference to a variable
317 * type yes the type of the parameter
318 * length yes the max size of the parameter
Derek Allard2067d1a2008-11-13 22:59:24 +0000319 */
Andrey Andreev611e1fd2015-07-17 12:24:29 +0300320 public function stored_procedure($package, $procedure, array $params)
Derek Allard2067d1a2008-11-13 22:59:24 +0000321 {
Andrey Andreev611e1fd2015-07-17 12:24:29 +0300322 if ($package === '' OR $procedure === '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000323 {
Andrey Andreeve18de502013-07-17 19:59:20 +0300324 log_message('error', 'Invalid query: '.$package.'.'.$procedure);
325 return ($this->db_debug) ? $this->display_error('db_invalid_query') : FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000326 }
Barry Mienydd671972010-10-04 16:33:58 +0200327
Andrey Andreev611e1fd2015-07-17 12:24:29 +0300328 // Build the query string
Andrey Andreeve35d7782012-01-19 15:56:20 +0200329 $sql = 'BEGIN '.$package.'.'.$procedure.'(';
Derek Allard2067d1a2008-11-13 22:59:24 +0000330
331 $have_cursor = FALSE;
Pascal Krietec3a4a8d2011-02-14 13:40:08 -0500332 foreach ($params as $param)
Derek Allard2067d1a2008-11-13 22:59:24 +0000333 {
Andrey Andreevaa786c92012-01-16 12:14:45 +0200334 $sql .= $param['name'].',';
Barry Mienydd671972010-10-04 16:33:58 +0200335
Andrey Andreev85facfa2012-01-26 14:12:14 +0200336 if (isset($param['type']) && $param['type'] === OCI_B_CURSOR)
Derek Allard2067d1a2008-11-13 22:59:24 +0000337 {
338 $have_cursor = TRUE;
339 }
340 }
Andrey Andreev3ca060a2013-11-27 16:30:31 +0200341 $sql = trim($sql, ',').'); END;';
Barry Mienydd671972010-10-04 16:33:58 +0200342
Andrey Andreev611e1fd2015-07-17 12:24:29 +0300343 $this->_reset_stmt_id = FALSE;
344 $this->stmt_id = oci_parse($this->conn_id, $sql);
Derek Allard2067d1a2008-11-13 22:59:24 +0000345 $this->_bind_params($params);
Andrey Andreev611e1fd2015-07-17 12:24:29 +0300346 $result = $this->query($sql, FALSE, $have_cursor);
347 $this->_reset_stmt_id = TRUE;
348 return $result;
Derek Allard2067d1a2008-11-13 22:59:24 +0000349 }
Barry Mienydd671972010-10-04 16:33:58 +0200350
Derek Allard2067d1a2008-11-13 22:59:24 +0000351 // --------------------------------------------------------------------
352
353 /**
354 * Bind parameters
355 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200356 * @param array $params
Andrey Andreevaa786c92012-01-16 12:14:45 +0200357 * @return void
Derek Allard2067d1a2008-11-13 22:59:24 +0000358 */
Andrey Andreev1b5a8562012-03-13 13:13:43 +0200359 protected function _bind_params($params)
Derek Allard2067d1a2008-11-13 22:59:24 +0000360 {
361 if ( ! is_array($params) OR ! is_resource($this->stmt_id))
362 {
363 return;
364 }
Barry Mienydd671972010-10-04 16:33:58 +0200365
Derek Allard2067d1a2008-11-13 22:59:24 +0000366 foreach ($params as $param)
367 {
Barry Mienydd671972010-10-04 16:33:58 +0200368 foreach (array('name', 'value', 'type', 'length') as $val)
Derek Allard2067d1a2008-11-13 22:59:24 +0000369 {
370 if ( ! isset($param[$val]))
371 {
372 $param[$val] = '';
373 }
374 }
375
Andrey Andreev5c3a2022011-10-07 21:04:58 +0300376 oci_bind_by_name($this->stmt_id, $param['name'], $param['value'], $param['length'], $param['type']);
Derek Allard2067d1a2008-11-13 22:59:24 +0000377 }
378 }
379
380 // --------------------------------------------------------------------
381
382 /**
383 * Begin Transaction
384 *
Barry Mienydd671972010-10-04 16:33:58 +0200385 * @return bool
386 */
Andrey Andreeva7d4aba2015-10-19 14:39:44 +0300387 protected function _trans_begin()
Derek Allard2067d1a2008-11-13 22:59:24 +0000388 {
Andrey Andreeva8382792016-07-28 16:40:12 +0300389 $this->commit_mode = OCI_NO_AUTO_COMMIT;
Derek Allard2067d1a2008-11-13 22:59:24 +0000390 return TRUE;
391 }
392
393 // --------------------------------------------------------------------
394
395 /**
396 * Commit Transaction
397 *
Barry Mienydd671972010-10-04 16:33:58 +0200398 * @return bool
399 */
Andrey Andreeva7d4aba2015-10-19 14:39:44 +0300400 protected function _trans_commit()
Derek Allard2067d1a2008-11-13 22:59:24 +0000401 {
Andrey Andreev99013ed2012-03-05 16:17:32 +0200402 $this->commit_mode = OCI_COMMIT_ON_SUCCESS;
Andrey Andreeva7d4aba2015-10-19 14:39:44 +0300403
Andrey Andreev24abcb92012-01-05 20:40:15 +0200404 return oci_commit($this->conn_id);
Derek Allard2067d1a2008-11-13 22:59:24 +0000405 }
406
407 // --------------------------------------------------------------------
408
409 /**
410 * Rollback Transaction
411 *
Barry Mienydd671972010-10-04 16:33:58 +0200412 * @return bool
413 */
Andrey Andreeva7d4aba2015-10-19 14:39:44 +0300414 protected function _trans_rollback()
Derek Allard2067d1a2008-11-13 22:59:24 +0000415 {
Andrey Andreev99013ed2012-03-05 16:17:32 +0200416 $this->commit_mode = OCI_COMMIT_ON_SUCCESS;
Andrey Andreev24abcb92012-01-05 20:40:15 +0200417 return oci_rollback($this->conn_id);
Derek Allard2067d1a2008-11-13 22:59:24 +0000418 }
419
420 // --------------------------------------------------------------------
421
422 /**
Derek Allard2067d1a2008-11-13 22:59:24 +0000423 * Affected Rows
424 *
Andrey Andreevaa786c92012-01-16 12:14:45 +0200425 * @return int
Derek Allard2067d1a2008-11-13 22:59:24 +0000426 */
Andrey Andreev5c3a2022011-10-07 21:04:58 +0300427 public function affected_rows()
Derek Allard2067d1a2008-11-13 22:59:24 +0000428 {
Andrey Andreev2bbbd1a2014-05-09 10:24:14 +0300429 return oci_num_rows($this->stmt_id);
Derek Allard2067d1a2008-11-13 22:59:24 +0000430 }
431
432 // --------------------------------------------------------------------
433
434 /**
435 * Insert ID
436 *
Andrey Andreevaa786c92012-01-16 12:14:45 +0200437 * @return int
Derek Allard2067d1a2008-11-13 22:59:24 +0000438 */
Andrey Andreev5c3a2022011-10-07 21:04:58 +0300439 public function insert_id()
Derek Allard2067d1a2008-11-13 22:59:24 +0000440 {
441 // not supported in oracle
Derek Allardfac8fbc2010-02-05 16:14:49 +0000442 return $this->display_error('db_unsupported_function');
Derek Allard2067d1a2008-11-13 22:59:24 +0000443 }
444
445 // --------------------------------------------------------------------
446
447 /**
Derek Allard2067d1a2008-11-13 22:59:24 +0000448 * Show table query
449 *
450 * Generates a platform-specific query string so that the table names can be fetched
451 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200452 * @param bool $prefix_limit
Andrey Andreev5c3a2022011-10-07 21:04:58 +0300453 * @return string
Derek Allard2067d1a2008-11-13 22:59:24 +0000454 */
Andrey Andreevbc95e472011-10-20 09:44:48 +0300455 protected function _list_tables($prefix_limit = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000456 {
Andrey Andreevd3f13672012-06-24 22:13:21 +0300457 $sql = 'SELECT "TABLE_NAME" FROM "ALL_TABLES"';
Derek Allard2067d1a2008-11-13 22:59:24 +0000458
Alex Bilbie48a2baf2012-06-02 11:09:54 +0100459 if ($prefix_limit !== FALSE && $this->dbprefix !== '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000460 {
Andrey Andreevd3f13672012-06-24 22:13:21 +0300461 return $sql.' WHERE "TABLE_NAME" LIKE \''.$this->escape_like_str($this->dbprefix)."%' "
462 .sprintf($this->_like_escape_str, $this->_like_escape_chr);
Derek Allard2067d1a2008-11-13 22:59:24 +0000463 }
Barry Mienydd671972010-10-04 16:33:58 +0200464
Derek Allard2067d1a2008-11-13 22:59:24 +0000465 return $sql;
466 }
467
468 // --------------------------------------------------------------------
469
470 /**
471 * Show column query
472 *
473 * Generates a platform-specific query string so that the column names can be fetched
474 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200475 * @param string $table
Andrey Andreevaa786c92012-01-16 12:14:45 +0200476 * @return string
Derek Allard2067d1a2008-11-13 22:59:24 +0000477 */
Andrey Andreevbc95e472011-10-20 09:44:48 +0300478 protected function _list_columns($table = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000479 {
Andrey Andreeve1580572012-11-16 16:17:54 +0200480 if (strpos($table, '.') !== FALSE)
481 {
482 sscanf($table, '%[^.].%s', $owner, $table);
483 }
484 else
485 {
486 $owner = $this->username;
487 }
488
489 return 'SELECT COLUMN_NAME FROM ALL_TAB_COLUMNS
490 WHERE UPPER(OWNER) = '.$this->escape(strtoupper($owner)).'
491 AND UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
Derek Allard2067d1a2008-11-13 22:59:24 +0000492 }
493
494 // --------------------------------------------------------------------
495
496 /**
Andrey Andreeve1580572012-11-16 16:17:54 +0200497 * Returns an object with field data
Derek Allard2067d1a2008-11-13 22:59:24 +0000498 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200499 * @param string $table
Andrey Andreeve1580572012-11-16 16:17:54 +0200500 * @return array
Derek Allard2067d1a2008-11-13 22:59:24 +0000501 */
Andrey Andreev5350f052015-01-12 12:33:37 +0200502 public function field_data($table)
Derek Allard2067d1a2008-11-13 22:59:24 +0000503 {
Andrey Andreev5350f052015-01-12 12:33:37 +0200504 if (strpos($table, '.') !== FALSE)
Andrey Andreeve1580572012-11-16 16:17:54 +0200505 {
506 sscanf($table, '%[^.].%s', $owner, $table);
507 }
508 else
509 {
510 $owner = $this->username;
511 }
512
513 $sql = 'SELECT COLUMN_NAME, DATA_TYPE, CHAR_LENGTH, DATA_PRECISION, DATA_LENGTH, DATA_DEFAULT, NULLABLE
514 FROM ALL_TAB_COLUMNS
515 WHERE UPPER(OWNER) = '.$this->escape(strtoupper($owner)).'
516 AND UPPER(TABLE_NAME) = '.$this->escape(strtoupper($table));
517
518 if (($query = $this->query($sql)) === FALSE)
519 {
520 return FALSE;
521 }
522 $query = $query->result_object();
523
524 $retval = array();
525 for ($i = 0, $c = count($query); $i < $c; $i++)
526 {
527 $retval[$i] = new stdClass();
528 $retval[$i]->name = $query[$i]->COLUMN_NAME;
529 $retval[$i]->type = $query[$i]->DATA_TYPE;
530
531 $length = ($query[$i]->CHAR_LENGTH > 0)
532 ? $query[$i]->CHAR_LENGTH : $query[$i]->DATA_PRECISION;
533 if ($length === NULL)
534 {
535 $length = $query[$i]->DATA_LENGTH;
536 }
537 $retval[$i]->max_length = $length;
538
539 $default = $query[$i]->DATA_DEFAULT;
540 if ($default === NULL && $query[$i]->NULLABLE === 'N')
541 {
542 $default = '';
543 }
Leandro Mangini Antunes4c08ea92015-05-13 11:15:01 -0300544 $retval[$i]->default = $default;
Andrey Andreeve1580572012-11-16 16:17:54 +0200545 }
546
547 return $retval;
Derek Allard2067d1a2008-11-13 22:59:24 +0000548 }
549
550 // --------------------------------------------------------------------
551
552 /**
Andrey Andreev4be5de12012-03-02 15:45:41 +0200553 * Error
Derek Allard2067d1a2008-11-13 22:59:24 +0000554 *
Andrey Andreev4be5de12012-03-02 15:45:41 +0200555 * Returns an array containing code and message of the last
Andrey Andreev71d8f722017-01-17 12:01:00 +0200556 * database error that has occurred.
Derek Allard2067d1a2008-11-13 22:59:24 +0000557 *
Andrey Andreev601f8b22012-03-01 20:11:15 +0200558 * @return array
Derek Allard2067d1a2008-11-13 22:59:24 +0000559 */
Andrey Andreev4be5de12012-03-02 15:45:41 +0200560 public function error()
Derek Allard2067d1a2008-11-13 22:59:24 +0000561 {
Andrey Andreev45520a52016-05-19 18:51:25 +0300562 // oci_error() returns an array that already contains
563 // 'code' and 'message' keys, but it can return false
564 // if there was no error ....
Andrey Andreev601f8b22012-03-01 20:11:15 +0200565 if (is_resource($this->curs_id))
566 {
Andrey Andreev45520a52016-05-19 18:51:25 +0300567 $error = oci_error($this->curs_id);
Andrey Andreev601f8b22012-03-01 20:11:15 +0200568 }
569 elseif (is_resource($this->stmt_id))
570 {
Andrey Andreev45520a52016-05-19 18:51:25 +0300571 $error = oci_error($this->stmt_id);
Andrey Andreev601f8b22012-03-01 20:11:15 +0200572 }
573 elseif (is_resource($this->conn_id))
574 {
Andrey Andreev45520a52016-05-19 18:51:25 +0300575 $error = oci_error($this->conn_id);
576 }
577 else
578 {
579 $error = oci_error();
Andrey Andreev601f8b22012-03-01 20:11:15 +0200580 }
581
Andrey Andreev45520a52016-05-19 18:51:25 +0300582 return is_array($error)
583 ? $error
Andrey Andreevad20f712016-05-25 09:58:03 +0300584 : array('code' => '', 'message' => '');
Derek Allard2067d1a2008-11-13 22:59:24 +0000585 }
Barry Mienydd671972010-10-04 16:33:58 +0200586
Derek Allard2067d1a2008-11-13 22:59:24 +0000587 // --------------------------------------------------------------------
588
589 /**
Andrey Andreev083e3c82012-11-06 12:48:32 +0200590 * Insert batch statement
Andrey Andreev99c6dd42011-09-23 03:07:01 +0300591 *
592 * Generates a platform-specific insert string from the supplied data
593 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200594 * @param string $table Table name
595 * @param array $keys INSERT keys
596 * @param array $values INSERT values
Andrey Andreevda123732012-03-20 22:27:40 +0200597 * @return string
Andrey Andreev99c6dd42011-09-23 03:07:01 +0300598 */
Andrey Andreevbc95e472011-10-20 09:44:48 +0300599 protected function _insert_batch($table, $keys, $values)
Andrey Andreev99c6dd42011-09-23 03:07:01 +0300600 {
601 $keys = implode(', ', $keys);
602 $sql = "INSERT ALL\n";
603
604 for ($i = 0, $c = count($values); $i < $c; $i++)
Andrey Andreevb83c4082011-09-23 03:32:45 +0300605 {
Andrey Andreev97f36972012-04-05 12:44:36 +0300606 $sql .= ' INTO '.$table.' ('.$keys.') VALUES '.$values[$i]."\n";
Andrey Andreevb83c4082011-09-23 03:32:45 +0300607 }
Andrey Andreev99c6dd42011-09-23 03:07:01 +0300608
Andrey Andreevaa786c92012-01-16 12:14:45 +0200609 return $sql.'SELECT * FROM dual';
Derek Allard2067d1a2008-11-13 22:59:24 +0000610 }
611
612 // --------------------------------------------------------------------
613
614 /**
615 * Truncate statement
616 *
617 * Generates a platform-specific truncate string from the supplied data
Derek Allard2067d1a2008-11-13 22:59:24 +0000618 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200619 * If the database does not support the TRUNCATE statement,
Andrey Andreeva6fe36e2012-04-05 16:00:32 +0300620 * then this method maps to 'DELETE FROM table'
Derek Allard2067d1a2008-11-13 22:59:24 +0000621 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200622 * @param string $table
Derek Allard2067d1a2008-11-13 22:59:24 +0000623 * @return string
Barry Mienydd671972010-10-04 16:33:58 +0200624 */
Andrey Andreevbc95e472011-10-20 09:44:48 +0300625 protected function _truncate($table)
Derek Allard2067d1a2008-11-13 22:59:24 +0000626 {
Andrey Andreevaa786c92012-01-16 12:14:45 +0200627 return 'TRUNCATE TABLE '.$table;
Derek Allard2067d1a2008-11-13 22:59:24 +0000628 }
Barry Mienydd671972010-10-04 16:33:58 +0200629
Derek Allard2067d1a2008-11-13 22:59:24 +0000630 // --------------------------------------------------------------------
631
632 /**
633 * Delete statement
634 *
635 * Generates a platform-specific delete string from the supplied data
636 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200637 * @param string $table
Derek Allard2067d1a2008-11-13 22:59:24 +0000638 * @return string
Barry Mienydd671972010-10-04 16:33:58 +0200639 */
Andrey Andreevb0478652012-07-18 15:34:46 +0300640 protected function _delete($table)
Derek Allard2067d1a2008-11-13 22:59:24 +0000641 {
Andrey Andreevb0478652012-07-18 15:34:46 +0300642 if ($this->qb_limit)
643 {
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300644 $this->where('rownum <= ',$this->qb_limit, FALSE);
Andrey Andreevb0478652012-07-18 15:34:46 +0300645 $this->qb_limit = FALSE;
646 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000647
Andrey Andreevb0478652012-07-18 15:34:46 +0300648 return parent::_delete($table);
Derek Allard2067d1a2008-11-13 22:59:24 +0000649 }
650
651 // --------------------------------------------------------------------
652
653 /**
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200654 * LIMIT
Derek Allard2067d1a2008-11-13 22:59:24 +0000655 *
656 * Generates a platform-specific LIMIT clause
657 *
Andrey Andreeva24e52e2012-11-02 03:54:12 +0200658 * @param string $sql SQL Query
Andrey Andreevaa786c92012-01-16 12:14:45 +0200659 * @return string
Derek Allard2067d1a2008-11-13 22:59:24 +0000660 */
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300661 protected function _limit($sql)
Derek Allard2067d1a2008-11-13 22:59:24 +0000662 {
Andrey Andreeve8de9eb2016-01-06 15:53:19 +0200663 if (version_compare($this->version(), '12.1', '>='))
664 {
665 // OFFSET-FETCH can be used only with the ORDER BY clause
666 empty($this->qb_orderby) && $sql .= ' ORDER BY 1';
667
668 return $sql.' OFFSET '.(int) $this->qb_offset.' ROWS FETCH NEXT '.$this->qb_limit.' ROWS ONLY';
669 }
670
Derek Allard2067d1a2008-11-13 22:59:24 +0000671 $this->limit_used = TRUE;
Andrey Andreevc9b924c2012-07-19 13:06:02 +0300672 return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($this->qb_offset + $this->qb_limit + 1).')'
Andrey Andreev1a61ba42014-03-24 16:53:16 +0200673 .($this->qb_offset ? ' WHERE rnum >= '.($this->qb_offset + 1) : '');
Barry Mienydd671972010-10-04 16:33:58 +0200674 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000675
676 // --------------------------------------------------------------------
677
678 /**
679 * Close DB Connection
680 *
Andrey Andreevaa786c92012-01-16 12:14:45 +0200681 * @return void
Derek Allard2067d1a2008-11-13 22:59:24 +0000682 */
Andrey Andreev79922c02012-05-23 12:27:17 +0300683 protected function _close()
Derek Allard2067d1a2008-11-13 22:59:24 +0000684 {
Andrey Andreev2bbbd1a2014-05-09 10:24:14 +0300685 oci_close($this->conn_id);
Derek Allard2067d1a2008-11-13 22:59:24 +0000686 }
687
Andrey Andreev6efd42e2018-03-15 16:24:42 +0200688 // --------------------------------------------------------------------
689
690 /**
691 * We need to reset our $limit_used hack flag, so it doesn't propagate
692 * to subsequent queries.
693 *
694 * @return void
695 */
696 protected function _reset_select()
697 {
698 $this->limit_used = FALSE;
699 parent::_reset_select();
700 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000701}