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