blob: c4ab70051afc90fd19b13e9ab76853c23b85f758 [file] [log] [blame]
Derek Allardd2df9bc2007-04-15 17:41:17 +00001<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
2/**
3 * CodeIgniter
4 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
8 * @author Rick Ellis
9 * @copyright Copyright (c) 2006, EllisLab, Inc.
Derek Allard6838f002007-10-04 19:29:59 +000010 * @license http://www.codeigniter.com/user_guide/license.html
Derek Allardd2df9bc2007-04-15 17:41:17 +000011 * @link http://www.codeigniter.com
12 * @since Version 1.0
13 * @filesource
14 */
15
16// ------------------------------------------------------------------------
17
18/**
19 * oci8 Database Adapter Class
20 *
21 * Note: _DB is an extender class that the app controller
22 * creates dynamically based on whether the active record
23 * class is being used or not.
24 *
25 * @package CodeIgniter
26 * @subpackage Drivers
27 * @category Database
28 * @author Rick Ellis
29 * @link http://www.codeigniter.com/user_guide/database/
30 */
31
32/**
33 * oci8 Database Adapter Class
34 *
35 * This is a modification of the DB_driver class to
36 * permit access to oracle databases
37 *
38 * NOTE: this uses the PHP 4 oci methods
39 *
40 * @author Kelly McArdle
41 *
42 */
43
44class CI_DB_oci8_driver extends CI_DB {
45
Derek Allard694b5b82007-12-18 15:58:03 +000046 /**
47 * The syntax to count rows is slightly different across different
48 * database engines, so this string appears in each driver and is
49 * used for the count_all() and count_all_results() functions.
50 */
Derek Allard6ddb5a12007-12-18 17:22:50 +000051 var $_count_string = "SELECT COUNT(1) AS numrows ";
Derek Allard694b5b82007-12-18 15:58:03 +000052
Derek Allardd2df9bc2007-04-15 17:41:17 +000053 // Set "auto commit" by default
54 var $_commit = OCI_COMMIT_ON_SUCCESS;
55
56 // need to track statement id and cursor id
57 var $stmt_id;
58 var $curs_id;
59
60 // if we use a limit, we will add a field that will
61 // throw off num_fields later
62 var $limit_used;
63
64 /**
65 * Non-persistent database connection
66 *
67 * @access private called by the base class
68 * @return resource
69 */
70 function db_connect()
71 {
72 return @ocilogon($this->username, $this->password, $this->hostname);
73 }
74
75 // --------------------------------------------------------------------
76
77 /**
78 * Persistent database connection
79 *
80 * @access private called by the base class
81 * @return resource
82 */
83 function db_pconnect()
84 {
85 return @ociplogon($this->username, $this->password, $this->hostname);
86 }
87
88 // --------------------------------------------------------------------
89
90 /**
91 * Select the database
92 *
93 * @access private called by the base class
94 * @return resource
95 */
96 function db_select()
97 {
98 return TRUE;
99 }
100
101 // --------------------------------------------------------------------
102
103 /**
104 * Version number query string
105 *
106 * @access public
107 * @return string
108 */
109 function _version()
110 {
111 return ociserverversion($this->conn_id);
112 }
113
114 // --------------------------------------------------------------------
115
116 /**
117 * Execute the query
118 *
119 * @access private called by the base class
120 * @param string an SQL query
121 * @return resource
122 */
123 function _execute($sql)
124 {
125 // oracle must parse the query before it is run. All of the actions with
126 // the query are based on the statement id returned by ociparse
127 $this->_set_stmt_id($sql);
128 ocisetprefetch($this->stmt_id, 1000);
129 return @ociexecute($this->stmt_id, $this->_commit);
130 }
131
132 /**
133 * Generate a statement ID
134 *
135 * @access private
136 * @param string an SQL query
137 * @return none
138 */
139 function _set_stmt_id($sql)
140 {
141 if ( ! is_resource($this->stmt_id))
142 {
143 $this->stmt_id = ociparse($this->conn_id, $this->_prep_query($sql));
144 }
145 }
146
147 // --------------------------------------------------------------------
148
149 /**
150 * Prep the query
151 *
152 * If needed, each database adapter can prep the query string
153 *
154 * @access private called by execute()
155 * @param string an SQL query
156 * @return string
157 */
158 function _prep_query($sql)
159 {
160 return $sql;
161 }
162
163 // --------------------------------------------------------------------
164
165 /**
166 * getCursor. Returns a cursor from the datbase
167 *
168 * @access public
169 * @return cursor id
170 */
171 function get_cursor()
172 {
173 $this->curs_id = ocinewcursor($this->conn_id);
174 return $this->curs_id;
175 }
176
177 // --------------------------------------------------------------------
178
179 /**
180 * Stored Procedure. Executes a stored procedure
181 *
182 * @access public
183 * @param package package stored procedure is in
184 * @param procedure stored procedure to execute
185 * @param params array of parameters
186 * @return array
187 *
188 * params array keys
189 *
190 * KEY OPTIONAL NOTES
191 * name no the name of the parameter should be in :<param_name> format
192 * value no the value of the parameter. If this is an OUT or IN OUT parameter,
193 * this should be a reference to a variable
194 * type yes the type of the parameter
195 * length yes the max size of the parameter
196 */
197 function stored_procedure($package, $procedure, $params)
198 {
199 if ($package == '' OR $procedure == '' OR ! is_array($params))
200 {
201 if ($this->db_debug)
202 {
203 log_message('error', 'Invalid query: '.$package.'.'.$procedure);
204 return $this->display_error('db_invalid_query');
205 }
206 return FALSE;
207 }
208
209 // build the query string
210 $sql = "begin $package.$procedure(";
211
212 $have_cursor = FALSE;
213 foreach($params as $param)
214 {
215 $sql .= $param['name'] . ",";
216
217 if (array_key_exists('type', $param) && ($param['type'] == OCI_B_CURSOR))
218 {
219 $have_cursor = TRUE;
220 }
221 }
222 $sql = trim($sql, ",") . "); end;";
223
224 $this->stmt_id = FALSE;
225 $this->_set_stmt_id($sql);
226 $this->_bind_params($params);
227 $this->query($sql, FALSE, $have_cursor);
228 }
229
230 // --------------------------------------------------------------------
231
232 /**
233 * Bind parameters
234 *
235 * @access private
236 * @return none
237 */
238 function _bind_params($params)
239 {
240 if ( ! is_array($params) OR ! is_resource($this->stmt_id))
241 {
242 return;
243 }
244
245 foreach ($params as $param)
246 {
247 foreach (array('name', 'value', 'type', 'length') as $val)
248 {
249 if ( ! isset($param[$val]))
250 {
251 $param[$val] = '';
252 }
253 }
254
255 ocibindbyname($this->stmt_id, $param['name'], $param['value'], $param['length'], $param['type']);
256 }
257 }
258
259 // --------------------------------------------------------------------
260
261 /**
262 * Begin Transaction
263 *
264 * @access public
265 * @return bool
266 */
267 function trans_begin($test_mode = FALSE)
268 {
269 if ( ! $this->trans_enabled)
270 {
271 return TRUE;
272 }
273
274 // When transactions are nested we only begin/commit/rollback the outermost ones
275 if ($this->_trans_depth > 0)
276 {
277 return TRUE;
278 }
279
280 // Reset the transaction failure flag.
281 // If the $test_mode flag is set to TRUE transactions will be rolled back
282 // even if the queries produce a successful result.
283 $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
284
285 $this->_commit = OCI_DEFAULT;
286 return TRUE;
287 }
288
289 // --------------------------------------------------------------------
290
291 /**
292 * Commit Transaction
293 *
294 * @access public
295 * @return bool
296 */
297 function trans_commit()
298 {
299 if ( ! $this->trans_enabled)
300 {
301 return TRUE;
302 }
303
304 // When transactions are nested we only begin/commit/rollback the outermost ones
305 if ($this->_trans_depth > 0)
306 {
307 return TRUE;
308 }
309
310 $ret = OCIcommit($this->conn_id);
311 $this->_commit = OCI_COMMIT_ON_SUCCESS;
312 return $ret;
313 }
314
315 // --------------------------------------------------------------------
316
317 /**
318 * Rollback Transaction
319 *
320 * @access public
321 * @return bool
322 */
323 function trans_rollback()
324 {
325 if ( ! $this->trans_enabled)
326 {
327 return TRUE;
328 }
329
330 // When transactions are nested we only begin/commit/rollback the outermost ones
331 if ($this->_trans_depth > 0)
332 {
333 return TRUE;
334 }
335
336 $ret = OCIrollback($this->conn_id);
337 $this->_commit = OCI_COMMIT_ON_SUCCESS;
338 return $ret;
339 }
340
341 // --------------------------------------------------------------------
342
343 /**
344 * Escape String
345 *
346 * @access public
347 * @param string
348 * @return string
349 */
350 function escape_str($str)
351 {
352 return $str;
353 }
354
355 // --------------------------------------------------------------------
356
357 /**
358 * Affected Rows
359 *
360 * @access public
361 * @return integer
362 */
363 function affected_rows()
364 {
365 return @ocirowcount($this->stmt_id);
366 }
367
368 // --------------------------------------------------------------------
369
370 /**
371 * Insert ID
372 *
373 * @access public
374 * @return integer
375 */
376 function insert_id()
377 {
378 // not supported in oracle
379 return 0;
380 }
381
382 // --------------------------------------------------------------------
383
384 /**
385 * "Count All" query
386 *
387 * Generates a platform-specific query string that counts all records in
388 * the specified database
389 *
390 * @access public
391 * @param string
392 * @return string
393 */
394 function count_all($table = '')
395 {
396 if ($table == '')
397 return '0';
398
Derek Allard6ddb5a12007-12-18 17:22:50 +0000399 $query = $this->query($this->_count_string . "FROM ".$table);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000400
401 if ($query == FALSE)
402 {
403 return 0;
404 }
405
406 $row = $query->row();
407 return $row->NUMROWS;
408 }
409
410 // --------------------------------------------------------------------
411
412 /**
413 * Show table query
414 *
415 * Generates a platform-specific query string so that the table names can be fetched
416 *
417 * @access private
418 * @return string
419 */
420 function _list_tables()
421 {
422 return "SELECT TABLE_NAME FROM ALL_TABLES";
423 }
424
425 // --------------------------------------------------------------------
426
427 /**
428 * Show column query
429 *
430 * Generates a platform-specific query string so that the column names can be fetched
431 *
432 * @access public
433 * @param string the table name
434 * @return string
435 */
436 function _list_columns($table = '')
437 {
438 return "SELECT COLUMN_NAME FROM all_tab_columns WHERE table_name = '$table'";
439 }
440
441 // --------------------------------------------------------------------
442
443 /**
444 * Field data query
445 *
446 * Generates a platform-specific query so that the column data can be retrieved
447 *
448 * @access public
449 * @param string the table name
450 * @return object
451 */
452 function _field_data($table)
453 {
454 return "SELECT * FROM ".$this->_escape_table($table)." where rownum = 1";
455 }
456
457 // --------------------------------------------------------------------
458
459 /**
460 * The error message string
461 *
462 * @access private
463 * @return string
464 */
465 function _error_message()
466 {
467 $error = ocierror($this->conn_id);
468 return $error['message'];
469 }
470
471 // --------------------------------------------------------------------
472
473 /**
474 * The error message number
475 *
476 * @access private
477 * @return integer
478 */
479 function _error_number()
480 {
481 $error = ocierror($this->conn_id);
482 return $error['code'];
483 }
484
485 // --------------------------------------------------------------------
486
487 /**
488 * Escape Table Name
489 *
490 * This function adds backticks if the table name has a period
491 * in it. Some DBs will get cranky unless periods are escaped
492 *
493 * @access private
494 * @param string the table name
495 * @return string
496 */
497 function _escape_table($table)
498 {
499 if (stristr($table, '.'))
500 {
501 $table = preg_replace("/\./", "`.`", $table);
502 }
503
504 return $table;
505 }
506
507 // --------------------------------------------------------------------
508
509 /**
510 * Insert statement
511 *
512 * Generates a platform-specific insert string from the supplied data
513 *
514 * @access public
515 * @param string the table name
516 * @param array the insert keys
517 * @param array the insert values
518 * @return string
519 */
520 function _insert($table, $keys, $values)
521 {
522 return "INSERT INTO ".$this->_escape_table($table)." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
523 }
524
525 // --------------------------------------------------------------------
526
527 /**
528 * Update statement
529 *
530 * Generates a platform-specific update string from the supplied data
531 *
532 * @access public
533 * @param string the table name
534 * @param array the update data
535 * @param array the where clause
536 * @return string
537 */
Derek Allardda6d2402007-12-19 14:49:29 +0000538 function _update($table, $values, $where, $limit = FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000539 {
540 foreach($values as $key => $val)
541 {
542 $valstr[] = $key." = ".$val;
543 }
Derek Allardda6d2402007-12-19 14:49:29 +0000544
545 $limit = (!$limit) ? '' : ' LIMIT '.$limit;
546
547 return "UPDATE ".$this->_escape_table($table)." SET ".implode(', ', $valstr)." WHERE ".implode(" ", $where).$limit;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000548 }
549
550 // --------------------------------------------------------------------
551
552 /**
553 * Delete statement
554 *
555 * Generates a platform-specific delete string from the supplied data
556 *
557 * @access public
558 * @param string the table name
559 * @param array the where clause
560 * @return string
561 */
Derek Allarde77d77c2007-12-19 15:01:55 +0000562 function _delete($table, $where, $limit = FALSE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000563 {
Derek Allarde77d77c2007-12-19 15:01:55 +0000564 $limit = (!$limit) ? '' : ' LIMIT '.$limit;
565
566 return "DELETE FROM ".$this->_escape_table($table)." WHERE ".implode(" ", $where).$limit;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000567 }
568
569 // --------------------------------------------------------------------
570
571 /**
572 * Limit string
573 *
574 * Generates a platform-specific LIMIT clause
575 *
576 * @access public
577 * @param string the sql query string
578 * @param integer the number of rows to limit the query to
579 * @param integer the offset value
580 * @return string
581 */
582 function _limit($sql, $limit, $offset)
583 {
584 $limit = $offset + $limit;
585 $newsql = "SELECT * FROM (select inner_query.*, rownum rnum FROM ($sql) inner_query WHERE rownum < $limit)";
586
587 if ($offset != 0)
588 {
589 $newsql .= " WHERE rnum >= $offset";
590 }
591
592 // remember that we used limits
593 $this->limit_used = TRUE;
594
595 return $newsql;
596 }
597
598 // --------------------------------------------------------------------
599
600 /**
601 * Close DB Connection
602 *
603 * @access public
604 * @param resource
605 * @return void
606 */
607 function _close($conn_id)
608 {
609 @ocilogoff($conn_id);
610 }
611
612
613}
614
615
admin99e1b292006-09-24 18:12:43 +0000616?>