alecpl
2010-04-01 70318e5463986edff014e881e7e121483679726b
program/include/rcube_mdb2.php
@@ -5,7 +5,7 @@
 | program/include/rcube_mdb2.php                                        |
 |                                                                       |
 | This file is part of the RoundCube Webmail client                     |
 | Copyright (C) 2005-2008, RoundCube Dev. - Switzerland                 |
 | Copyright (C) 2005-2009, RoundCube Dev. - Switzerland                 |
 | Licensed under the GNU GPL                                            |
 |                                                                       |
 | PURPOSE:                                                              |
@@ -46,6 +46,8 @@
  var $a_query_results = array('dummy');
  var $last_res_id = 0;
  private $tables;
  /**
@@ -69,17 +71,6 @@
  /**
   * PHP 4 object constructor
   *
   * @see  rcube_mdb2::__construct
   */
  function rcube_db($db_dsnw,$db_dsnr='')
    {
    $this->__construct($db_dsnw,$db_dsnr);
    }
  /**
   * Connect to specific database
   *
   * @param  string  DSN for DB connections
@@ -89,12 +80,19 @@
  function dsn_connect($dsn)
    {
    // Use persistent connections if available
    $dbh = MDB2::connect($dsn, array(
    $db_options = array(
        'persistent' => $this->db_pconn,
        'emulate_prepared' => $this->debug_mode,
        'debug' => $this->debug_mode,
        'debug_handler' => 'mdb2_debug_handler',
        'portability' => MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL));
        'portability' => MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL);
    if ($this->db_provider == 'pgsql') {
      $db_options['disable_smart_seqname'] = true;
      $db_options['seqname_format'] = '%s';
    }
    $dbh = MDB2::connect($dsn, $db_options);
    if (MDB2::isError($dbh))
      {
@@ -110,7 +108,7 @@
      if (!filesize($dsn_array['database']) && !empty($this->sqlite_initials))
        $this->_sqlite_create_database($dbh, $this->sqlite_initials);
      }
    else
    else if ($this->db_provider!='mssql' && $this->db_provider!='sqlsrv')
      $dbh->setCharset('utf8');
    return $dbh;
@@ -182,6 +180,17 @@
    
  /**
   * Connection state checker
   *
   * @param  boolean  True if in connected state
   */
  function is_connected()
    {
    return PEAR::isError($this->db_handle) ? false : true;
    }
  /**
   * Execute a SQL query
   *
   * @param  string  SQL query to execute
@@ -191,6 +200,9 @@
   */
  function query()
    {
    if (!$this->is_connected())
      return NULL;
    $params = func_get_args();
    $query = array_shift($params);
@@ -232,7 +244,7 @@
  function _query($query, $offset, $numrows, $params)
    {
    // Read or write ?
    if (strtolower(trim(substr($query,0,6)))=='select')
    if (strtolower(substr(trim($query),0,6))=='select')
      $mode='r';
    else
      $mode='w';
@@ -246,18 +258,19 @@
      $result = $this->db_handle->setLimit($numrows,$offset);
    if (empty($params))
        $result = $this->db_handle->query($query);
      $result = $mode=='r' ? $this->db_handle->query($query) : $this->db_handle->exec($query);
    else
      {
      $params = (array)$params;
      $q = $this->db_handle->prepare($query);
      $q = $this->db_handle->prepare($query, null, $mode=='w' ? MDB2_PREPARE_MANIP : null);
      if ($this->db_handle->isError($q))
        {
        $this->db_error = TRUE;
        $this->db_error_msg = $q->userinfo;
        raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__,
                          'message' => $this->db_error_msg), TRUE, TRUE);
        raise_error(array('code' => 500, 'type' => 'db',
          'line' => __LINE__, 'file' => __FILE__,
          'message' => $this->db_error_msg), TRUE, TRUE);
        }
      else
        {
@@ -292,17 +305,18 @@
  /**
   * Get number of affected rows fort he last query
   * Get number of affected rows for the last query
   *
   * @param  number  Optional query handle identifier
   * @return mixed   Number of rows or FALSE on failure
   * @access public
   */
  function affected_rows($result = null)
  function affected_rows($res_id = null)
    {
    if (!$this->db_handle)
      return FALSE;
    return $this->_get_result($result);
    return (int) $this->_get_result($res_id);
    }
@@ -310,16 +324,27 @@
   * Get last inserted record ID
   * For Postgres databases, a sequence name is required
   *
   * @param  string  Sequence name for increment
   * @param  string  Table name (to find the incremented sequence)
   * @return mixed   ID or FALSE on failure
   * @access public
   */
  function insert_id($sequence = '')
  function insert_id($table = '')
    {
    if (!$this->db_handle || $this->db_mode=='r')
      return FALSE;
    return $this->db_handle->lastInsertID($sequence);
    if ($table) {
      if ($this->db_provider == 'pgsql')
        // find sequence name
        $table = get_sequence_name($table);
      else
        // resolve table name
        $table = get_table_name($table);
    }
    $id = $this->db_handle->lastInsertID($table);
    return $this->db_handle->isError($id) ? null : $id;
    }
@@ -354,7 +379,7 @@
  /**
   * Get co values for a result row
   * Get col values for a result row
   *
   * @param  object  Query result handle
   * @param  number  Fetch mode identifier
@@ -363,15 +388,31 @@
   */
  function _fetch_row($result, $mode)
    {
    if (PEAR::isError($result))
      {
      raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__,
                        'message' => $this->db_link->getMessage()), TRUE, FALSE);
    if ($result === FALSE || PEAR::isError($result) || !$this->is_connected())
      return FALSE;
      }
    return $result->fetchRow($mode);
    }
  /**
   * Wrapper for the SHOW TABLES command
   *
   * @return array List of all tables of the current database
   */
  function list_tables()
  {
    // get tables if not cached
    if (!$this->tables) {
      $this->db_handle->loadModule('Manager');
      if (!PEAR::isError($result = $this->db_handle->listTables()))
        $this->tables = $result;
      else
        $this->tables = array();
    }
    return $this->tables;
  }
  /**
@@ -402,13 +443,13 @@
   * @param  string  Value to quote
   * @return string  Quoted string for use in query
   * @deprecated     Replaced by rcube_MDB2::quote_identifier
   * @see            rcube_MDB2::quote_identifier
   * @see            rcube_mdb2::quote_identifier
   * @access public
   */
  function quoteIdentifier($str)
   {
    {
    return $this->quote_identifier($str);
   }
    }
  /**
@@ -454,11 +495,32 @@
    switch($this->db_provider)
      {
      case 'mssql':
      case 'sqlsrv':
        return "getdate()";
      default:
        return "now()";
      }
    }
  /**
   * Return list of elements for use with SQL's IN clause
   *
   * @param  string Input array
   * @return string Elements list string
   * @access public
   */
  function array2list($arr, $type=null)
    {
    if (!is_array($arr))
      return $this->quote($arr, $type);
    $res = array();
    foreach ($arr as $item)
      $res[] = $this->quote($item, $type);
    return implode(',', $res);
    }
