<?php
////////////////////////////////////////////////////////////////////
class MySQLResultSet implements Iterator{
  //dane składowe
  private $strSQL;
  private $databasename;
  private $connection;
  private $result;
  private $valid;
  private $currentrow;
  private $key;
  //numery błędów zdefinowane przez programistę
  //wychodzące poza zakres błędów używanych przez MySQL
  const INDETERMINATE_TOTAL_NUMBER = 5001;
  const UNNECESSARY_SQL_CALC_FOUND_ROWS = 5002;
  const NOT_SELECT_QUERY = 5003;
////////////////////////////////////////////////////////////////////
//konstruktor
////////////////////////////////////////////////////////////////////
  public function __construct( $strSQL, $databasename, $connection ){
    $this->strSQL = $strSQL;
    $this->connection = $connection;
    $this->databasename = $databasename;
    if(!mysql_selectdb($databasename, $connection)){
      throw new MySQLException(mysql_error(), mysql_errno());
    }
    if(!$this->result = mysql_query($strSQL, $connection)){
      throw new MySQLException(mysql_error(), mysql_errno());
    }
    //sprawdza obecność SQL_CALC_FOUND_ROWS
    if (stristr($strSQL,"SQL_CALC_FOUND_ROWS")){
      $msg = "No need to use SQL_CALC_FOUND_ROWS.";
      throw new MySQLException($msg, self::UNNECESSARY_SQL_CALC_FOUND_ROWS);
    }
    //inicjuje wartości (niekoniecznie dla foreach)
    $this->rewind();
  }
////////////////////////////////////////////////////////////////////
//destruktor
////////////////////////////////////////////////////////////////////
  public function __destruct(){
    $this->close();
  }
////////////////////////////////////////////////////////////////////
// metody publiczne
////////////////////////////////////////////////////////////////////
  public function __call($name, $args){  
    $args = null;
    $name = "mysql_". $name;
    if(function_exists($name)){
      return call_user_func_array($name, $args);
       
    }  
  }
  public function getDatabaseName(){
    return $this->databasename;
  }
////////////////////////////////////////////////////////////////////
  public function getNumberColumns(){
    return mysql_num_fields($this->result);
  }
////////////////////////////////////////////////////////////////////
//wyłącznie dla zapytań SELECT
////////////////////////////////////////////////////////////////////
  public function getNumberRows(){
    return mysql_num_rows($this->result);
  }
////////////////////////////////////////////////////////////////////
  public function getInsertId(){
    return mysql_insert_id( $this->connection); 
  }
////////////////////////////////////////////////////////////////////
//Oblicza całkowitą liczbę rekordów, jeśli obecny jest warunek ograniczający
//Przydaje się w wyznaczaniu liczby stron w wersjach niższych niż 4
//Użycie DISTRICT daje niewiarygodne wyniki
////////////////////////////////////////////////////////////////////
  public function getUnlimitedNumberRows(){
    $number = 0;
    $versionnumber = $this->findVersionNumber();
    //potrzebna jedynie skrajna cyfra
    $version = substr($versionnumber,0,1);
    //CHECK SELECT
    if (!$this->checkForSelect()){
      $msg = "Nielegalne wywołanie metody - to nie jest zapytanie SELECT";
      throw new MySQLException($msg, self::NOT_SELECT_QUERY);
    }
    //sprawdza warunek ograniczający
    $tempsql = strtoupper($this->strSQL);
    $end = strpos($tempsql,"LIMIT");
    if ($end === false){ //bez warunku limit
      $number = mysql_num_rows($this->result);
    }
    elseif($version < 4){
      $number = $this->countVersionThree($end);
    }else{ //wersja 4 lub wyższa korzysta z funkcji SQL_CALC_FOUND_ROWS
      $number = $this->countVersionFour();
    }
    return $number;
  }
////////////////////////////////////////////////////////////////////
  public function getFieldNames(){
    $fieldnames = array();
    if(isset($this->result)){
      $num = mysql_numfields($this->result);
      for($i = 0; $i < $num; $i++){
        if (!$meta = mysql_fetch_field($this->result, $i)){
          throw new MySQLException(mysql_error(), mysql_errno());
        }else{
          $fieldnames[$i]= $meta->name;
        }
      }
    }
    return $fieldnames;
  }
////////////////////////////////////////////////////////////////////
  public function findVersionNumber(){
    //mysql_get_server_info
    return mysql_get_server_info($this->connection);
  }
////////////////////////////////////////////////////////////////////
//Metody Iteratora muszą zostać zaimplementowane
////////////////////////////////////////////////////////////////////
  public function current (){
    return $this->currentrow;
  }
////////////////////////////////////////////////////////////////////
  public function key (){
    return $this->key;
  }
////////////////////////////////////////////////////////////////////
  public function next (){
    if($this->currentrow = mysql_fetch_array($this->result)){
      $this->valid = true;
      $this->key++;
    }else{
      $this->valid = false;
    }
  }
////////////////////////////////////////////////////////////////////
  public function rewind (){
    if($num = mysql_num_rows($this->result) > 0){
      if(mysql_data_seek($this->result, 0)){
        $this->valid = true;
        $this->key = 0;
        $this->currentrow = mysql_fetch_array($this->result);
      }
    }else{
      $this->valid = false;
    } 
  }
////////////////////////////////////////////////////////////////////
 	public function valid (){
    return $this->valid;
  }
////////////////////////////////////////////////////////////////////
//metody prywatne
////////////////////////////////////////////////////////////////////  
  private function checkForSelect(){
    $bln = true;
    $strtemp = trim(strtoupper($this->strSQL));
    if(substr($strtemp,0,6)!= "SELECT"){
      $bln = false;
    }
    return $bln;  
  }
////////////////////////////////////////////////////////////////////
  private function close(){
    if(isset($this->result)){
      mysql_free_result($this->result);
      unset($this->result);
    }
  }
////////////////////////////////////////////////////////////////////  
  private function countVersionFour(){
    $tempsql = trim($this->strSQL);
    //wstawia SQL_CALC_FOUND_ROWS
    $insertstr = " SQL_CALC_FOUND_ROWS ";
    //już wie, że rozpoczyna się wyrażeniem "SELECT"
    $tempsql = substr_replace($tempsql, $insertstr, 6, 1);
    if(!$rs = mysql_query($tempsql, $this->connection)){
      throw new MySQLException(mysql_error(), mysql_errno());
    }
    $tempsql = "SELECT FOUND_ROWS()";
    if(!$rs = mysql_query($tempsql)){
      throw new MySQLException(mysql_error(), mysql_errno());
    }
    $row = mysql_fetch_row($rs);
    $number = $row[0];
    //dispose of $rs
    mysql_free_result($rs);
    return $number;
  }
////////////////////////////////////////////////////////////////////  
  private function countVersionThree($end){
    $tempsql = strtoupper($this->strSQL);
    //sprawdza DISTINCT - będzie odrzucać 
    if(!strpos($tempsql,"DISTINCT")){
      //tworzy zestaw zmiennych
      $start = strpos($tempsql,"FROM");
      $numchars = $end-$start;
      $countsql = "SELECT COUNT(*) ";
      $countsql .= substr($this->strSQL, $start, $numchars);
      if(!$rs=mysql_query($countsql, $this->connection)){
        throw new MySQLException( mysql_error(), mysql_errno());
      }
      $row = mysql_fetch_row($rs);
      $number = $row[0];
      //pozbywa się $rs
      mysql_free_result($rs);
    }else{
      $msg = "Korzystanie ze słowa kluczowego DISTINCT, ".
        "oblicza całkowitą liczbę ręcznie.";
      //misu użyć polecenia self - nie jest właściwością
      throw new MySQLException($msg, self::INDETERMINATE_TOTAL_NUMBER);
    }
    return $number;
  }
}//koniec klasy
?>
