Aleksander Machniak
2014-03-22 8cc567c00423a343f3b785ee4dd856111b985fe7
commit | author | age
0d94fd 1 <?php
AM 2
3d231c 3 /**
0d94fd 4  +-----------------------------------------------------------------------+
AM 5  | This file is part of the Roundcube Webmail client                     |
6  | Copyright (C) 2005-2012, The Roundcube Dev Team                       |
7  |                                                                       |
8  | Licensed under the GNU General Public License version 3 or            |
9  | any later version with exceptions for skins & plugins.                |
10  | See the README file for a full license statement.                     |
11  |                                                                       |
12  | PURPOSE:                                                              |
13  |   Database wrapper class that implements PHP PDO functions            |
14  |   for MySQL database                                                  |
15  +-----------------------------------------------------------------------+
16  | Author: Aleksander Machniak <alec@alec.pl>                            |
17  +-----------------------------------------------------------------------+
18 */
19
20 /**
21  * Database independent query interface
22  *
23  * This is a wrapper for the PHP PDO
24  *
9ab346 25  * @package    Framework
AM 26  * @subpackage Database
0d94fd 27  */
AM 28 class rcube_db_mysql extends rcube_db
29 {
88107d 30     public $db_provider = 'mysql';
TB 31
8c2375 32     /**
d18640 33      * Object constructor
AM 34      *
35      * @param string $db_dsnw DSN for read/write operations
36      * @param string $db_dsnr Optional DSN for read only operations
37      * @param bool   $pconn   Enables persistent connections
8c2375 38      */
d18640 39     public function __construct($db_dsnw, $db_dsnr = '', $pconn = false)
0d94fd 40     {
d18640 41         parent::__construct($db_dsnw, $db_dsnr, $pconn);
AM 42
0d94fd 43         // SQL identifiers quoting
AM 44         $this->options['identifier_start'] = '`';
45         $this->options['identifier_end'] = '`';
46     }
47
48     /**
d18640 49      * Driver-specific configuration of database connection
AM 50      *
51      * @param array $dsn DSN for DB connections
52      * @param PDO   $dbh Connection handler
53      */
54     protected function conn_configure($dsn, $dbh)
55     {
120db6 56         $dbh->query("SET NAMES 'utf8'");
d18640 57     }
AM 58
59     /**
0d94fd 60      * Abstract SQL statement for value concatenation
AM 61      *
62      * @return string SQL statement to be used in query
63      */
64     public function concat(/* col1, col2, ... */)
65     {
66         $args = func_get_args();
67
68         if (is_array($args[0])) {
69             $args = $args[0];
70         }
71
72         return 'CONCAT(' . join(', ', $args) . ')';
73     }
74
75     /**
8c2375 76      * Returns PDO DSN string from DSN array
c2b20f 77      *
AM 78      * @param array $dsn DSN parameters
79      *
80      * @return string Connection string
0d94fd 81      */
AM 82     protected function dsn_string($dsn)
83     {
84         $params = array();
85         $result = 'mysql:';
86
87         if ($dsn['database']) {
88             $params[] = 'dbname=' . $dsn['database'];
89         }
90
91         if ($dsn['hostspec']) {
92             $params[] = 'host=' . $dsn['hostspec'];
93         }
94
95         if ($dsn['port']) {
96             $params[] = 'port=' . $dsn['port'];
97         }
98
99         if ($dsn['socket']) {
100             $params[] = 'unix_socket=' . $dsn['socket'];
101         }
102
103         $params[] = 'charset=utf8';
104
105         if (!empty($params)) {
106             $result .= implode(';', $params);
107         }
108
109         return $result;
110     }
111
c389a8 112     /**
c2b20f 113      * Returns driver-specific connection options
AM 114      *
115      * @param array $dsn DSN parameters
116      *
117      * @return array Connection options
118      */
119     protected function dsn_options($dsn)
120     {
121         $result = array();
122
123         if (!empty($dsn['key'])) {
32c612 124             $result[PDO::MYSQL_ATTR_SSL_KEY] = $dsn['key'];
c2b20f 125         }
AM 126
127         if (!empty($dsn['cipher'])) {
32c612 128             $result[PDO::MYSQL_ATTR_SSL_CIPHER] = $dsn['cipher'];
c2b20f 129         }
AM 130
131         if (!empty($dsn['cert'])) {
132             $result[PDO::MYSQL_ATTR_SSL_CERT] = $dsn['cert'];
133         }
134
135         if (!empty($dsn['capath'])) {
136             $result[PDO::MYSQL_ATTR_SSL_CAPATH] = $dsn['capath'];
137         }
138
139         if (!empty($dsn['ca'])) {
140             $result[PDO::MYSQL_ATTR_SSL_CA] = $dsn['ca'];
141         }
142
f6cd73 143         // Always return matching (not affected only) rows count
AM 144         $result[PDO::MYSQL_ATTR_FOUND_ROWS] = true;
145
f96593 146         // Enable AUTOCOMMIT mode (#1488902)
3725cf 147         $result[PDO::ATTR_AUTOCOMMIT] = true;
f96593 148
c2b20f 149         return $result;
AM 150     }
151
152     /**
c389a8 153      * Get database runtime variables
AM 154      *
3d231c 155      * @param string $varname Variable name
AM 156      * @param mixed  $default Default value if variable is not set
c389a8 157      *
AM 158      * @return mixed Variable value or default
159      */
160     public function get_variable($varname, $default = null)
161     {
162         if (!isset($this->variables)) {
163             $this->variables = array();
164
165             $result = $this->query('SHOW VARIABLES');
166
c027ba 167             while ($row = $this->fetch_array($result)) {
c389a8 168                 $this->variables[$row[0]] = $row[1];
AM 169             }
170         }
171
172         return isset($this->variables[$varname]) ? $this->variables[$varname] : $default;
173     }
174
0ee22c 175     /**
TB 176      * Handle DB errors, re-issue the query on deadlock errors from InnoDB row-level locking
177      *
178      * @param string Query that triggered the error
179      * @return mixed Result to be stored and returned
180      */
181     protected function handle_error($query)
182     {
183         $error = $this->dbh->errorInfo();
184
185         // retry after "Deadlock found when trying to get lock" errors
186         $retries = 2;
187         while ($error[1] == 1213 && $retries >= 0) {
188             usleep(50000);  // wait 50 ms
189             $result = $this->dbh->query($query);
190             if ($result !== false) {
191                 return $result;
192             }
193             $error = $this->dbh->errorInfo();
194             $retries--;
195         }
196
197         return parent::handle_error($query);
198     }
199
0d94fd 200 }