initial import from onelab svn codebase
[plewww.git] / includes / database.mysql.inc
1 <?php
2 // $Id: database.mysql.inc 144 2007-03-28 07:52:20Z thierry $
3
4 /**
5  * @file
6  * Database interface code for MySQL database servers.
7  */
8
9 /**
10  * @ingroup database
11  * @{
12  */
13
14 /**
15  * Initialize a database connection.
16  *
17  * Note that you can change the mysql_connect() call to mysql_pconnect() if you
18  * want to use persistent connections. This is not recommended on shared hosts,
19  * and might require additional database/webserver tuning. It can increase
20  * performance, however, when the overhead to connect to your database is high
21  * (e.g. your database and web server live on different machines).
22  */
23 function db_connect($url) {
24   // Check if MySQL support is present in PHP
25   if (!function_exists('mysql_connect')) {
26     drupal_maintenance_theme();
27     drupal_set_title('PHP MySQL support not enabled');
28     print theme('maintenance_page', '<p>We were unable to use the MySQL database because the MySQL extension for PHP is not installed. Check your <code>PHP.ini</code> to see how you can enable it.</p>
29 <p>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.</p>');
30     exit;
31   }
32
33   $url = db_parse_url($url);
34
35   // Decode url-encoded information in the db connection string
36   $url['user'] = urldecode($url['user']);
37   $url['pass'] = urldecode($url['pass']);
38   $url['host'] = urldecode($url['host']);
39   $url['path'] = urldecode($url['path']);
40
41   // Allow for non-standard MySQL port.
42   if (isset($url['port'])) {
43      $url['host'] = $url['host'] .':'. $url['port'];
44   }
45
46   // - TRUE makes mysql_connect() always open a new link, even if
47   //   mysql_connect() was called before with the same parameters.
48   //   This is important if you are using two databases on the same
49   //   server.
50   // - 2 means CLIENT_FOUND_ROWS: return the number of found
51   //   (matched) rows, not the number of affected rows.
52   $connection = @mysql_connect($url['host'], $url['user'], $url['pass'], TRUE, 2);
53   if (!$connection) {
54     drupal_maintenance_theme();
55     drupal_set_title('Unable to connect to database server');
56     print theme('maintenance_page', '<p>This either means that the username and password information in your <code>settings.php</code> file is incorrect or we can\'t contact the MySQL database server. This could mean your hosting provider\'s database server is down.</p>
57 <p>The MySQL error was: '. theme('placeholder', mysql_error()) .'.</p>
58 <p>Currently, the username is '. theme('placeholder', $url['user']) .' and the database server is '. theme('placeholder', $url['host']) .'.</p>
59 <ul>
60   <li>Are you sure you have the correct username and password?</li>
61   <li>Are you sure that you have typed the correct hostname?</li>
62   <li>Are you sure that the database server is running?</li>
63 </ul>
64 <p>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.</p>');
65     exit;
66   }
67
68   if (!mysql_select_db(substr($url['path'], 1))) {
69     drupal_maintenance_theme();
70     drupal_set_title('Unable to select database');
71     print theme('maintenance_page', '<p>We were able to connect to the MySQL database server (which means your username and password are okay) but not able to select the database.</p>
72 <p>The MySQL error was: '. theme('placeholder', mysql_error($connection)) .'.</p>
73 <p>Currently, the database is '. theme('placeholder', substr($url['path'], 1)) .'. The username is '. theme('placeholder', $url['user']) .' and the database server is '. theme('placeholder', $url['host']) .'.</p>
74 <ul>
75   <li>Are you sure you have the correct database name?</li>
76   <li>Are you sure the database exists?</li>
77   <li>Are you sure the username has permission to access the database?</li>
78 </ul>
79 <p>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.</p>');
80     exit;
81   }
82
83   /* On MySQL 4.1 and later, force UTF-8 */
84   if (version_compare(mysql_get_server_info(), '4.1.0', '>=')) {
85     mysql_query('SET NAMES "utf8"', $connection);
86   }
87   return $connection;
88 }
89
90 /**
91  * Helper function for db_query().
92  */
93 function _db_query($query, $debug = 0) {
94   global $active_db, $queries;
95
96   if (variable_get('dev_query', 0)) {
97     list($usec, $sec) = explode(' ', microtime());
98     $timer = (float)$usec + (float)$sec;
99   }
100
101   $result = mysql_query($query, $active_db);
102
103   if (variable_get('dev_query', 0)) {
104     $bt = debug_backtrace();
105     $query = $bt[2]['function'] . "\n" . $query;
106     list($usec, $sec) = explode(' ', microtime());
107     $stop = (float)$usec + (float)$sec;
108     $diff = $stop - $timer;
109     $queries[] = array($query, $diff);
110   }
111
112   if ($debug) {
113     print '<p>query: '. $query .'<br />error:'. mysql_error($active_db) .'</p>';
114   }
115
116   if (!mysql_errno($active_db)) {
117     return $result;
118   }
119   else {
120     trigger_error(check_plain(mysql_error($active_db) ."\nquery: ". $query), E_USER_WARNING);
121     return FALSE;
122   }
123 }
124
125 /**
126  * Fetch one result row from the previous query as an object.
127  *
128  * @param $result
129  *   A database query result resource, as returned from db_query().
130  * @return
131  *   An object representing the next row of the result. The attributes of this
132  *   object are the table fields selected by the query.
133  */
134 function db_fetch_object($result) {
135   if ($result) {
136     return mysql_fetch_object($result);
137   }
138 }
139
140 /**
141  * Fetch one result row from the previous query as an array.
142  *
143  * @param $result
144  *   A database query result resource, as returned from db_query().
145  * @return
146  *   An associative array representing the next row of the result. The keys of
147  *   this object are the names of the table fields selected by the query, and
148  *   the values are the field values for this result row.
149  */
150 function db_fetch_array($result) {
151   if ($result) {
152     return mysql_fetch_array($result, MYSQL_ASSOC);
153   }
154 }
155
156 /**
157  * Determine how many result rows were found by the preceding query.
158  *
159  * @param $result
160  *   A database query result resource, as returned from db_query().
161  * @return
162  *   The number of result rows.
163  */
164 function db_num_rows($result) {
165   if ($result) {
166     return mysql_num_rows($result);
167   }
168 }
169
170 /**
171  * Return an individual result field from the previous query.
172  *
173  * Only use this function if exactly one field is being selected; otherwise,
174  * use db_fetch_object() or db_fetch_array().
175  *
176  * @param $result
177  *   A database query result resource, as returned from db_query().
178  * @param $row
179  *   The index of the row whose result is needed.
180  * @return
181  *   The resulting field.
182  */
183 function db_result($result, $row = 0) {
184   if ($result && mysql_num_rows($result) > $row) {
185     return mysql_result($result, $row);
186   }
187 }
188
189 /**
190  * Determine whether the previous query caused an error.
191  */
192 function db_error() {
193   global $active_db;
194   return mysql_errno($active_db);
195 }
196
197 /**
198  * Return a new unique ID in the given sequence.
199  *
200  * For compatibility reasons, Drupal does not use auto-numbered fields in its
201  * database tables. Instead, this function is used to return a new unique ID
202  * of the type requested. If necessary, a new sequence with the given name
203  * will be created.
204  */
205 function db_next_id($name) {
206   $name = db_prefix_tables($name);
207   db_query('LOCK TABLES {sequences} WRITE');
208   $id = db_result(db_query("SELECT id FROM {sequences} WHERE name = '%s'", $name)) + 1;
209   db_query("REPLACE INTO {sequences} VALUES ('%s', %d)", $name, $id);
210   db_query('UNLOCK TABLES');
211
212   return $id;
213 }
214
215 /**
216  * Determine the number of rows changed by the preceding query.
217  */
218 function db_affected_rows() {
219   global $active_db;
220   return mysql_affected_rows($active_db);
221 }
222
223 /**
224  * Runs a limited-range query in the active database.
225  *
226  * Use this as a substitute for db_query() when a subset of the query is to be
227  * returned.
228  * User-supplied arguments to the query should be passed in as separate parameters
229  * so that they can be properly escaped to avoid SQL injection attacks.
230  *
231  * Note that if you need to know how many results were returned, you should do
232  * a SELECT COUNT(*) on the temporary table afterwards. db_num_rows() and
233  * db_affected_rows() do not give consistent result across different database
234  * types in this case.
235  *
236  * @param $query
237  *   A string containing an SQL query.
238  * @param ...
239  *   A variable number of arguments which are substituted into the query
240  *   using printf() syntax. The query arguments can be enclosed in one
241  *   array instead.
242  *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose
243  *   in '') and %%.
244  *
245  *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
246  *   and TRUE values to decimal 1.
247  *
248  * @param $from
249  *   The first result row to return.
250  * @param $count
251  *   The maximum number of result rows to return.
252  * @return
253  *   A database query result resource, or FALSE if the query was not executed
254  *   correctly.
255  */
256 function db_query_range($query) {
257   $args = func_get_args();
258   $count = array_pop($args);
259   $from = array_pop($args);
260   array_shift($args);
261
262   $query = db_prefix_tables($query);
263   if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
264     $args = $args[0];
265   }
266   _db_query_callback($args, TRUE);
267   $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
268   $query .= ' LIMIT '. (int)$from .', '. (int)$count;
269   return _db_query($query);
270 }
271
272 /**
273  * Runs a SELECT query and stores its results in a temporary table.
274  *
275  * Use this as a substitute for db_query() when the results need to stored
276  * in a temporary table. Temporary tables exist for the duration of the page
277  * request.
278  * User-supplied arguments to the query should be passed in as separate parameters
279  * so that they can be properly escaped to avoid SQL injection attacks.
280  *
281  * Note that if you need to know how many results were returned, you should do
282  * a SELECT COUNT(*) on the temporary table afterwards. db_num_rows() and
283  * db_affected_rows() do not give consistent result across different database
284  * types in this case.
285  *
286  * @param $query
287  *   A string containing a normal SELECT SQL query.
288  * @param ...
289  *   A variable number of arguments which are substituted into the query
290  *   using printf() syntax. The query arguments can be enclosed in one
291  *   array instead.
292  *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose
293  *   in '') and %%.
294  *
295  *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
296  *   and TRUE values to decimal 1.
297  *
298  * @param $table
299  *   The name of the temporary table to select into. This name will not be
300  *   prefixed as there is no risk of collision.
301  * @return
302  *   A database query result resource, or FALSE if the query was not executed
303  *   correctly.
304  */
305 function db_query_temporary($query) {
306   $args = func_get_args();
307   $tablename = array_pop($args);
308   array_shift($args);
309
310   $query = preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE '. $tablename .' SELECT', db_prefix_tables($query));
311   if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
312     $args = $args[0];
313   }
314   _db_query_callback($args, TRUE);
315   $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
316   return _db_query($query);
317 }
318
319 /**
320  * Returns a properly formatted Binary Large OBject value.
321  *
322  * @param $data
323  *   Data to encode.
324  * @return
325  *  Encoded data.
326  */
327 function db_encode_blob($data) {
328   global $active_db;
329   return "'" . mysql_real_escape_string($data, $active_db) . "'";
330 }
331
332 /**
333  * Returns text from a Binary Large Object value.
334  *
335  * @param $data
336  *   Data to decode.
337  * @return
338  *  Decoded data.
339  */
340 function db_decode_blob($data) {
341   return $data;
342 }
343
344 /**
345  * Prepare user input for use in a database query, preventing SQL injection attacks.
346  */
347 function db_escape_string($text) {
348   global $active_db;
349   return mysql_real_escape_string($text, $active_db);
350 }
351
352 /**
353  * Lock a table.
354  */
355 function db_lock_table($table) {
356   db_query('LOCK TABLES {'. db_escape_table($table) .'} WRITE');
357 }
358
359 /**
360  * Unlock all locked tables.
361  */
362 function db_unlock_tables() {
363   db_query('UNLOCK TABLES');
364 }
365
366 /**
367  * @} End of "ingroup database".
368  */
369
370