@@ -478,7 +540,8 @@
        break;
      case 'mssql':
        return "datediff(s, '1970-01-01 00:00:00', $field)";
      case 'sqlsrv':
   return "DATEDIFF(second, '19700101', $field) + DATEDIFF(second, GETDATE(), GETUTCDATE())";
      default:
        return "UNIX_TIMESTAMP($field)";
@@ -509,10 +572,79 @@
  /**
   * Return SQL statement for case insensitive LIKE
   *
   * @param  string  Field name
   * @param  string  Search value
   * @return string  SQL statement to use in query
   * @access public
   */
  function ilike($column, $value)
    {
    // TODO: use MDB2's matchPattern() function
    switch($this->db_provider)
      {
      case 'pgsql':
        return $this->quote_identifier($column).' ILIKE '.$this->quote($value);
      default:
        return $this->quote_identifier($column).' LIKE '.$this->quote($value);
      }
    }
  /**
   * Encodes non-UTF-8 characters in string/array/object (recursive)
   *
   * @param  mixed  Data to fix
   * @return mixed  Properly UTF-8 encoded data
   * @access public
   */
  function encode($input)
    {
    if (is_object($input)) {
      foreach (get_object_vars($input) as $idx => $value)
        $input->$idx = $this->encode($value);
      return $input;
      }
    else if (is_array($input)) {
      foreach ($input as $idx => $value)
        $input[$idx] = $this->encode($value);
      return $input;
      }
    return utf8_encode($input);
    }
  /**
   * Decodes encoded UTF-8 string/object/array (recursive)
   *
   * @param  mixed  Input data
   * @return mixed  Decoded data
   * @access public
   */
  function decode($input)
    {
    if (is_object($input)) {
      foreach (get_object_vars($input) as $idx => $value)
        $input->$idx = $this->decode($value);
      return $input;
      }
    else if (is_array($input)) {
      foreach ($input as $idx => $value)
        $input[$idx] = $this->decode($value);
      return $input;
      }
    return utf8_decode($input);
    }
  /**
   * Adds a query result and returns a handle ID
   *
   * @param  object  Query handle
   * @return mixed   Handle ID or FALE on failure
   * @return mixed   Handle ID
   * @access private
   */
  function _add_result($res)
