converted to unix-style eol
[www-register-wizard.git] / database / drivers / oci8 / oci8_driver.php
1 <?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              ExpressionEngine Dev Team
9  * @copyright   Copyright (c) 2008, EllisLab, Inc.
10  * @license             http://codeigniter.com/user_guide/license.html
11  * @link                http://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              ExpressionEngine Dev Team
29  * @link                http://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
44 class CI_DB_oci8_driver extends CI_DB {
45
46         var $dbdriver = 'oci8';
47         
48         // The character used for excaping
49         var $_escape_char = '"';
50
51         /**
52          * The syntax to count rows is slightly different across different
53          * database engines, so this string appears in each driver and is
54          * used for the count_all() and count_all_results() functions.
55          */
56         var $_count_string = "SELECT COUNT(1) AS ";
57         var $_random_keyword = ' ASC'; // not currently supported
58
59         // Set "auto commit" by default
60         var $_commit = OCI_COMMIT_ON_SUCCESS;
61
62         // need to track statement id and cursor id
63         var $stmt_id;
64         var $curs_id;
65
66         // if we use a limit, we will add a field that will
67         // throw off num_fields later
68         var $limit_used;
69
70         /**
71          * Non-persistent database connection
72          *
73          * @access  private called by the base class
74          * @return  resource
75          */
76         function db_connect()
77         {
78                 return @ocilogon($this->username, $this->password, $this->hostname);
79         }
80
81         // --------------------------------------------------------------------
82
83         /**
84          * Persistent database connection
85          *
86          * @access  private called by the base class
87          * @return  resource
88          */
89         function db_pconnect()
90         {
91                 return @ociplogon($this->username, $this->password, $this->hostname);
92         }
93
94         // --------------------------------------------------------------------
95
96         /**
97          * Select the database
98          *
99          * @access  private called by the base class
100          * @return  resource
101          */
102         function db_select()
103         {
104                 return TRUE;
105         }
106
107         // --------------------------------------------------------------------
108
109         /**
110          * Set client character set
111          *
112          * @access      public
113          * @param       string
114          * @param       string
115          * @return      resource
116          */
117         function db_set_charset($charset, $collation)
118         {
119                 // @todo - add support if needed
120                 return TRUE;
121         }
122
123         // --------------------------------------------------------------------
124         
125         /**
126          * Version number query string
127          *
128          * @access  public
129          * @return  string
130          */
131         function _version()
132         {
133                 return ociserverversion($this->conn_id);
134         }
135
136         // --------------------------------------------------------------------
137
138         /**
139          * Execute the query
140          *
141          * @access  private called by the base class
142          * @param   string  an SQL query
143          * @return  resource
144          */
145         function _execute($sql)
146         {
147                 // oracle must parse the query before it is run. All of the actions with
148                 // the query are based on the statement id returned by ociparse
149                 $this->stmt_id = FALSE;
150                 $this->_set_stmt_id($sql);
151                 ocisetprefetch($this->stmt_id, 1000);
152                 return @ociexecute($this->stmt_id, $this->_commit);
153         }
154
155         /**
156          * Generate a statement ID
157          *
158          * @access  private
159          * @param   string  an SQL query
160          * @return  none
161          */
162         function _set_stmt_id($sql)
163         {
164                 if ( ! is_resource($this->stmt_id))
165                 {
166                         $this->stmt_id = ociparse($this->conn_id, $this->_prep_query($sql));
167                 }
168         }
169
170         // --------------------------------------------------------------------
171
172         /**
173          * Prep the query
174          *
175          * If needed, each database adapter can prep the query string
176          *
177          * @access  private called by execute()
178          * @param   string  an SQL query
179          * @return  string
180          */
181         function _prep_query($sql)
182         {
183                 return $sql;
184         }
185
186         // --------------------------------------------------------------------
187
188         /**
189          * getCursor.  Returns a cursor from the datbase
190          *
191          * @access  public
192          * @return  cursor id
193          */
194         function get_cursor()
195         {
196                 $this->curs_id = ocinewcursor($this->conn_id);
197                 return $this->curs_id;
198         }
199
200         // --------------------------------------------------------------------
201
202         /**
203          * Stored Procedure.  Executes a stored procedure
204          *
205          * @access  public
206          * @param   package      package stored procedure is in
207          * @param   procedure   stored procedure to execute
208          * @param   params        array of parameters
209          * @return  array
210          *
211          * params array keys
212          *
213          * KEY    OPTIONAL      NOTES
214          * name         no              the name of the parameter should be in :<param_name> format
215          * value        no              the value of the parameter.  If this is an OUT or IN OUT parameter,
216          *                                      this should be a reference to a variable
217          * type         yes             the type of the parameter
218          * length       yes             the max size of the parameter
219          */
220         function stored_procedure($package, $procedure, $params)
221         {
222                 if ($package == '' OR $procedure == '' OR ! is_array($params))
223                 {
224                         if ($this->db_debug)
225                         {
226                                 log_message('error', 'Invalid query: '.$package.'.'.$procedure);
227                                 return $this->display_error('db_invalid_query');
228                         }
229                         return FALSE;
230                 }
231                 
232                 // build the query string
233                 $sql = "begin $package.$procedure(";
234
235                 $have_cursor = FALSE;
236                 foreach($params as $param)
237                 {
238                         $sql .= $param['name'] . ",";
239                         
240                         if (array_key_exists('type', $param) && ($param['type'] == OCI_B_CURSOR))
241                         {
242                                 $have_cursor = TRUE;
243                         }
244                 }
245                 $sql = trim($sql, ",") . "); end;";
246                                 
247                 $this->stmt_id = FALSE;
248                 $this->_set_stmt_id($sql);
249                 $this->_bind_params($params);
250                 $this->query($sql, FALSE, $have_cursor);
251         }
252         
253         // --------------------------------------------------------------------
254
255         /**
256          * Bind parameters
257          *
258          * @access  private
259          * @return  none
260          */
261         function _bind_params($params)
262         {
263                 if ( ! is_array($params) OR ! is_resource($this->stmt_id))
264                 {
265                         return;
266                 }
267                 
268                 foreach ($params as $param)
269                 {
270                         foreach (array('name', 'value', 'type', 'length') as $val)
271                         {
272                                 if ( ! isset($param[$val]))
273                                 {
274                                         $param[$val] = '';
275                                 }
276                         }
277
278                         ocibindbyname($this->stmt_id, $param['name'], $param['value'], $param['length'], $param['type']);
279                 }
280         }
281
282         // --------------------------------------------------------------------
283
284         /**
285          * Begin Transaction
286          *
287          * @access      public
288          * @return      bool            
289          */     
290         function trans_begin($test_mode = FALSE)
291         {
292                 if ( ! $this->trans_enabled)
293                 {
294                         return TRUE;
295                 }
296                 
297                 // When transactions are nested we only begin/commit/rollback the outermost ones
298                 if ($this->_trans_depth > 0)
299                 {
300                         return TRUE;
301                 }
302                 
303                 // Reset the transaction failure flag.
304                 // If the $test_mode flag is set to TRUE transactions will be rolled back
305                 // even if the queries produce a successful result.
306                 $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
307                 
308                 $this->_commit = OCI_DEFAULT;
309                 return TRUE;
310         }
311
312         // --------------------------------------------------------------------
313
314         /**
315          * Commit Transaction
316          *
317          * @access      public
318          * @return      bool            
319          */     
320         function trans_commit()
321         {
322                 if ( ! $this->trans_enabled)
323                 {
324                         return TRUE;
325                 }
326
327                 // When transactions are nested we only begin/commit/rollback the outermost ones
328                 if ($this->_trans_depth > 0)
329                 {
330                         return TRUE;
331                 }
332
333                 $ret = OCIcommit($this->conn_id);
334                 $this->_commit = OCI_COMMIT_ON_SUCCESS;
335                 return $ret;
336         }
337
338         // --------------------------------------------------------------------
339
340         /**
341          * Rollback Transaction
342          *
343          * @access      public
344          * @return      bool            
345          */     
346         function trans_rollback()
347         {
348                 if ( ! $this->trans_enabled)
349                 {
350                         return TRUE;
351                 }
352
353                 // When transactions are nested we only begin/commit/rollback the outermost ones
354                 if ($this->_trans_depth > 0)
355                 {
356                         return TRUE;
357                 }
358
359                 $ret = OCIrollback($this->conn_id);
360                 $this->_commit = OCI_COMMIT_ON_SUCCESS;
361                 return $ret;
362         }
363
364         // --------------------------------------------------------------------
365
366         /**
367          * Escape String
368          *
369          * @access  public
370          * @param   string
371          * @return  string
372          */
373         function escape_str($str)
374         {
375                 // Access the CI object
376                 $CI =& get_instance();
377
378                 return $CI->_remove_invisible_characters($str);
379         }
380
381         // --------------------------------------------------------------------
382
383         /**
384          * Affected Rows
385          *
386          * @access  public
387          * @return  integer
388          */
389         function affected_rows()
390         {
391                 return @ocirowcount($this->stmt_id);
392         }
393
394         // --------------------------------------------------------------------
395
396         /**
397          * Insert ID
398          *
399          * @access  public
400          * @return  integer
401          */
402         function insert_id()
403         {
404                 // not supported in oracle
405                 return $this->display_error('db_unsupported_function');
406         }
407
408         // --------------------------------------------------------------------
409
410         /**
411          * "Count All" query
412          *
413          * Generates a platform-specific query string that counts all records in
414          * the specified database
415          *
416          * @access  public
417          * @param   string
418          * @return  string
419          */
420         function count_all($table = '')
421         {
422                 if ($table == '')
423                         return '0';
424
425                 $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows'). " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE));
426
427                 if ($query == FALSE)
428                         {
429                         return 0;
430                         }
431
432                 $row = $query->row();
433                 return $row->NUMROWS;
434         }
435
436         // --------------------------------------------------------------------
437
438         /**
439          * Show table query
440          *
441          * Generates a platform-specific query string so that the table names can be fetched
442          *
443          * @access  private
444          * @param       boolean
445          * @return  string
446          */
447         function _list_tables($prefix_limit = FALSE)
448         {
449                 $sql = "SELECT TABLE_NAME FROM ALL_TABLES";
450
451                 if ($prefix_limit !== FALSE AND $this->dbprefix != '')
452                 {
453                         $sql .= " WHERE TABLE_NAME LIKE '".$this->dbprefix."%'";
454                 }
455                 
456                 return $sql;
457         }
458
459         // --------------------------------------------------------------------
460
461         /**
462          * Show column query
463          *
464          * Generates a platform-specific query string so that the column names can be fetched
465          *
466          * @access  public
467          * @param   string  the table name
468          * @return  string
469          */
470         function _list_columns($table = '')
471         {
472                 return "SELECT COLUMN_NAME FROM all_tab_columns WHERE table_name = '$table'";
473         }
474
475         // --------------------------------------------------------------------
476
477         /**
478          * Field data query
479          *
480          * Generates a platform-specific query so that the column data can be retrieved
481          *
482          * @access  public
483          * @param   string  the table name
484          * @return  object
485          */
486         function _field_data($table)
487         {
488                 return "SELECT * FROM ".$table." where rownum = 1";
489         }
490
491         // --------------------------------------------------------------------
492
493         /**
494          * The error message string
495          *
496          * @access  private
497          * @return  string
498          */
499         function _error_message()
500         {
501                 $error = ocierror($this->conn_id);
502                 return $error['message'];
503         }
504
505         // --------------------------------------------------------------------
506
507         /**
508          * The error message number
509          *
510          * @access  private
511          * @return  integer
512          */
513         function _error_number()
514         {
515                 $error = ocierror($this->conn_id);
516                 return $error['code'];
517         }
518         
519         // --------------------------------------------------------------------
520
521         /**
522          * Escape the SQL Identifiers
523          *
524          * This function escapes column and table names
525          *
526          * @access      private
527          * @param       string
528          * @return      string
529          */
530         function _escape_identifiers($item)
531         {
532                 if ($this->_escape_char == '')
533                 {
534                         return $item;
535                 }
536         
537                 if (strpos($item, '.') !== FALSE)
538                 {
539                         $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char;                    
540                 }
541                 else
542                 {
543                         $str = $this->_escape_char.$item.$this->_escape_char;
544                 }
545                 
546                 // remove duplicates if the user already included the escape
547                 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str);
548         }
549         
550         // --------------------------------------------------------------------
551
552         /**
553          * From Tables
554          *
555          * This function implicitly groups FROM tables so there is no confusion
556          * about operator precedence in harmony with SQL standards
557          *
558          * @access      public
559          * @param       type
560          * @return      type
561          */
562         function _from_tables($tables)
563         {
564                 if ( ! is_array($tables))
565                 {
566                         $tables = array($tables);
567                 }
568                 
569                 return implode(', ', $tables);
570         }
571
572         // --------------------------------------------------------------------
573         
574         /**
575          * Insert statement
576          *
577          * Generates a platform-specific insert string from the supplied data
578          *
579          * @access  public
580          * @param   string  the table name
581          * @param   array   the insert keys
582          * @param   array   the insert values
583          * @return  string
584          */
585         function _insert($table, $keys, $values)
586         {
587         return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")";
588         }
589
590         // --------------------------------------------------------------------
591
592         /**
593          * Update statement
594          *
595          * Generates a platform-specific update string from the supplied data
596          *
597          * @access      public
598          * @param       string  the table name
599          * @param       array   the update data
600          * @param       array   the where clause
601          * @param       array   the orderby clause
602          * @param       array   the limit clause
603          * @return      string
604          */
605         function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
606         {
607                 foreach($values as $key => $val)
608                 {
609                         $valstr[] = $key." = ".$val;
610                 }
611                 
612                 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
613                 
614                 $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):'';
615         
616                 $sql = "UPDATE ".$table." SET ".implode(', ', $valstr);
617
618                 $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : '';
619
620                 $sql .= $orderby.$limit;
621                 
622                 return $sql;
623         }
624
625         // --------------------------------------------------------------------
626
627         /**
628          * Truncate statement
629          *
630          * Generates a platform-specific truncate string from the supplied data
631          * If the database does not support the truncate() command
632          * This function maps to "DELETE FROM table"
633          *
634          * @access      public
635          * @param       string  the table name
636          * @return      string
637          */     
638         function _truncate($table)
639         {
640                 return "TRUNCATE TABLE ".$table;
641         }
642         
643         // --------------------------------------------------------------------
644
645         /**
646          * Delete statement
647          *
648          * Generates a platform-specific delete string from the supplied data
649          *
650          * @access      public
651          * @param       string  the table name
652          * @param       array   the where clause
653          * @param       string  the limit clause
654          * @return      string
655          */     
656         function _delete($table, $where = array(), $like = array(), $limit = FALSE)
657         {
658                 $conditions = '';
659
660                 if (count($where) > 0 OR count($like) > 0)
661                 {
662                         $conditions = "\nWHERE ";
663                         $conditions .= implode("\n", $this->ar_where);
664
665                         if (count($where) > 0 && count($like) > 0)
666                         {
667                                 $conditions .= " AND ";
668                         }
669                         $conditions .= implode("\n", $like);
670                 }
671
672                 $limit = ( ! $limit) ? '' : ' LIMIT '.$limit;
673         
674                 return "DELETE FROM ".$table.$conditions.$limit;
675         }
676
677         // --------------------------------------------------------------------
678
679         /**
680          * Limit string
681          *
682          * Generates a platform-specific LIMIT clause
683          *
684          * @access  public
685          * @param   string  the sql query string
686          * @param   integer the number of rows to limit the query to
687          * @param   integer the offset value
688          * @return  string
689          */
690         function _limit($sql, $limit, $offset)
691         {
692                 $limit = $offset + $limit;
693                 $newsql = "SELECT * FROM (select inner_query.*, rownum rnum FROM ($sql) inner_query WHERE rownum < $limit)";
694
695                 if ($offset != 0)
696                 {
697                         $newsql .= " WHERE rnum >= $offset";
698                 }
699
700                 // remember that we used limits
701                 $this->limit_used = TRUE;
702
703                 return $newsql;
704         }       
705
706         // --------------------------------------------------------------------
707
708         /**
709          * Close DB Connection
710          *
711          * @access  public
712          * @param   resource
713          * @return  void
714          */
715         function _close($conn_id)
716         {
717                 @ocilogoff($conn_id);
718         }
719
720
721 }
722
723
724
725 /* End of file oci8_driver.php */
726 /* Location: ./system/database/drivers/oci8/oci8_driver.php */