| | |
| | | protected $db_connected = false; // Already connected ? |
| | | protected $db_mode; // Connection mode |
| | | protected $dbh; // Connection handle |
| | | protected $dbhs = array(); |
| | | |
| | | protected $db_error = false; |
| | | protected $db_error_msg = ''; |
| | |
| | | $this->db_dsnw = $db_dsnw; |
| | | $this->db_dsnr = $db_dsnr; |
| | | $this->db_pconn = $pconn; |
| | | $this->db_dsnw_noread = rcube::get_instance()->config->get('db_dsnw_noread', false); |
| | | |
| | | $this->db_dsnw_array = self::parse_dsn($db_dsnw); |
| | | $this->db_dsnr_array = self::parse_dsn($db_dsnr); |
| | |
| | | { |
| | | $this->db_error = false; |
| | | $this->db_error_msg = null; |
| | | |
| | | // return existing handle |
| | | if ($this->dbhs[$mode]) { |
| | | $this->dbh = $this->dbhs[$mode]; |
| | | $this->db_mode = $mode; |
| | | return $this->dbh; |
| | | } |
| | | |
| | | // Get database specific connection options |
| | | $dsn_string = $this->dsn_string($dsn); |
| | |
| | | } |
| | | |
| | | $this->dbh = $dbh; |
| | | $this->dbhs[$mode] = $dbh; |
| | | $this->db_mode = $mode; |
| | | $this->db_connected = true; |
| | | $this->conn_configure($dsn, $dbh); |
| | |
| | | |
| | | // Already connected |
| | | if ($this->db_connected) { |
| | | // connected to db with the same or "higher" mode |
| | | if ($this->db_mode == 'w' || $this->db_mode == $mode) { |
| | | // connected to db with the same or "higher" mode (if allowed) |
| | | if ($this->db_mode == $mode || $this->db_mode == 'w' && !$this->db_dsnw_noread) { |
| | | return; |
| | | } |
| | | } |
| | | |
| | | $dsn = ($mode == 'r') ? $this->db_dsnr_array : $this->db_dsnw_array; |
| | | |
| | | $this->dsn_connect($dsn, $mode); |
| | | |
| | | // use write-master when read-only fails |
| | |
| | | $result = $this->dbh->query($query); |
| | | |
| | | if ($result === false) { |
| | | $error = $this->dbh->errorInfo(); |
| | | |
| | | if (empty($this->options['ignore_key_errors']) || $error[0] != '23000') { |
| | | $this->db_error = true; |
| | | $this->db_error_msg = sprintf('[%s] %s', $error[1], $error[2]); |
| | | |
| | | rcube::raise_error(array('code' => 500, 'type' => 'db', |
| | | 'line' => __LINE__, 'file' => __FILE__, |
| | | 'message' => $this->db_error_msg . " (SQL Query: $query)" |
| | | ), true, false); |
| | | } |
| | | $result = $this->handle_error($query); |
| | | } |
| | | |
| | | $this->last_result = $result; |
| | | |
| | | return $result; |
| | | } |
| | | |
| | | /** |
| | | * Helper method to handle DB errors. |
| | | * This by default logs the error but could be overriden by a driver implementation |
| | | * |
| | | * @param string Query that triggered the error |
| | | * @return mixed Result to be stored and returned |
| | | */ |
| | | protected function handle_error($query) |
| | | { |
| | | $error = $this->dbh->errorInfo(); |
| | | |
| | | if (empty($this->options['ignore_key_errors']) || $error[0] != '23000') { |
| | | $this->db_error = true; |
| | | $this->db_error_msg = sprintf('[%s] %s', $error[1], $error[2]); |
| | | |
| | | rcube::raise_error(array('code' => 500, 'type' => 'db', |
| | | 'line' => __LINE__, 'file' => __FILE__, |
| | | 'message' => $this->db_error_msg . " (SQL Query: $query)" |
| | | ), true, false); |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | |
| | | if ($interval) { |
| | | $add = ' ' . ($interval > 0 ? '+' : '-') . ' INTERVAL '; |
| | | $add .= $interval > 0 ? intval($interval) : intval($interval) * -1; |
| | | $add .= ' SECONDS'; |
| | | $add .= ' SECOND'; |
| | | } |
| | | |
| | | return "now()" . $add; |