@@ -520,26 +652,28 @@
    // sql error occured
    if (PEAR::isError($res))
      {
      raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__,
                        'message' => $res->getMessage() . " Query: " . substr(preg_replace('/[\r\n]+\s*/', ' ', $res->userinfo), 0, 512)), TRUE, FALSE);
      return FALSE;
      $this->db_error = TRUE;
      $this->db_error_msg = $res->getMessage();
      raise_error(array('code' => 500, 'type' => 'db',
           'line' => __LINE__, 'file' => __FILE__,
           'message' => $res->getMessage() . " Query: "
       . substr(preg_replace('/[\r\n]+\s*/', ' ', $res->userinfo), 0, 512)),
       TRUE, FALSE);
      }
    else
      {
      $res_id = sizeof($this->a_query_results);
      $this->a_query_results[$res_id] = $res;
      $this->last_res_id = $res_id;
      return $res_id;
      }
    $res_id = sizeof($this->a_query_results);
    $this->last_res_id = $res_id;
    $this->a_query_results[$res_id] = $res;
    return $res_id;
    }
  /**
   * Resolves a given handle ID and returns the according query handle
   * If no ID is specified, the last ressource handle will be returned
   * If no ID is specified, the last resource handle will be returned
   *
   * @param  number  Handle ID
   * @return mixed   Ressource handle or FALE on failure
   * @return mixed   Resource handle or FALSE on failure
   * @access private
   */
  function _get_result($res_id=NULL)
@@ -547,10 +681,11 @@
    if ($res_id==NULL)
      $res_id = $this->last_res_id;
     if ($res_id && isset($this->a_query_results[$res_id]))
       return $this->a_query_results[$res_id];
     else
       return FALSE;
    if (isset($this->a_query_results[$res_id]))
      if (!PEAR::isError($this->a_query_results[$res_id]))
        return $this->a_query_results[$res_id];
    return FALSE;
    }
@@ -569,7 +704,9 @@
    $data = file_get_contents($file_name);
    if (strlen($data))
      sqlite_exec($dbh->connection, $data);
      if (!sqlite_exec($dbh->connection, $data, $error) || MDB2::isError($dbh))
        raise_error(array('code' => 500, 'type' => 'db',
       'line' => __LINE__, 'file' => __FILE__, 'message' => $error), TRUE, FALSE);
    }
@@ -601,8 +738,6 @@
  {
    $debug_output = $scope . '('.$db->db_index.'): ';
    $debug_output .= $message . $db->getOption('log_line_break');
    write_log('sqllog', $debug_output);
    write_log('sql', $debug_output);
  }
}