PHPDocumentor [http://en.wikipedia.org/wiki/PhpDocumentor] documentation tweaking...
[lhc/web/wiklou.git] / includes / Database.php
index 4ab1b98..0b1462c 100644 (file)
@@ -2,21 +2,8 @@
 /**
  * This file deals with MySQL interface functions
  * and query specifics/optimisations
- * @package MediaWiki
  */
 
-/**
- * Depends on the CacheManager
- */
-require_once( 'CacheManager.php' );
-
-/** See Database::makeList() */
-define( 'LIST_COMMA', 0 );
-define( 'LIST_AND', 1 );
-define( 'LIST_SET', 2 );
-define( 'LIST_NAMES', 3);
-define( 'LIST_OR', 4);
-
 /** Number of times to re-try an operation in case of deadlock */
 define( 'DEADLOCK_TRIES', 4 );
 /** Minimum time to wait before retry, in microseconds */
@@ -28,6 +15,9 @@ define( 'DEADLOCK_DELAY_MAX', 1500000 );
  * Utility classes
  *****************************************************************************/
 
+/**
+ * Utility class.
+ */
 class DBObject {
        public $mData;
 
@@ -44,6 +34,58 @@ class DBObject {
        }
 };
 
+/**
+ * Utility class.
+ */
+class MySQLField {
+       private $name, $tablename, $default, $max_length, $nullable,
+               $is_pk, $is_unique, $is_key, $type;
+       function __construct ($info) {
+               $this->name = $info->name;
+               $this->tablename = $info->table;
+               $this->default = $info->def;
+               $this->max_length = $info->max_length;
+               $this->nullable = !$info->not_null;
+               $this->is_pk = $info->primary_key;
+               $this->is_unique = $info->unique_key;
+               $this->is_multiple = $info->multiple_key;
+               $this->is_key = ($this->is_pk || $this->is_unique || $this->is_multiple);
+               $this->type = $info->type;
+       }
+
+       function name() {
+               return $this->name;
+       }
+
+       function tableName() {
+               return $this->tableName;
+       }
+
+       function defaultValue() {
+               return $this->default;
+       }
+
+       function maxLength() {
+               return $this->max_length;
+       }
+
+       function nullable() {
+               return $this->nullable;
+       }
+
+       function isKey() {
+               return $this->is_key;
+       }
+
+       function isMultipleKey() {
+               return $this->is_multiple;
+       }
+
+       function type() {
+               return $this->type;
+       }
+}
+
 /******************************************************************************
  * Error classes
  *****************************************************************************/
@@ -91,14 +133,19 @@ class DBConnectionError extends DBError {
                return $this->getMessage() . "\n";
        }
 
+       function getLogMessage() {
+               # Don't send to the exception log
+               return false;
+       }
+
        function getPageTitle() {
                global $wgSitename;
                return "$wgSitename has a problem";
        }
 
        function getHTML() {
-               global $wgTitle, $wgUseFileCache, $title, $wgInputEncoding, $wgOutputEncoding;
-               global $wgSitename, $wgServer, $wgMessageCache, $wgLogo;
+               global $wgTitle, $wgUseFileCache, $title, $wgInputEncoding;
+               global $wgSitename, $wgServer, $wgMessageCache;
 
                # I give up, Brion is right. Getting the message cache to work when there is no DB is tricky.
                # Hard coding strings instead.
@@ -159,8 +206,9 @@ border=\"0\" ALT=\"Google\"></A>
                                }
                        }
 
-                       $cache = new CacheManager( $t );
+                       $cache = new HTMLFileCache( $t );
                        if( $cache->isFileCached() ) {
+                               // FIXME: $msg is not defined on the next line.
                                $msg = '<p style="color: red"><b>'.$msg."<br />\n" .
                                        $cachederror . "</b></p>\n";
 
@@ -210,6 +258,11 @@ class DBQueryError extends DBError {
                }
        }
        
+       function getLogMessage() {
+               # Don't send to the exception log
+               return false;
+       }
+
        function getPageTitle() {
                return $this->msg( 'databaseerror', 'Database error' );
        }
