Aleksander Machniak
2016-05-16 0b7e26c1bf6bc7a684eb3a214d92d3927306cd8a
commit | author | age
0d94fd 1 <?php
AM 2
a95874 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     {
0ee572 121         $result = parent::dsn_options($dsn);
c2b20f 122
AM 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     /**
48d018 153      * Returns list of tables in a database
AM 154      *
155      * @return array List of all tables of the current database
156      */
157     public function list_tables()
158     {
159         // get tables if not cached
160         if ($this->tables === null) {
161             // first fetch current database name
162             $d = $this->query("SELECT database()");
163             $d = $this->fetch_array($d);
164
165             // get list of tables in current database
166             $q = $this->query("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES"
167                 . " WHERE TABLE_SCHEMA = ? AND TABLE_TYPE = 'BASE TABLE'"
168                 . " ORDER BY TABLE_NAME", $d ? $d[0] : '');
169
170             $this->tables = $q ? $q->fetchAll(PDO::FETCH_COLUMN, 0) : array();
171         }
172
173         return $this->tables;
174     }
175
176     /**
c389a8 177      * Get database runtime variables
AM 178      *
3d231c 179      * @param string $varname Variable name
AM 180      * @param mixed  $default Default value if variable is not set
c389a8 181      *
AM 182      * @return mixed Variable value or default
183      */
184     public function get_variable($varname, $default = null)
185     {
186         if (!isset($this->variables)) {
187             $this->variables = array();
188         }
189
c7b77b 190         if (array_key_exists($varname, $this->variables)) {
AM 191             return $this->variables[$varname];
192         }
193
8f4854 194         // configured value has higher prio
AM 195         $conf_value = rcube::get_instance()->config->get('db_' . $varname);
196         if ($conf_value !== null) {
197             return $this->variables[$varname] = $conf_value;
198         }
199
c7b77b 200         $result = $this->query('SHOW VARIABLES LIKE ?', $varname);
AM 201
202         while ($row = $this->fetch_array($result)) {
203             $this->variables[$row[0]] = $row[1];
204         }
205
206         // not found, use default
207         if (!isset($this->variables[$varname])) {
208             $this->variables[$varname] = $default;
209         }
210
211         return $this->variables[$varname];
c389a8 212     }
AM 213
0ee22c 214     /**
TB 215      * Handle DB errors, re-issue the query on deadlock errors from InnoDB row-level locking
216      *
217      * @param string Query that triggered the error
218      * @return mixed Result to be stored and returned
219      */
220     protected function handle_error($query)
221     {
222         $error = $this->dbh->errorInfo();
223
224         // retry after "Deadlock found when trying to get lock" errors
225         $retries = 2;
226         while ($error[1] == 1213 && $retries >= 0) {
227             usleep(50000);  // wait 50 ms
228             $result = $this->dbh->query($query);
229             if ($result !== false) {
230                 return $result;
231             }
232             $error = $this->dbh->errorInfo();
233             $retries--;
234         }
235
236         return parent::handle_error($query);
237     }
238
0d94fd 239 }