blob: b05cd7c5b5a491faa9dfe52c59a56975b08a18c3 [file] [log] [blame]
adminb0dd10f2006-08-25 17:25:49 +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 * Database Driver Class
20 *
21 * This is the platform-independent base DB implementation class.
22 * This class will not be called directly. Rather, the adapter
23 * class for the specific database will extend and instantiate it.
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 */
31class CI_DB_driver {
32
33 var $username;
34 var $password;
35 var $hostname;
36 var $database;
37 var $dbdriver = 'mysql';
38 var $dbprefix = '';
admin2ed76d52006-09-02 17:34:52 +000039 var $port = '';
adminb0dd10f2006-08-25 17:25:49 +000040 var $pconnect = FALSE;
41 var $conn_id = FALSE;
42 var $result_id = FALSE;
43 var $db_debug = FALSE;
44 var $benchmark = 0;
45 var $query_count = 0;
46 var $bind_marker = '?';
47 var $queries = array();
admin66530a82006-09-23 19:58:55 +000048 var $trans_enabled = TRUE;
49 var $_trans_depth = 0;
50 var $_trans_failure = FALSE; // Used with transactions to determine if a rollback should occur
51
admine348efb2006-09-20 21:13:26 +000052 // These are use with Oracle
53 var $stmt_id;
54 var $curs_id;
55 var $limit_used;
admin66530a82006-09-23 19:58:55 +000056
admine348efb2006-09-20 21:13:26 +000057
adminb0dd10f2006-08-25 17:25:49 +000058 /**
59 * Constructor. Accepts one parameter containing the database
60 * connection settings.
61 *
62 * Database settings can be passed as discreet
63 * parameters or as a data source name in the first
64 * parameter. DSNs must have this prototype:
65 * $dsn = 'driver://username:password@hostname/database';
66 *
67 * @param mixed. Can be an array or a DSN string
68 */
69 function CI_DB_driver($params)
70 {
71 $this->initialize($params);
72 log_message('debug', 'Database Driver Class Initialized');
73 }
74
75 // --------------------------------------------------------------------
76
77 /**
78 * Initialize Database Settings
79 *
80 * @access private Called by the constructor
81 * @param mixed
82 * @return void
83 */
84 function initialize($params = '')
85 {
86 if (is_array($params))
87 {
admin2ed76d52006-09-02 17:34:52 +000088 foreach (array('hostname' => '', 'username' => '', 'password' => '', 'database' => '', 'dbdriver' => 'mysql', 'dbprefix' => '', 'port' => '', 'pconnect' => FALSE, 'db_debug' => FALSE) as $key => $val)
adminb0dd10f2006-08-25 17:25:49 +000089 {
90 $this->$key = ( ! isset($params[$key])) ? $val : $params[$key];
91 }
92 }
93 elseif (strpos($params, '://'))
94 {
95 if (FALSE === ($dsn = @parse_url($params)))
96 {
97 log_message('error', 'Invalid DB Connection String');
98
admin57b3d392006-08-27 15:28:31 +000099 if ($this->db_debug)
adminb0dd10f2006-08-25 17:25:49 +0000100 {
101 return $this->display_error('db_invalid_connection_str');
102 }
103 return FALSE;
104 }
105
106 $this->hostname = ( ! isset($dsn['host'])) ? '' : rawurldecode($dsn['host']);
107 $this->username = ( ! isset($dsn['user'])) ? '' : rawurldecode($dsn['user']);
108 $this->password = ( ! isset($dsn['pass'])) ? '' : rawurldecode($dsn['pass']);
109 $this->database = ( ! isset($dsn['path'])) ? '' : rawurldecode(substr($dsn['path'], 1));
110 }
111
112 if ($this->pconnect == FALSE)
113 {
114 $this->conn_id = $this->db_connect();
115 }
116 else
117 {
118 $this->conn_id = $this->db_pconnect();
119 }
120
121 if ( ! $this->conn_id)
122 {
123 log_message('error', 'Unable to connect to the database');
124
125 if ($this->db_debug)
126 {
127 $this->display_error('db_unable_to_connect');
128 }
129 }
130 else
131 {
132 if ( ! $this->db_select())
133 {
134 log_message('error', 'Unable to select database: '.$this->database);
135
136 if ($this->db_debug)
137 {
138 $this->display_error('db_unable_to_select', $this->database);
139 }
140 }
141 }
142 }
143
144 // --------------------------------------------------------------------
145
146 /**
147 * Database Version Number. Returns a string containing the
148 * version of the database being used
149 *
150 * @access public
151 * @return string
152 */
153 function version()
154 {
155 if (FALSE === ($sql = $this->_version()))
156 {
157 if ($this->db_debug)
158 {
159 return $this->display_error('db_unsupported_function');
160 }
161 return FALSE;
162 }
admine348efb2006-09-20 21:13:26 +0000163
164 if ($this->dbdriver == 'oci8')
165 {
166 return $sql;
167 }
adminb0dd10f2006-08-25 17:25:49 +0000168
169 $query = $this->query($sql);
170 $row = $query->row();
171 return $row->ver;
172 }
173
174 // --------------------------------------------------------------------
175
176 /**
177 * Execute the query
178 *
179 * Accepts an SQL string as input and returns a result object upon
180 * successful execution of a "read" type query. Returns boolean TRUE
181 * upon successful execution of a "write" type query. Returns boolean
182 * FALSE upon failure, and if the $db_debug variable is set to TRUE
183 * will raise an error.
184 *
185 * @access public
186 * @param string An SQL query string
187 * @param array An array of binding data
188 * @return mixed
189 */
admine348efb2006-09-20 21:13:26 +0000190 function query($sql, $binds = FALSE, $return_object = TRUE)
adminb0dd10f2006-08-25 17:25:49 +0000191 {
adminb0dd10f2006-08-25 17:25:49 +0000192 if ($sql == '')
193 {
194 if ($this->db_debug)
195 {
196 log_message('error', 'Invalid query: '.$sql);
197 return $this->display_error('db_invalid_query');
198 }
199 return FALSE;
200 }
201
202 // Compile binds if needed
203 if ($binds !== FALSE)
204 {
205 $sql = $this->compile_binds($sql, $binds);
206 }
207
adminb0dd10f2006-08-25 17:25:49 +0000208 // Save the query for debugging
209 $this->queries[] = $sql;
admin66530a82006-09-23 19:58:55 +0000210
211 // Start the Query Timer
212 $time_start = list($sm, $ss) = explode(' ', microtime());
213
adminb0dd10f2006-08-25 17:25:49 +0000214 // Run the Query
admin66530a82006-09-23 19:58:55 +0000215 if (FALSE === ($this->result_id = $this->simple_query($sql)))
adminb0dd10f2006-08-25 17:25:49 +0000216 {
admin66530a82006-09-23 19:58:55 +0000217 // This will trigger a rollback if transactions are being used
218 $this->_trans_failure = TRUE;
219
adminb0dd10f2006-08-25 17:25:49 +0000220 if ($this->db_debug)
221 {
222 log_message('error', 'Query error: '.$this->error_message());
223 return $this->display_error(
224 array(
225 'Error Number: '.$this->error_number(),
226 $this->error_message(),
227 $sql
228 )
229 );
230 }
231
232 return FALSE;
233 }
234
235 // Stop and aggregate the query time results
236 $time_end = list($em, $es) = explode(' ', microtime());
237 $this->benchmark += ($em + $es) - ($sm + $ss);
238
239 // Increment the query counter
240 $this->query_count++;
241
242 // Was the query a "write" type?
admine348efb2006-09-20 21:13:26 +0000243 // If so we'll simply return true
adminb0dd10f2006-08-25 17:25:49 +0000244 if ($this->is_write_type($sql) === TRUE)
245 {
246 return TRUE;
247 }
admine348efb2006-09-20 21:13:26 +0000248
249 // Return TRUE if we don't need to create a result object
250 // Currently only the Oracle driver uses this when stored
251 // procedures are used
252 if ($return_object !== TRUE)
253 {
254 return TRUE;
255 }
adminb0dd10f2006-08-25 17:25:49 +0000256
257 // Instantiate and return the DB result object
258 $result = 'CI_DB_'.$this->dbdriver.'_result';
259
260 $RES = new $result();
261 $RES->conn_id = $this->conn_id;
262 $RES->db_debug = $this->db_debug;
263 $RES->result_id = $this->result_id;
admine348efb2006-09-20 21:13:26 +0000264
265 if ($this->dbdriver == 'oci8')
266 {
267 $RES->stmt_id = $this->stmt_id;
268 $RES->curs_id = NULL;
269 $RES->limit_used = $this->limit_used;
270 }
adminb0dd10f2006-08-25 17:25:49 +0000271
272 return $RES;
273 }
274
275 // --------------------------------------------------------------------
276
277 /**
admin66530a82006-09-23 19:58:55 +0000278 * Simple Query
279 * This is a simiplified version of the query() function. Internally
280 * we only use it when running transaction commands since they do
281 * not require all the features of the main query() function.
282 *
283 * @access public
284 * @param string the sql query
285 * @return mixed
286 */
287 function simple_query($sql)
288 {
289 if ( ! $this->conn_id)
290 {
291 $this->initialize();
292 }
293
294 return $this->_execute($sql, $this->conn_id);
295 }
296
297 // --------------------------------------------------------------------
298
299 /**
300 * Disable Transactions
301 * This permits transactions to be disabled at run-time.
302 *
303 * @access public
304 * @return void
305 */
306 function trans_off()
307 {
308 $this->trans_enabled = FALSE;
309 }
310
311 // --------------------------------------------------------------------
312
313 /**
314 * Start Transaction
315 *
316 * @access public
317 * @return void
318 */
319 function trans_start()
320 {
321 if ( ! $this->trans_enabled)
322 {
323 return FALSE;
324 }
325
326 // When transactions are nested we only begin/commit/rollback the outermost ones
327 if ($this->_trans_depth > 0)
328 {
329 $this->_trans_depth += 1;
330 return;
331 }
332
333 // Reset the transaction failure flag
334 $this->_trans_failure = FALSE;
335 $this->trans_begin();
336 }
337
338 // --------------------------------------------------------------------
339
340 /**
341 * Complete Transaction
342 *
343 * @access public
344 * @return bool
345 */
346 function trans_complete()
347 {
348 if ( ! $this->trans_enabled)
349 {
350 return FALSE;
351 }
352
353 // When transactions are nested we only begin/commit/rollback the outermost ones
354 if ($this->_trans_depth > 1)
355 {
356 $this->_trans_depth -= 1;
357 return TRUE;
358 }
359
360 // The query() function will set this flag to TRUE in the event that a query failed
361 if ($this->_trans_failure === TRUE)
362 {
363 $this->trans_rollback();
364
365 if ($this->db_debug)
366 {
367 return $this->display_error('db_transaction_failure');
368 }
369 return FALSE;
370 }
371
372 $this->trans_commit();
373 return TRUE;
374 }
375
376 // --------------------------------------------------------------------
377
378 /**
adminb0dd10f2006-08-25 17:25:49 +0000379 * Enables a native PHP function to be run, using a platform agnostic wrapper.
380 *
381 * @access public
382 * @param string the function name
383 * @param mixed any parameters needed by the function
384 * @return mixed
385 */
386 function call_function($function)
387 {
388 $driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_';
389
390 if (FALSE === strpos($driver, $function))
391 {
392 $function = $driver.$function;
393 }
394
395 if ( ! function_exists($function))
396 {
admin57b3d392006-08-27 15:28:31 +0000397 if ($this->db_debug)
adminb0dd10f2006-08-25 17:25:49 +0000398 {
399 return $this->display_error('db_unsupported_function');
400 }
401 return FALSE;
402 }
403 else
404 {
405 $args = (func_num_args() > 1) ? array_shift(func_get_args()) : null;
406
407 return call_user_func_array($function, $args);
408 }
409 }
410
411 // --------------------------------------------------------------------
412
413 /**
414 * Determines if a query is a "write" type.
415 *
416 * @access public
417 * @param string An SQL query string
418 * @return boolean
419 */
420 function is_write_type($sql)
421 {
422 if ( ! preg_match('/^\s*"?(INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|LOAD DATA|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK)\s+/i', $sql))
423 {
424 return FALSE;
425 }
426 return TRUE;
427 }
428
429 // --------------------------------------------------------------------
430
431 /**
432 * Calculate the aggregate query elapsed time
433 *
434 * @access public
435 * @param intiger The number of decimal places
436 * @return integer
437 */
438 function elapsed_time($decimals = 6)
439 {
440 return number_format($this->benchmark, $decimals);
441 }
442
443 // --------------------------------------------------------------------
444
445 /**
446 * Returns the total number of queries
447 *
448 * @access public
449 * @return integer
450 */
451 function total_queries()
452 {
453 return $this->query_count;
454 }
455
456 // --------------------------------------------------------------------
457
458 /**
459 * Returns the last query that was executed
460 *
461 * @access public
462 * @return void
463 */
464 function last_query()
465 {
466 return end($this->queries);
467 }
468
469 // --------------------------------------------------------------------
470
471 /**
472 * "Smart" Escape String
473 *
474 * Escapes data based on type
475 * Sets boolean and null types
476 *
477 * @access public
478 * @param string
479 * @return integer
480 */
481 function escape($str)
482 {
admine348efb2006-09-20 21:13:26 +0000483 switch (gettype($str))
adminb0dd10f2006-08-25 17:25:49 +0000484 {
admine348efb2006-09-20 21:13:26 +0000485 case 'string' : $str = "'".$this->escape_str($str)."'";
486 break;
487 case 'boolean' : $str = ($str === FALSE) ? 0 : 1;
488 break;
489 default : $str = ($str === NULL) ? 'NULL' : $str;
490 break;
491 }
492
adminb0dd10f2006-08-25 17:25:49 +0000493 return $str;
494 }
495
496 // --------------------------------------------------------------------
497
498 /**
499 * Returns an array of table names
500 *
501 * @access public
502 * @return array
503 */
504 function tables()
505 {
506 if (FALSE === ($sql = $this->_show_tables()))
507 {
508 if ($this->db_debug)
509 {
510 return $this->display_error('db_unsupported_function');
511 }
512 return FALSE;
513 }
514
515 $retval = array();
516 $query = $this->query($sql);
517
518 if ($query->num_rows() > 0)
519 {
520 foreach($query->result_array() as $row)
521 {
admine348efb2006-09-20 21:13:26 +0000522 if (isset($row['TABLE_NAME']))
523 {
524 $retval[] = $row['TABLE_NAME'];
525 }
526 else
527 {
528 $retval[] = array_shift($row);
529 }
adminb0dd10f2006-08-25 17:25:49 +0000530 }
531 }
532
533 return $retval;
534 }
535
536 // --------------------------------------------------------------------
537
538 /**
539 * Determine if a particular table exists
540 * @access public
541 * @return boolean
542 */
543 function table_exists($table_name)
544 {
545 return ( ! in_array($this->dbprefix.$table_name, $this->tables())) ? FALSE : TRUE;
546 }
547
548 // --------------------------------------------------------------------
549
550 /**
551 * Fetch MySQL Field Names
552 *
553 * @access public
554 * @param string the table name
555 * @return array
556 */
557 function field_names($table = '')
558 {
559 if ($table == '')
560 {
admin57b3d392006-08-27 15:28:31 +0000561 if ($this->db_debug)
adminb0dd10f2006-08-25 17:25:49 +0000562 {
563 return $this->display_error('db_field_param_missing');
564 }
565 return FALSE;
566 }
567
568 if (FALSE === ($sql = $this->_show_columns($this->dbprefix.$table)))
569 {
570 if ($this->db_debug)
571 {
572 return $this->display_error('db_unsupported_function');
573 }
574 return FALSE;
575 }
576
577 $query = $this->query($sql);
578
579 $retval = array();
580 foreach($query->result_array() as $row)
581 {
admine348efb2006-09-20 21:13:26 +0000582 if (isset($row['COLUMN_NAME']))
adminb0dd10f2006-08-25 17:25:49 +0000583 {
584 $retval[] = $row['COLUMN_NAME'];
585 }
586 else
587 {
588 $retval[] = current($row);
589 }
590 }
591
592 return $retval;
593 }
594
595 // --------------------------------------------------------------------
596
597 /**
598 * Returns an object with field data
599 *
600 * @access public
601 * @param string the table name
602 * @return object
603 */
604 function field_data($table = '')
605 {
606 if ($table == '')
607 {
admin57b3d392006-08-27 15:28:31 +0000608 if ($this->db_debug)
adminb0dd10f2006-08-25 17:25:49 +0000609 {
610 return $this->display_error('db_field_param_missing');
611 }
612 return FALSE;
613 }
614
615 return $this->_field_data($this->dbprefix.$table);
616 }
617
618 // --------------------------------------------------------------------
619
620 /**
621 * Primary
622 *
623 * Retrieves the primary key. It assumes that the row in the first
624 * position is the primary key
625 *
626 * @access public
627 * @param string the table name
628 * @return string
629 */
630 function primary($table = '')
631 {
632 $fields = $this->field_names($table);
633
634 if ( ! is_array($fields))
635 {
636 return FALSE;
637 }
638
639 return current($fields);
640 }
641
642 // --------------------------------------------------------------------
643
644 /**
645 * Compile Bindings
646 *
647 * @access public
648 * @param string the sql statement
649 * @param array an array of bind data
650 * @return string
651 */
652 function compile_binds($sql, $binds)
653 {
654 if (FALSE === strpos($sql, $this->bind_marker))
655 {
656 return $sql;
657 }
658
659 if ( ! is_array($binds))
660 {
661 $binds = array($binds);
662 }
663
664 foreach ($binds as $val)
665 {
666 $val = $this->escape($val);
667
668 // Just in case the replacement string contains the bind
669 // character we'll temporarily replace it with a marker
670 $val = str_replace($this->bind_marker, '{%bind_marker%}', $val);
admin57b3d392006-08-27 15:28:31 +0000671 $sql = preg_replace("#".preg_quote($this->bind_marker, '#')."#", str_replace('$', '\$', $val), $sql, 1);
adminb0dd10f2006-08-25 17:25:49 +0000672 }
673
674 return str_replace('{%bind_marker%}', $this->bind_marker, $sql);
675 }
676
677 // --------------------------------------------------------------------
678
679 /**
680 * Generate an insert string
681 *
682 * @access public
683 * @param string the table upon which the query will be performed
684 * @param array an associative array data of key/values
685 * @return string
686 */
687 function insert_string($table, $data)
688 {
689 $fields = array();
690 $values = array();
691
692 foreach($data as $key => $val)
693 {
694 $fields[] = $key;
695 $values[] = $this->escape($val);
696 }
697
698 return $this->_insert($this->dbprefix.$table, $fields, $values);
699 }
700
701 // --------------------------------------------------------------------
702
703 /**
704 * Generate an update string
705 *
706 * @access public
707 * @param string the table upon which the query will be performed
708 * @param array an associative array data of key/values
709 * @param mixed the "where" statement
710 * @return string
711 */
712 function update_string($table, $data, $where)
713 {
714 if ($where == '')
715 return false;
716
717 $fields = array();
718 foreach($data as $key => $val)
719 {
720 $fields[$key] = $this->escape($val);
721 }
722
723 if ( ! is_array($where))
724 {
725 $dest = array($where);
726 }
727 else
728 {
729 $dest = array();
730 foreach ($where as $key => $val)
731 {
732 $prefix = (count($dest) == 0) ? '' : ' AND ';
733
734 if ($val != '')
735 {
736 if ( ! $this->_has_operator($key))
737 {
738 $key .= ' =';
739 }
740
741 $val = ' '.$this->escape($val);
742 }
743
744 $dest[] = $prefix.$key.$val;
745 }
746 }
747
748 return $this->_update($this->dbprefix.$table, $fields, $dest);
749 }
750
751 // --------------------------------------------------------------------
752
753 /**
754 * Close DB Connection
755 *
756 * @access public
757 * @return void
758 */
759 function close()
760 {
761 if (is_resource($this->conn_id))
762 {
763 $this->destroy($this->conn_id);
764 }
765 $this->conn_id = FALSE;
766 }
767
768 // --------------------------------------------------------------------
769
770 /**
771 * Display an error message
772 *
773 * @access public
774 * @param string the error message
775 * @param string any "swap" values
776 * @param boolean whether to localize the message
777 * @return string sends the application/errror_db.php template
778 */
779 function display_error($error = '', $swap = '', $native = FALSE)
780 {
781 $LANG = new CI_Language();
782 $LANG->load('db');
783
784 $heading = 'MySQL Error';
785
786 if ($native == TRUE)
787 {
788 $message = $error;
789 }
790 else
791 {
792 $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error;
793 }
794
795 if ( ! class_exists('CI_Exceptions'))
796 {
797 include_once(BASEPATH.'libraries/Exceptions.php');
798 }
799
800 $error = new CI_Exceptions();
801 echo $error->show_error('An Error Was Encountered', $message, 'error_db');
802 exit;
803
804 }
805
adminb0dd10f2006-08-25 17:25:49 +0000806}
807
808
809/**
810 * Database Result Class
811 *
812 * This is the platform-independent result class.
813 * This class will not be called directly. Rather, the adapter
814 * class for the specific database will extend and instantiate it.
815 *
816 * @category Database
817 * @author Rick Ellis
818 * @link http://www.codeigniter.com/user_guide/libraries/database/
819 */
820class CI_DB_result {
821
822 var $conn_id = FALSE;
823 var $result_id = FALSE;
824 var $db_debug = FALSE;
825 var $result_array = array();
826 var $result_object = array();
827 var $current_row = 0;
828
829 /**
830 * Query result. Acts as a wrapper function for the following functions.
831 *
832 * @access public
833 * @param string can be "object" or "array"
834 * @return mixed either a result object or array
835 */
836 function result($type = 'object')
837 {
838 return ($type == 'object') ? $this->result_object() : $this->result_array();
839 }
840
841 // --------------------------------------------------------------------
842
843 /**
844 * Query result. "object" version.
845 *
846 * @access public
847 * @return object
848 */
849 function result_object()
850 {
851 if (count($this->result_object) > 0)
852 {
853 return $this->result_object;
854 }
855
856 while ($row = $this->_fetch_object())
857 {
858 $this->result_object[] = $row;
859 }
860
861 if (count($this->result_object) == 0)
862 {
863 return FALSE;
864 }
865
866 return $this->result_object;
867 }
868
869 // --------------------------------------------------------------------
870
871 /**
872 * Query result. "array" version.
873 *
874 * @access public
875 * @return array
876 */
877 function result_array()
878 {
879 if (count($this->result_array) > 0)
880 {
881 return $this->result_array;
882 }
883
884 while ($row = $this->_fetch_assoc())
885 {
886 $this->result_array[] = $row;
887 }
888
889 if (count($this->result_array) == 0)
890 {
891 return FALSE;
892 }
893
894 return $this->result_array;
895 }
896
897 // --------------------------------------------------------------------
898
899 /**
900 * Query result. Acts as a wrapper function for the following functions.
901 *
902 * @access public
903 * @param string can be "object" or "array"
904 * @return mixed either a result object or array
905 */
906 function row($n = 0, $type = 'object')
907 {
908 return ($type == 'object') ? $this->row_object($n) : $this->row_array($n);
909 }
910
911 // --------------------------------------------------------------------
912
913 /**
914 * Returns a single result row - object version
915 *
916 * @access public
917 * @return object
918 */
919 function row_object($n = 0)
920 {
921 if (FALSE === ($result = $this->result_object()))
922 {
923 return FALSE;
924 }
925
926 if ($n != $this->current_row AND isset($result[$n]))
927 {
928 $this->current_row = $n;
929 }
930
931 return $result[$this->current_row];
932 }
933
934 // --------------------------------------------------------------------
935
936 /**
937 * Returns a single result row - array version
938 *
939 * @access public
940 * @return array
941 */
942 function row_array($n = 0)
943 {
944 if (FALSE === ($result = $this->result_array()))
945 {
946 return FALSE;
947 }
948
949 if ($n != $this->current_row AND isset($result[$n]))
950 {
951 $this->current_row = $n;
952 }
953
954 return $result[$this->current_row];
955 }
956
957 // --------------------------------------------------------------------
958
959 /**
960 * Returns the "next" row
961 *
962 * @access public
963 * @return object
964 */
965 function next_row($type = 'object')
966 {
967 if (FALSE === ($result = $this->result($type)))
968 {
969 return FALSE;
970 }
971
972 if (isset($result[$this->current_row + 1]))
973 {
974 ++$this->current_row;
975 }
976
977 return $result[$this->current_row];
978 }
979
980 // --------------------------------------------------------------------
981
982 /**
983 * Returns the "previous" row
984 *
985 * @access public
986 * @return object
987 */
988 function previous_row($type = 'object')
989 {
990 if (FALSE === ($result = $this->result($type)))
991 {
992 return FALSE;
993 }
994
995 if (isset($result[$this->current_row - 1]))
996 {
997 --$this->current_row;
998 }
999 return $result[$this->current_row];
1000 }
1001
1002 // --------------------------------------------------------------------
1003
1004 /**
1005 * Returns the "first" row
1006 *
1007 * @access public
1008 * @return object
1009 */
1010 function first_row($type = 'object')
1011 {
1012 if (FALSE === ($result = $this->result($type)))
1013 {
1014 return FALSE;
1015 }
1016 return $result[0];
1017 }
1018
1019 // --------------------------------------------------------------------
1020
1021 /**
1022 * Returns the "last" row
1023 *
1024 * @access public
1025 * @return object
1026 */
1027 function last_row($type = 'object')
1028 {
1029 if (FALSE === ($result = $this->result($type)))
1030 {
1031 return FALSE;
1032 }
1033 return $result[count($result) -1];
1034 }
1035
1036}
1037
adminb0dd10f2006-08-25 17:25:49 +00001038?>