<?php
class MySQLConnection extends ConnectionCommon 
{
  /** Current database (used in mysql_select_db()). */
  private $database;

  /**
     * Connect to a database and log in as the specified user.
     *
     * @param $dsn the data source name (see DB::parseDSN for syntax)
     * @param $flags Any conneciton flags.
     * @access public
     * @throws Exception
     * @return void
     */
  function connect($dsninfo, $flags = 0)
  {
//    if (!extension_loaded('mysql')) {
//      throw new Exception('mysql extension not loaded');
//    }

    $this->dsn = $dsninfo;
    $this->flags = $flags;

    //$persistent = ($flags & Creole::PERSISTENT) === Creole::PERSISTENT;
    $persistent = $flags;

    if (isset($dsninfo['protocol']) && $dsninfo['protocol'] == 'unix') {
      $dbhost = ':' . $dsninfo['socket'];
    } else {
      $dbhost = $dsninfo['hostspec'] ? $dsninfo['hostspec'] : 'localhost';
      if (!empty($dsninfo['port'])) {
        $dbhost .= ':' . $dsninfo['port'];
      }
    }
    $user = $dsninfo['username'];
    $pw = $dsninfo['password'];

    $encoding = !empty($dsninfo['encoding']) ? $dsninfo['encoding'] : null;

    $connect_function = $persistent ? 'mysql_pconnect' : 'mysql_connect';

    @ini_set('track_errors', true);
    if ($dbhost && $user && $pw) {
      $conn = @$connect_function($dbhost, $user, $pw);
    } elseif ($dbhost && $user) {
      $conn = @$connect_function($dbhost, $user);
    } elseif ($dbhost) {
      $conn = @$connect_function($dbhost);
    } else {
      $conn = false;
    }
    @ini_restore('track_errors');
    if (empty($conn)) {
      if (($err = @mysql_error()) != '') {
        throw new Exception("connect failed", $err);
      } elseif (empty($php_errormsg)) {
        throw new Exception("connect failed");
      } else {
        throw new Exception("connect failed", $php_errormsg);
      }
    }

    if ($dsninfo['database']) {
      if (!@mysql_select_db($dsninfo['database'], $conn)) {
        switch(mysql_errno($conn)) {
          case 1049:
            $exc = new Exception("no such database", mysql_error($conn));
            break;
          case 1044:
            $exc = new Exception("access violation", mysql_error($conn));
            break;
          default:
            $exc = new Exception("cannot select database", mysql_error($conn));
        }

        throw $exc;

      }
      // fix to allow calls to different databases in the same script
      $this->database = $dsninfo['database'];
    }

    $this->dblink = $conn;

    if ($encoding) {
      $this->executeUpdate("SET NAMES " . $encoding);
    }
  }

  /**
     * @see Connection::disconnect()
     */
  function close()
  {
    $ret = mysql_close($this->dblink);
    $this->dblink = null;
    return $ret;
  }

  /**
     * @see Connection::applyLimit()
     */
  public function applyLimit(&$sql, $offset, $limit)
  {
    if ( $limit > 0 ) {
      $sql .= " LIMIT " . ($offset > 0 ? $offset . ", " : "") . $limit;
    } else if ( $offset > 0 ) {
      $sql .= " LIMIT " . $offset . ", 18446744073709551615";
    }
  }

  /**
     * @see Connection::executeQuery()
     */
  function executeQuery($sql, $fetchmode = null)
  {
    $this->lastQuery = $sql;
    if ($this->database) {
      if (!@mysql_select_db($this->database, $this->dblink)) {
        throw new Exception('No database selected', mysql_error($this->dblink));
      }
    }
    $result = @mysql_query($sql, $this->dblink);
    if (!$result) {
      throw new Exception('Could not execute query', mysql_error($this->dblink), $sql);
    }
    return new MySQLResultSet($this, $result, $fetchmode);
  }

  /**
     * @see Connection::executeUpdate()
     */
  function executeUpdate($sql)
  {
    $this->lastQuery = $sql;

    if ($this->database) {
      if (!@mysql_select_db($this->database, $this->dblink)) {
        throw new Exception('No database selected', mysql_error($this->dblink));
      }
    }

    $result = @mysql_query($sql, $this->dblink);
    if (!$result) {
      throw new Exception('Could not execute update', mysql_error($this->dblink), $sql);
    }
    return (int) mysql_affected_rows($this->dblink);
  }

  /**
     * Start a database transaction.
     * @throws Exception
     * @return void
     */
  protected function beginTrans()
  {
    $result = @mysql_query('SET AUTOCOMMIT=0', $this->dblink);
    $result = @mysql_query('BEGIN', $this->dblink);
    if (!$result) {
      throw new Exception('Could not begin transaction', mysql_error($this->dblink));
    }
  }

  /**
     * Commit the current transaction.
     * @throws Exception
     * @return void
     */
  protected function commitTrans()
  {
    if ($this->database) {
      if (!@mysql_select_db($this->database, $this->dblink)) {
        throw new Exception('No database selected', mysql_error($this->dblink));
      }
    }
    $result = @mysql_query('COMMIT', $this->dblink);
    $result = @mysql_query('SET AUTOCOMMIT=1', $this->dblink);
    if (!$result) {
      throw new Exception('Can not commit transaction', mysql_error($this->dblink));
    }
  }

  /**
     * Roll back (undo) the current transaction.
     * @throws Exception
     * @return void
     */
  protected function rollbackTrans()
  {
    if ($this->database) {
      if (!@mysql_select_db($this->database, $this->dblink)) {
        throw new Exception('No database selected', mysql_error($this->dblink));
      }
    }
    $result = @mysql_query('ROLLBACK', $this->dblink);
    $result = @mysql_query('SET AUTOCOMMIT=1', $this->dblink);
    if (!$result) {
      throw new Exception('Could not rollback transaction', mysql_error($this->dblink));
    }
  }

  /**
     * Gets the number of rows affected by the data manipulation
     * query.
     *
     * @return int Number of rows affected by the last query.
     */
  function getUpdateCount()
  {
    return (int) @mysql_affected_rows($this->dblink);
  }

}