blob: 06426dcacee51a684a50c0254c5a5a2b78180979 [file] [log] [blame]
admin0fce0f22006-09-20 21:13:41 +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/libraries/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 extends CI_DB {
45
46 // need to track statement id and cursor id
47 var $stmt_id;
48 var $curs_id;
49
50 // if we use a limit, we will add a field that will
51 // throw off num_fields later
52 var $limit_used;
53
54 /**
55 * Non-persistent database connection
56 *
57 * @access private called by the base class
58 * @return resource
59 */
60 function db_connect()
61 {
62 return ocilogon($this->username, $this->password, $this->hostname);
63 }
64
65 // --------------------------------------------------------------------
66
67 /**
68 * Persistent database connection
69 *
70 * @access private called by the base class
71 * @return resource
72 */
73 function db_pconnect()
74 {
75 return ociplogon($this->username, $this->password, $this->hostname);
76 }
77
78 // --------------------------------------------------------------------
79
80 /**
81 * Select the database
82 *
83 * @access private called by the base class
84 * @return resource
85 */
86 function db_select()
87 {
88 return TRUE;
89 }
90
91 // --------------------------------------------------------------------
92
93 /**
94 * Execute the query
95 *
96 * @access private called by the base class
97 * @param string an SQL query
98 * @return resource
99 */
100 function execute($sql)
101 {
102 // oracle must parse the query before it
103 // is run, all of the actions with
104 // the query are based off the statement id
105 // returned by ociparse
106 $this->_set_stmt_id($sql);
107 ocisetprefetch($this->stmt_id, 1000);
108 return @ociexecute($this->stmt_id);
109 }
110
111 /**
112 * Generate a statement ID
113 *
114 * @access private
115 * @param string an SQL query
116 * @return none
117 */
118 function _set_stmt_id($sql)
119 {
120 if ( ! is_resource($this->stmt_id))
121 {
122 $this->stmt_id = ociparse($this->conn_id, $this->_prep_query($sql));
123 }
124 }
125
126 // --------------------------------------------------------------------
127
128 /**
129 * Prep the query
130 *
131 * If needed, each database adapter can prep the query string
132 *
133 * @access private called by execute()
134 * @param string an SQL query
135 * @return string
136 */
137 function _prep_query($sql)
138 {
139 return $sql;
140 }
141
142 // --------------------------------------------------------------------
143
144 /**
145 * getCursor. Returns a cursor from the datbase
146 *
147 * @access public
148 * @return cursor id
149 */
150 function get_cursor()
151 {
152 return $this->curs_id = ocinewcursor($this->conn_id);
153 }
154
155 // --------------------------------------------------------------------
156
157 /**
158 * Stored Procedure. Executes a stored procedure
159 *
160 * @access public
161 * @param package package stored procedure is in
162 * @param procedure stored procedure to execute
163 * @param params array of parameters
164 * @return array
165 *
166 * params array keys
167 *
168 * KEY OPTIONAL NOTES
169 * name no the name of the parameter should be in :<param_name> format
170 * value no the value of the parameter. If this is an OUT or IN OUT parameter,
171 * this should be a reference to a variable
172 * type yes the type of the parameter
173 * length yes the max size of the parameter
174 */
175 function stored_procedure($package, $procedure, $params)
176 {
177 if ($package == '' OR $procedure == '' OR ! is_array($params))
178 {
179 if ($this->db_debug)
180 {
181 log_message('error', 'Invalid query: '.$package.'.'.$procedure);
182 return $this->display_error('db_invalid_query');
183 }
184 return FALSE;
185 }
186
187 // build the query string
188 $sql = "begin $package.$procedure(";
189
190 $have_cursor = FALSE;
191 foreach($params as $param)
192 {
193 $sql .= $param['name'] . ",";
194
195 if (array_key_exists('type', $param) && ($param['type'] == OCI_B_CURSOR))
196 {
197 $have_cursor = TRUE;
198 }
199 }
200 $sql = trim($sql, ",") . "); end;";
201
202 $this->stmt_id = FALSE;
203 $this->_set_stmt_id($sql);
204 $this->_bind_params($params);
205 $this->query($sql, FALSE, $have_cursor);
206 }
207
208 // --------------------------------------------------------------------
209
210 /**
211 * Bind parameters
212 *
213 * @access private
214 * @return none
215 */
216 function _bind_params($params)
217 {
218 if ( ! is_array($params) OR ! is_resource($this->stmt_id))
219 {
220 return;
221 }
222
223 foreach ($params as $param)
224 {
225 foreach (array('name', 'value', 'type', 'length') as $val)
226 {
227 if ( ! isset($param[$val]))
228 {
229 $param[$val] = '';
230 }
231 }
232
233 ocibindbyname($this->stmt_id, $param['name'], $param['value'], $param['length'], $param['type']);
234 }
235 }
236
237 // --------------------------------------------------------------------
238
239 /**
240 * Escape String
241 *
242 * @access public
243 * @param string
244 * @return string
245 */
246 function escape_str($str)
247 {
248 return $str;
249 }
250
251 // --------------------------------------------------------------------
252
253 /**
254 * Close DB Connection
255 *
256 * @access public
257 * @param resource
258 * @return void
259 */
260 function destroy($conn_id)
261 {
262 ocilogoff($conn_id);
263 }
264
265 // --------------------------------------------------------------------
266
267 /**
268 * Affected Rows
269 *
270 * @access public
271 * @return integer
272 */
273 function affected_rows()
274 {
275 return @ocirowcount($this->stmt_id);
276 }
277
278 // --------------------------------------------------------------------
279
280 /**
281 * Insert ID
282 *
283 * @access public
284 * @return integer
285 */
286 function insert_id()
287 {
288 // not supported in oracle
289 return 0;
290 }
291
292 // --------------------------------------------------------------------
293
294 /**
295 * "Count All" query
296 *
297 * Generates a platform-specific query string that counts all records in
298 * the specified database
299 *
300 * @access public
301 * @param string
302 * @return string
303 */
304 function count_all($table = '')
305 {
306 if ($table == '')
307 return '0';
308
309 $query = $this->query("SELECT COUNT(1) AS numrows FROM ".$table);
310
311 if ($query == FALSE)
312 {
313 return 0;
314 }
315
316 $row = $query->row();
317 return $row->NUMROWS;
318 }
319
320 // --------------------------------------------------------------------
321
322 /**
323 * The error message string
324 *
325 * @access public
326 * @return string
327 */
328 function error_message()
329 {
330 $error = ocierror($this->conn_id);
331 return $error['message'];
332 }
333
334 // --------------------------------------------------------------------
335
336 /**
337 * The error message number
338 *
339 * @access public
340 * @return integer
341 */
342 function error_number()
343 {
344 $error = ocierror($this->conn_id);
345 return $error['code'];
346 }
347
348 // --------------------------------------------------------------------
349
350 /**
351 * Escape Table Name
352 *
353 * This function adds backticks if the table name has a period
354 * in it. Some DBs will get cranky unless periods are escaped
355 *
356 * @access public
357 * @param string the table name
358 * @return string
359 */
360 function escape_table($table)
361 {
362 if (stristr($table, '.'))
363 {
364 $table = preg_replace("/\./", "`.`", $table);
365 }
366
367 return $table;
368 }
369
370 // --------------------------------------------------------------------
371
372 /**
373 * Field data query
374 *
375 * Generates a platform-specific query so that the column data can be retrieved
376 *
377 * @access public
378 * @param string the table name
379 * @return object
380 */
381 function _field_data($table)
382 {
383 $sql = "SELECT * FROM ".$this->escape_table($table)." where rownum = 1";
384 $query = $this->query($sql);
385 return $query->field_data();
386 }
387
388 // --------------------------------------------------------------------
389
390 /**
391 * Insert statement
392 *
393 * Generates a platform-specific insert string from the supplied data
394 *
395 * @access public
396 * @param string the table name
397 * @param array the insert keys
398 * @param array the insert values
399 * @return string
400 */
401 function _insert($table, $keys, $values)
402 {
403 return "INSERT INTO ".$this->escape_table($table)." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
404 }
405
406 // --------------------------------------------------------------------
407
408 /**
409 * Update statement
410 *
411 * Generates a platform-specific update string from the supplied data
412 *
413 * @access public
414 * @param string the table name
415 * @param array the update data
416 * @param array the where clause
417 * @return string
418 */
419 function _update($table, $values, $where)
420 {
421 foreach($values as $key => $val)
422 {
423 $valstr[] = $key." = ".$val;
424 }
425
426 return "UPDATE ".$this->escape_table($table)." SET ".implode(', ', $valstr)." WHERE ".implode(" ", $where);
427 }
428
429 // --------------------------------------------------------------------
430
431 /**
432 * Delete statement
433 *
434 * Generates a platform-specific delete string from the supplied data
435 *
436 * @access public
437 * @param string the table name
438 * @param array the where clause
439 * @return string
440 */
441 function _delete($table, $where)
442 {
443 return "DELETE FROM ".$this->escape_table($table)." WHERE ".implode(" ", $where);
444 }
445
446 // --------------------------------------------------------------------
447
448 /**
449 * Version number query string
450 *
451 * @access public
452 * @return string
453 */
454 function _version()
455 {
456 $ver = ociserverversion($this->conn_id);
457 return $ver;
458 }
459
460 // --------------------------------------------------------------------
461
462 /**
463 * Show table query
464 *
465 * Generates a platform-specific query string so that the table names can be fetched
466 *
467 * @access public
468 * @return string
469 */
470 function _show_tables()
471 {
472 return "select TABLE_NAME FROM ALL_TABLES";
473 }
474
475 // --------------------------------------------------------------------
476
477 /**
478 * Show columnn query
479 *
480 * Generates a platform-specific query string so that the column names can be fetched
481 *
482 * @access public
483 * @param string the table name
484 * @return string
485 */
486 function _show_columns($table = '')
487 {
488 return "SELECT COLUMN_NAME FROM all_tab_columns WHERE table_name = '$table'";
489 }
490
491 // --------------------------------------------------------------------
492
493 /**
494 * Limit string
495 *
496 * Generates a platform-specific LIMIT clause
497 *
498 * @access public
499 * @param string the sql query string
500 * @param integer the number of rows to limit the query to
501 * @param integer the offset value
502 * @return string
503 */
504 function _limit($sql, $limit, $offset)
505 {
506 $limit = $offset + $limit;
507 $newsql = "SELECT * FROM (select inner_query.*, rownum rnum FROM ($sql) inner_query WHERE rownum < $limit)";
508
509 if ($offset != 0)
510 {
511 $newsql .= " WHERE rnum >= $offset";
512 }
513
514 // remember that we used limits
515 $this->limit_used = TRUE;
516
517 return $newsql;
518 }
519
520}
521
522
523/**
524 * oci8 Result Class
525 *
526 * This class extends the parent result class: CI_DB_result
527 *
528 * @category Database
529 * @author Rick Ellis
530 * @link http://www.codeigniter.com/user_guide/libraries/database/
531 */
532class CI_DB_oci8_result extends CI_DB_result {
533
534 var $stmt_id;
535 var $curs_id;
536 var $limit_used;
537
538 /**
539 * Number of rows in the result set
540 *
541 * @access public
542 * @return integer
543 */
544 function num_rows()
545 {
546 // get the results, count them,
547 // rerun query - otherwise we
548 // won't have data after calling
549 // num_rows()
550 $this->result_array();
551 $rowcount = count($this->result_array);
552 @ociexecute($this->stmt_id);
553 if ($this->curs_id)
554 {
555 @ociexecute($this->curs_id);
556 }
557 return $rowcount;
558 }
559
560 // --------------------------------------------------------------------
561
562 /**
563 * Number of fields in the result set
564 *
565 * @access public
566 * @return integer
567 */
568 function num_fields()
569 {
570 $count = @ocinumcols($this->stmt_id);
571
572 // if we used a limit, we added a field,
573 // subtract it out
574 if ($this->limit_used)
575 {
576 $count = $count - 1;
577 }
578
579 return $count;
580 }
581
582 // --------------------------------------------------------------------
583
584 /**
585 * Field data
586 *
587 * Generates an array of objects containing field meta-data
588 *
589 * @access public
590 * @return array
591 */
592 function field_data()
593 {
594 $retval = array();
595 $fieldCount = $this->num_fields();
596 for ($c = 1; $c <= $fieldCount; $c++)
597 {
598 $F = new stdClass();
599 $F->name = ocicolumnname($this->stmt_id, $c);
600 $F->type = ocicolumntype($this->stmt_id, $c);
601 $F->max_length = ocicolumnsize($this->stmt_id, $c);
602
603 $retval[] = $F;
604 }
605
606 return $retval;
607 }
608
609 // --------------------------------------------------------------------
610
611 /**
612 * Result - associative array
613 *
614 * Returns the result set as an array
615 *
616 * @access private
617 * @return array
618 */
619 function _fetch_assoc(&$row)
620 {
621 // if pulling from a cursor, use curs_id
622 if ($this->curs_id)
623 {
624 return ocifetchinto($this->curs_id, $row, OCI_ASSOC + OCI_RETURN_NULLS);
625 }
626 else
627 {
628 return ocifetchinto($this->stmt_id, $row, OCI_ASSOC + OCI_RETURN_NULLS);
629 }
630 }
631
632 // --------------------------------------------------------------------
633
634 /**
635 * Result - object
636 *
637 * Returns the result set as an object
638 *
639 * @access private
640 * @return object
641 */
642 function _fetch_object()
643 {
644 // the PHP 4 version of the oracle functions do not
645 // have a fetch method so we call the array version
646 // and build an object from that
647
648 $row = array();
649 $res = $this->_fetch_assoc($row);
650 if ($res != FALSE)
651 {
652 $obj = new stdClass();
653 foreach ($row as $key => $value)
654 {
655 $obj->{$key} = $value;
656 }
657
658 $res = $obj;
659 }
660 return $res;
661 }
662
663 /**
664 * Query result. "array" version.
665 *
666 * @access public
667 * @return array
668 */
669 function result_array()
670 {
671 if (count($this->result_array) > 0)
672 {
673 return $this->result_array;
674 }
675
676 // oracle's fetch functions do not
677 // return arrays, the information
678 // is returned in reference parameters
679 //
680 $row = NULL;
681 while ($this->_fetch_assoc($row))
682 {
683 $this->result_array[] = $row;
684 }
685
686 if (count($this->result_array) == 0)
687 {
688 return FALSE;
689 }
690
691 return $this->result_array;
692 }
693
694}
695
696?>