@@ -230,7 +283,6 @@ class DBUnexpectedError extends DBError {}
 
 /**
  * Database abstraction object
- * @package MediaWiki
  */
 class Database {
 
@@ -294,7 +346,7 @@ class Database {
         * Turns on (false) or off (true) the automatic generation and sending
         * of a "we're sorry, but there has been a database error" page on
         * database errors. Default is on (false). When turned off, the
-        * code should use wfLastErrno() and wfLastError() to handle the
+        * code should use lastErrno() and lastError() to handle the
         * situation as appropriate.
         */
        function ignoreErrors( $ignoreErrors = NULL ) {
@@ -339,6 +391,50 @@ class Database {
                }
        }
 
+       /**
+        * Returns true if this database supports (and uses) cascading deletes
+        */
+       function cascadingDeletes() {
+               return false;
+       }
+
+       /**
+        * Returns true if this database supports (and uses) triggers (e.g. on the page table)
+        */
+       function cleanupTriggers() {
+               return false;
+       }
+
+       /**
+        * Returns true if this database is strict about what can be put into an IP field.
+        * Specifically, it uses a NULL value instead of an empty string.
+        */
+       function strictIPs() {
+               return false;
+       }
+
+       /**
+        * Returns true if this database uses timestamps rather than integers
+       */
+       function realTimestamps() {
+               return false;
+       }
+
+       /**
+        * Returns true if this database does an implicit sort when doing GROUP BY
+        */
+       function implicitGroupby() {
+               return true;
+       }
+
+       /**
+        * Returns true if this database can do a native search on IP columns
+        * e.g. this works as expected: .. WHERE rc_ip = '127.42.12.102/32';
+        */
+       function searchableIPs() {
+               return false;
+       }
+
        /**#@+
         * Get function
         */
@@ -369,14 +465,12 @@ class Database {
 # Other functions
 #------------------------------------------------------------------------------
 
-       /**@{{
+       /**
+        * Constructor.
         * @param string $server database server host
         * @param string $user database user name
         * @param string $password database user password
         * @param string $dbname database name
-        */
-
-       /**
         * @param failFunction
         * @param $flags
         * @param $tablePrefix String: database table prefixes. By default use the prefix gave in LocalSettings.php
@@ -426,8 +520,7 @@ class Database {
         * @param failFunction
         * @param $flags
         */
-       static function newFromParams( $server, $user, $password, $dbName,
-               $failFunction = false, $flags = 0 )
+       static function newFromParams( $server, $user, $password, $dbName, $failFunction = false, $flags = 0 )
        {
                return new Database( $server, $user, $password, $dbName, $failFunction, $flags );
        }
@@ -438,6 +531,7 @@ class Database {
         */
        function open( $server, $user, $password, $dbName ) {
                global $wguname;
+               wfProfileIn( __METHOD__ );
 
                # Test for missing mysql.so
                # First try to load it
@@ -459,12 +553,28 @@ class Database {
 
                $success = false;
 
-               if ( $this->mFlags & DBO_PERSISTENT ) {
-                       @/**/$this->mConn = mysql_pconnect( $server, $user, $password );
-               } else {
-                       # Create a new connection...
-                       @/**/$this->mConn = mysql_connect( $server, $user, $password, true );
+               wfProfileIn("dbconnect-$server");
+               
+               # LIVE PATCH by Tim, ask Domas for why: retry loop
+               $this->mConn = false;
+               $max = 3;
+               for ( $i = 0; $i < $max && !$this->mConn; $i++ ) {
+                       if ( $i > 1 ) {
+                               usleep( 1000 );
+                       }
+                       if ( $this->mFlags & DBO_PERSISTENT ) {
+                               @/**/$this->mConn = mysql_pconnect( $server, $user, $password );
+                       } else {
+                               # Create a new connection...
+                               @/**/$this->mConn = mysql_connect( $server, $user, $password, true );
+                       }
+                       if ($this->mConn === false) {
+                               $iplus = $i + 1;
+                               #wfLogDBError("Connect loop error $iplus of $max ($server): " . mysql_errno() . " - " . mysql_error()."\n"); 
+                       }
                }
+               
+               wfProfileOut("dbconnect-$server");
 
                if ( $dbName != '' ) {
                        if ( $this->mConn !== false ) {
@@ -472,6 +582,7 @@ class Database {
                                if ( !$success ) {
                                        $error = "Error selecting database $dbName on server {$this->mServer} " .
                                                "from client host {$wguname['nodename']}\n";
+                                       wfLogDBError(" Error selecting database $dbName on server {$this->mServer} \n");
                                        wfDebug( $error );
                                }
                        } else {
@@ -485,21 +596,21 @@ class Database {
                        $success = (bool)$this->mConn;
                }
 
-               if ( !$success ) {
+               if ( $success ) {
+                       global $wgDBmysql5;
+                       if( $wgDBmysql5 ) {
+                               // Tell the server we're communicating with it in UTF-8.
+                               // This may engage various charset conversions.
+                               $this->query( 'SET NAMES utf8' );
+                       }
+               } else {
                        $this->reportConnectionError();
                }
 
-               global $wgDBmysql5;
-               if( $wgDBmysql5 ) {
-                       // Tell the server we're communicating with it in UTF-8.
-                       // This may engage various charset conversions.
-                       $this->query( 'SET NAMES utf8' );
-               }
-
                $this->mOpened = $success;
+               wfProfileOut( __METHOD__ );
                return $success;
        }
-       /**@}}*/
 
        /**
         * Closes a database connection.
@@ -571,7 +682,7 @@ class Database {
 
                # Add a comment for easy SHOW PROCESSLIST interpretation
                if ( $fname ) {
-                       $commentedSql = preg_replace("/\s/", " /* $fname */ ", $sql, 1);
+                       $commentedSql = preg_replace('/\s/', " /* $fname */ ", $sql, 1);
                } else {
                        $commentedSql = $sql;
                }
@@ -599,6 +710,11 @@ class Database {
                        wfDebug( "Connection lost, reconnecting...\n" );
                        if ( $this->ping() ) {
                                wfDebug( "Reconnected\n" );
+                               $sqlx = substr( $commentedSql, 0, 500 );
+                               $sqlx = strtr( $sqlx, "\t\n", '  ' );
+                               global $wgRequestTime;
+                               $elapsed = round( microtime(true) - $wgRequestTime, 3 );
+                               wfLogDBError( "Connection lost and reconnected after {$elapsed}s, query: $sqlx\n" );
                                $ret = $this->doQuery( $commentedSql );
                        } else {
                                wfDebug( "Failed\n" );
@@ -637,7 +753,7 @@ class Database {
         * @param bool $tempIgnore
         */
        function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) {
-               global $wgCommandLineMode, $wgFullyInitialised, $wgColorErrors;
+               global $wgCommandLineMode;
                # Ignore errors during error handling to avoid infinite recursion
                $ignore = $this->ignoreErrors( true );
                ++$this->mErrorCount;
@@ -736,7 +852,7 @@ class Database {
                        case '\\!': return '!';
                        case '\\&': return '&';
                }
-               list( $n, $arg ) = each( $this->preparedArgs );
+               list( /* $n */ , $arg ) = each( $this->preparedArgs );
                switch( $matches[1] ) {
                        case '?': return $this->addQuotes( $arg );
                        case '!': return $arg;
@@ -765,8 +881,8 @@ class Database {
         */
        function fetchObject( $res ) {
                @/**/$row = mysql_fetch_object( $res );
-               if( mysql_errno() ) {
-                       throw new DBUnexpectedError( $this, 'Error in fetchObject(): ' . htmlspecialchars( mysql_error() ) );
+               if( $this->lastErrno() ) {
+                       throw new DBUnexpectedError( $this, 'Error in fetchObject(): ' . htmlspecialchars( $this->lastError() ) );
                }
                return $row;
        }
@@ -777,8 +893,8 @@ class Database {
         */
        function fetchRow( $res ) {
                @/**/$row = mysql_fetch_array( $res );
-               if (mysql_errno() ) {
-                       throw new DBUnexpectedError( $this, 'Error in fetchRow(): ' . htmlspecialchars( mysql_error() ) );
+               if ( $this->lastErrno() ) {
+                       throw new DBUnexpectedError( $this, 'Error in fetchRow(): ' . htmlspecialchars( $this->lastError() ) );
                }
                return $row;
        }
@@ -788,8 +904,8 @@ class Database {
         */
        function numRows( $res ) {
                @/**/$n = mysql_num_rows( $res );
-               if( mysql_errno() ) {
-                       throw new DBUnexpectedError( $this, 'Error in numRows(): ' . htmlspecialchars( mysql_error() ) );
+               if( $this->lastErrno() ) {
+                       throw new DBUnexpectedError( $this, 'Error in numRows(): ' . htmlspecialchars( $this->lastError() ) );
                }
                return $n;
        }
@@ -916,7 +1032,7 @@ class Database {
         * @return array
         */
        function makeSelectOptions( $options ) {
-               $tailOpts = '';
+               $preLimitTail = $postLimitTail = '';
                $startOpts = '';
 
                $noKeyOptions = array();
@@ -926,19 +1042,21 @@ class Database {
                        }
                }
 
-               if ( isset( $options['GROUP BY'] ) ) $tailOpts .= " GROUP BY {$options['GROUP BY']}";
-               if ( isset( $options['ORDER BY'] ) ) $tailOpts .= " ORDER BY {$options['ORDER BY']}";
+               if ( isset( $options['GROUP BY'] ) ) $preLimitTail .= " GROUP BY {$options['GROUP BY']}";
+               if ( isset( $options['ORDER BY'] ) ) $preLimitTail .= " ORDER BY {$options['ORDER BY']}";
                
-               if (isset($options['LIMIT'])) {
-                       $tailOpts .= $this->limitResult('', $options['LIMIT'],
-                               isset($options['OFFSET']) ? $options['OFFSET'] : false);
-               }
-
-               if ( isset( $noKeyOptions['FOR UPDATE'] ) ) $tailOpts .= ' FOR UPDATE';
-               if ( isset( $noKeyOptions['LOCK IN SHARE MODE'] ) ) $tailOpts .= ' LOCK IN SHARE MODE';
+               //if (isset($options['LIMIT'])) {
+               //      $tailOpts .= $this->limitResult('', $options['LIMIT'],
+               //              isset($options['OFFSET']) ? $options['OFFSET'] 
+               //              : false);
+               //}
+
+               if ( isset( $noKeyOptions['FOR UPDATE'] ) ) $postLimitTail .= ' FOR UPDATE';
+               if ( isset( $noKeyOptions['LOCK IN SHARE MODE'] ) ) $postLimitTail .= ' LOCK IN SHARE MODE';
                if ( isset( $noKeyOptions['DISTINCT'] ) && isset( $noKeyOptions['DISTINCTROW'] ) ) $startOpts .= 'DISTINCT';
 
                # Various MySQL extensions
+               if ( isset( $noKeyOptions['STRAIGHT_JOIN'] ) ) $startOpts .= ' /*! STRAIGHT_JOIN */';
                if ( isset( $noKeyOptions['HIGH_PRIORITY'] ) ) $startOpts .= ' HIGH_PRIORITY';
                if ( isset( $noKeyOptions['SQL_BIG_RESULT'] ) ) $startOpts .= ' SQL_BIG_RESULT';
                if ( isset( $noKeyOptions['SQL_BUFFER_RESULT'] ) ) $startOpts .= ' SQL_BUFFER_RESULT';
@@ -953,11 +1071,19 @@ class Database {
                        $useIndex = '';
                }
                
-               return array( $startOpts, $useIndex, $tailOpts );
+               return array( $startOpts, $useIndex, $preLimitTail, $postLimitTail );
        }
 
        /**
         * SELECT wrapper
+        *
+        * @param mixed  $table   Array or string, table name(s) (prefix auto-added)
+        * @param mixed  $vars    Array or string, field name(s) to be retrieved
+        * @param mixed  $conds   Array or string, condition(s) for WHERE
+        * @param string $fname   Calling function name (use __METHOD__) for logs/profiling
+        * @param array  $options Associative array of options (e.g. array('GROUP BY' => 'page_title')),
+        *                        see Database::makeSelectOptions code for list of supported stuff
+        * @return mixed Database result resource (feed to Database::fetchObject or whatever), or false on failure
         */
        function select( $table, $vars, $conds='', $fname = 'Database::select', $options = array() )
        {
@@ -968,27 +1094,36 @@ class Database {
                        $options = array( $options );
                }
                if( is_array( $table ) ) {
-                       if ( @is_array( $options['USE INDEX'] ) )
+                       if ( isset( $options['USE INDEX'] ) && is_array( $options['USE INDEX'] ) )
                                $from = ' FROM ' . $this->tableNamesWithUseIndex( $table, $options['USE INDEX'] );
                        else
                                $from = ' FROM ' . implode( ',', array_map( array( &$this, 'tableName' ), $table ) );
                } elseif ($table!='') {
-                       $from = ' FROM ' . $this->tableName( $table );
+                       if ($table{0}==' ') {
+                               $from = ' FROM ' . $table;
+                       } else {
+                               $from = ' FROM ' . $this->tableName( $table );
+                       }
                } else {
                        $from = '';
                }
 
-               list( $startOpts, $useIndex, $tailOpts ) = $this->makeSelectOptions( $options );
+               list( $startOpts, $useIndex, $preLimitTail, $postLimitTail ) = $this->makeSelectOptions( $options );
 
                if( !empty( $conds ) ) {
                        if ( is_array( $conds ) ) {
                                $conds = $this->makeList( $conds, LIST_AND );
                        }
-                       $sql = "SELECT $startOpts $vars $from $useIndex WHERE $conds $tailOpts";
+                       $sql = "SELECT $startOpts $vars $from $useIndex WHERE $conds $preLimitTail";
                } else {
-                       $sql = "SELECT $startOpts $vars $from $useIndex $tailOpts";
+                       $sql = "SELECT $startOpts $vars $from $useIndex $preLimitTail";
                }
 
+               if (isset($options['LIMIT']))
+                       $sql = $this->limitResult($sql, $options['LIMIT'],
+                               isset($options['OFFSET']) ? $options['OFFSET'] : false);
+               $sql = "$sql $postLimitTail";
+
                return $this->query( $sql, $fname );
        }
 
@@ -1040,7 +1175,7 @@ class Database {
                $sql = preg_replace ('/".*"/s', "'X'", $sql);
 
                # All newlines, tabs, etc replaced by single space
-               $sql = preg_replace ( "/\s+/", ' ', $sql);
+               $sql = preg_replace ( '/\s+/', ' ', $sql);
 
                # All numbers => N
                $sql = preg_replace ('/-?[0-9]+/s', 'N', $sql);
@@ -1101,12 +1236,15 @@ class Database {
                        return NULL;
                }
 
+               $result = array();
                while ( $row = $this->fetchObject( $res ) ) {
                        if ( $row->Key_name == $index ) {
-                               return $row;
+                               $result[] = $row;
                        }
                }
-               return false;
+               $this->freeResult($res);
+               
+               return empty($result) ? false : $result;
        }
 
        /**
@@ -1139,7 +1277,7 @@ class Database {
                for( $i = 0; $i < $n; $i++ ) {
                        $meta = mysql_fetch_field( $res, $i );
                        if( $field == $meta->name ) {
-                               return $meta;
+                               return new MySQLField($meta);
                        }
                }
                return false;
@@ -1160,7 +1298,7 @@ class Database {
                if ( !$indexInfo ) {
                        return NULL;
                }
-               return !$indexInfo->Non_unique;
+               return !$indexInfo[0]->Non_unique;
        }
 
        /**
@@ -1250,7 +1388,7 @@ class Database {
        }
 
        /**
-        * Makes a wfStrencoded list from an array
+        * Makes an encoded list of strings from an array
         * $mode:
         *        LIST_COMMA         - comma separated, no field names
         *        LIST_AND           - ANDed WHERE clause (without the WHERE)
@@ -1279,6 +1417,8 @@ class Database {
                        }
                        if ( ($mode == LIST_AND || $mode == LIST_OR) && is_numeric( $field ) ) {
                                $list .= "($value)";
+                       } elseif ( ($mode == LIST_SET) && is_numeric( $field ) ) {
+                               $list .= "$value";
                        } elseif ( ($mode == LIST_AND || $mode == LIST_OR) && is_array ($value) ) {
                                $list .= $field." IN (".$this->makeList($value).") ";
                        } else {
@@ -1337,7 +1477,7 @@ class Database {
         * $sql = "SELECT wl_namespace,wl_title FROM $watchlist,$user
         *         WHERE wl_user=user_id AND wl_user=$nameWithQuotes";
         */
-       function tableNames() {
+       public function tableNames() {
                $inArray = func_get_args();
                $retVal = array();
                foreach ( $inArray as $name ) {
@@ -1345,6 +1485,24 @@ class Database {
                }
                return $retVal;
        }
+       
+       /**
+        * Fetch a number of table names into an zero-indexed numerical array
+        * This is handy when you need to construct SQL for joins
+        *
+        * Example:
+        * list( $user, $watchlist ) = $dbr->tableNames('user','watchlist');
+        * $sql = "SELECT wl_namespace,wl_title FROM $watchlist,$user
+        *         WHERE wl_user=user_id AND wl_user=$nameWithQuotes";
+        */
+       public function tableNamesN() {
+               $inArray = func_get_args();
+               $retVal = array();
+               foreach ( $inArray as $name ) {
+                       $retVal[] = $this->tableName( $name );
+               }
+               return $retVal;
+       }
 
        /**
         * @private
@@ -1367,7 +1525,7 @@ class Database {
         * @return string slashed string.
         */
        function strencode( $s ) {
-               return addslashes( $s );
+               return mysql_real_escape_string( $s, $this->mConn );
        }
 
        /**
@@ -1486,7 +1644,8 @@ class Database {
                $row = $this->fetchObject( $res );
                $this->freeResult( $res );
 
-               if ( preg_match( "/\((.*)\)/", $row->Type, $m ) ) {
+               $m = array();
+               if ( preg_match( '/\((.*)\)/', $row->Type, $m ) ) {
                        $size = $m[1];
                } else {
                        $size = -1;
@@ -1787,7 +1946,7 @@ class Database {
         * @return string Version information from the database
         */
        function getServerVersion() {
-               return mysql_get_server_info();
+               return mysql_get_server_info( $this->mConn );
        }
 
        /**
@@ -1810,7 +1969,6 @@ class Database {
                $res = $this->query( 'SHOW PROCESSLIST' );
                # Find slave SQL thread. Assumed to be the second one running, which is a bit
                # dubious, but unfortunately there's no easy rigorous way
-               $slaveThreads = 0;
                while ( $row = $this->fetchObject( $res ) ) {
                        /* This should work for most situations - when default db 
                         * for thread is not specified, it had no events executed, 
@@ -1859,6 +2017,22 @@ class Database {
                return $b;
        }
 
+       function decodeBlob($b) {
+               return $b;
+       }
+
+       /**
+        * Override database's default connection timeout.
+        * May be useful for very long batch queries such as
+        * full-wiki dumps, where a single query reads out
+        * over hours or days.
+        * @param int $timeout in seconds
+        */
+       public function setTimeout( $timeout ) {
+               $this->query( "SET net_read_timeout=$timeout" );
+               $this->query( "SET net_write_timeout=$timeout" );
+       }
+
        /**
         * Read and execute SQL commands from a file.
         * Returns true on success, error string on failure
@@ -1866,7 +2040,7 @@ class Database {
        function sourceFile( $filename ) {
                $fp = fopen( $filename, 'r' );
                if ( false === $fp ) {
-                       return "Could not open \"{$fname}\".\n";
+                       return "Could not open \"{$filename}\".\n";
                }
 
                $cmd = "";
@@ -1931,7 +2105,7 @@ class Database {
                // Ordinary variables
                foreach ( $varnames as $var ) {
                        if( isset( $GLOBALS[$var] ) ) {
-                               $val = addslashes( $GLOBALS[$var] );
+                               $val = addslashes( $GLOBALS[$var] ); // FIXME: safety check?
                                $ins = str_replace( '{$' . $var . '}', $val, $ins );
                                $ins = str_replace( '/*$' . $var . '*/`', '`' . $val, $ins );
                                $ins = str_replace( '/*$' . $var . '*/', $val, $ins );
@@ -1958,7 +2132,6 @@ class Database {
  * Database abstraction object for mySQL
  * Inherit all methods and properties of Database::Database()
  *
- * @package MediaWiki
  * @see Database
  */
 class DatabaseMysql extends Database {
@@ -1969,7 +2142,6 @@ class DatabaseMysql extends Database {
 /**
  * Result wrapper for grabbing data queried by someone else
  *
- * @package MediaWiki
  */
 class ResultWrapper {
        var $db, $result;
@@ -2015,6 +2187,12 @@ class ResultWrapper {
        function seek( $row ) {
                $this->db->dataSeek( $this->result, $row );
        }
+       
+       function rewind() {
+               if ($this->numRows()) {
+                       $this->db->dataSeek($this->result, 0);
+               }
+       }
 
 }