database.mysql.inc 10.2 KB
Newer Older
Dries's avatar
 
Dries committed
1
<?php
Kjartan's avatar
Kjartan committed
2
// $Id$
Dries's avatar
 
Dries committed
3

Dries's avatar
   
Dries committed
4
5
6
7
8
9
/**
 * @file
 * Database interface code for MySQL database servers.
 */

/**
Dries's avatar
   
Dries committed
10
 * @ingroup database
Dries's avatar
   
Dries committed
11
12
13
14
15
16
17
18
19
20
21
22
 * @{
 */

/**
 * Initialize a database connection.
 *
 * Note that you can change the mysql_connect() call to mysql_pconnect() if you
 * want to use persistent connections. This is not recommended on shared hosts,
 * and might require additional database/webserver tuning. It can increase
 * performance, however, when the overhead to connect to your database is high
 * (e.g. your database and web server live on different machines).
 */
Dries's avatar
 
Dries committed
23
24
25
function db_connect($url) {
  $url = parse_url($url);

26
  // Allow for non-standard MySQL port.
Dries's avatar
   
Dries committed
27
28
  if (isset($url['port'])) {
     $url['host'] = $url['host'] .':'. $url['port'];
29
  }
Dries's avatar
   
Dries committed
30

31
32
33
34
35
36
  // - TRUE makes mysql_connect() always open a new link, even if
  //   mysql_connect() was called before with the same parameters.
  //   This is important if you are using two databases on the same
  //   server.
  // - 2 means CLIENT_FOUND_ROWS: return the number of found
  //   (matched) rows, not the number of affected rows.
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
  $connection = @mysql_connect($url['host'], $url['user'], $url['pass'], TRUE, 2);
  if (!$connection) {
    drupal_maintenance_theme();
    drupal_set_title('Unable to connect to database server');
    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>
<p>The MySQL error was: '. theme('placeholder', mysql_error()) .'.</p>
<p>Currently, the username is '. theme('placeholder', $url['user']) .' and the database server is '. theme('placeholder', $url['host']) .'.</p>
<ul>
  <li>Are you sure you have the correct username and password?</li>
  <li>Are you sure that you have typed the correct hostname?</li>
  <li>Are you sure that the database server is running?</li>
</ul>
<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>');
    exit;
  }
52

53
54
55
56
57
58
59
60
61
62
63
64
65
66
  if (!mysql_select_db(substr($url['path'], 1))) {
    drupal_maintenance_theme();
    drupal_set_title('Unable to select database');
    print theme('maintenance_page', '<p>We were able to connect to the MySQL database server (which means your username and password is okay) but not able to select the database.</p>
<p>The MySQL error was: '. theme('placeholder', mysql_error()) .'.</p>
<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>
<ul>
  <li>Are you sure you have the correct database name?</li>
  <li>Are you sure the database exists?</li>
  <li>Are you sure the username has permission to access the database?</li>
</ul>
<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>');
    exit;
  }
Dries's avatar
 
Dries committed
67

Dries's avatar
   
Dries committed
68
  return $connection;
Dries's avatar
 
Dries committed
69
70
}

Dries's avatar
   
Dries committed
71
72
73
/**
 * Helper function for db_query().
 */
Dries's avatar
   
Dries committed
74
function _db_query($query, $debug = 0) {
75
  global $active_db, $queries;
Dries's avatar
   
Dries committed
76

77
  if (variable_get('dev_query', 0)) {
Dries's avatar
   
Dries committed
78
    list($usec, $sec) = explode(' ', microtime());
Dries's avatar
   
Dries committed
79
    $timer = (float)$usec + (float)$sec;
Dries's avatar
   
Dries committed
80
  }
Dries's avatar
 
Dries committed
81

Dries's avatar
   
Dries committed
82
  $result = mysql_query($query, $active_db);
Dries's avatar
 
Dries committed
83

84
  if (variable_get('dev_query', 0)) {
Dries's avatar
   
Dries committed
85
    list($usec, $sec) = explode(' ', microtime());
Dries's avatar
   
Dries committed
86
87
88
89
90
    $stop = (float)$usec + (float)$sec;
    $diff = $stop - $timer;
    $queries[] = array($query, $diff);
  }

Dries's avatar
 
Dries committed
91
  if ($debug) {
Dries's avatar
   
Dries committed
92
    print '<p>query: '. $query .'<br />error:'. mysql_error() .'</p>';
Dries's avatar
 
Dries committed
93
94
  }

Dries's avatar
   
Dries committed
95
  if (!mysql_errno()) {
Dries's avatar
 
Dries committed
96
    return $result;
Kjartan's avatar
Kjartan committed
97
98
  }
  else {
Dries's avatar
   
Dries committed
99
    trigger_error(mysql_error() ."\nquery: ". htmlspecialchars($query), E_USER_ERROR);
100
    return FALSE;
Dries's avatar
 
Dries committed
101
102
103
  }
}

Dries's avatar
   
Dries committed
104
105
106
107
108
109
110
111
112
/**
 * Fetch one result row from the previous query as an object.
 *
 * @param $result
 *   A database query result resource, as returned from db_query().
 * @return
 *   An object representing the next row of the result. The attributes of this
 *   object are the table fields selected by the query.
 */
Dries's avatar
 
Dries committed
113
114
115
116
117
118
function db_fetch_object($result) {
  if ($result) {
    return mysql_fetch_object($result);
  }
}

Dries's avatar
   
Dries committed
119
120
121
122
123
124
125
126
127
128
/**
 * Fetch one result row from the previous query as an array.
 *
 * @param $result
 *   A database query result resource, as returned from db_query().
 * @return
 *   An associative array representing the next row of the result. The keys of
 *   this object are the names of the table fields selected by the query, and
 *   the values are the field values for this result row.
 */
Dries's avatar
 
Dries committed
129
130
131
132
133
134
function db_fetch_array($result) {
  if ($result) {
    return mysql_fetch_array($result, MYSQL_ASSOC);
  }
}

Dries's avatar
   
Dries committed
135
136
137
138
139
140
141
142
/**
 * Determine how many result rows were found by the preceding query.
 *
 * @param $result
 *   A database query result resource, as returned from db_query().
 * @return
 *   The number of result rows.
 */
Dries's avatar
 
Dries committed
143
144
145
146
147
148
function db_num_rows($result) {
  if ($result) {
    return mysql_num_rows($result);
  }
}

Dries's avatar
   
Dries committed
149
150
151
152
153
154
155
156
157
158
159
160
161
/**
 * Return an individual result field from the previous query.
 *
 * Only use this function if exactly one field is being selected; otherwise,
 * use db_fetch_object() or db_fetch_array().
 *
 * @param $result
 *   A database query result resource, as returned from db_query().
 * @param $row
 *   The index of the row whose result is needed.
 * @return
 *   The resulting field.
 */
Dries's avatar
 
Dries committed
162
163
164
165
166
167
function db_result($result, $row = 0) {
  if ($result && mysql_num_rows($result) > $row) {
    return mysql_result($result, $row);
  }
}

Dries's avatar
   
Dries committed
168
169
170
/**
 * Determine whether the previous query caused an error.
 */
Dries's avatar
 
Dries committed
171
172
173
174
function db_error() {
  return mysql_errno();
}

Dries's avatar
   
Dries committed
175
176
177
178
179
180
181
182
/**
 * Return a new unique ID in the given sequence.
 *
 * For compatibility reasons, Drupal does not use auto-numbered fields in its
 * database tables. Instead, this function is used to return a new unique ID
 * of the type requested. If necessary, a new sequence with the given name
 * will be created.
 */
Dries's avatar
   
Dries committed
183
function db_next_id($name) {
Dries's avatar
   
Dries committed
184
  $name = db_prefix_tables($name);
Dries's avatar
   
Dries committed
185
  db_query('LOCK TABLES {sequences} WRITE');
Dries's avatar
   
Dries committed
186
187
  $id = db_result(db_query("SELECT id FROM {sequences} WHERE name = '%s'", $name)) + 1;
  db_query("REPLACE INTO {sequences} VALUES ('%s', %d)", $name, $id);
Dries's avatar
   
Dries committed
188
  db_query('UNLOCK TABLES');
Dries's avatar
   
Dries committed
189
190
191
192

  return $id;
}

Dries's avatar
   
Dries committed
193
194
195
/**
 * Determine the number of rows changed by the preceding query.
 */
Dries's avatar
   
Dries committed
196
197
198
199
function db_affected_rows() {
  return mysql_affected_rows();
}

Dries's avatar
   
Dries committed
200
/**
Dries's avatar
   
Dries committed
201
202
203
204
205
206
 * Runs a limited-range query in the active database.
 *
 * Use this as a substitute for db_query() when a subset of the query is to be
 * returned.
 * User-supplied arguments to the query should be passed in as separate parameters
 * so that they can be properly escaped to avoid SQL injection attacks.
Dries's avatar
   
Dries committed
207
 *
Dries's avatar
   
Dries committed
208
209
210
211
 * @param $query
 *   A string containing an SQL query.
 * @param ...
 *   A variable number of arguments which are substituted into the query using
212
213
 *   printf() syntax. Instead of a variable number of query arguments, you may
 *   also pass a single array containing the query arguments.
Dries's avatar
   
Dries committed
214
215
216
217
218
219
220
 * @param $from
 *   The first result row to return.
 * @param $count
 *   The maximum number of result rows to return.
 * @return
 *   A database query result resource, or FALSE if the query was not executed
 *   correctly.
Dries's avatar
   
Dries committed
221
 */
Dries's avatar
Dries committed
222
223
224
225
function db_query_range($query) {
  $args = func_get_args();
  $count = array_pop($args);
  $from = array_pop($args);
226
227

  $query = db_prefix_tables($query);
228
  if (count($args) > 1) {
229
230
231
232
    // Check for array (alternative syntax).
    if (is_array($args[1])) {
      $args = array_merge(array($query), $args[1]);
    }
Dries's avatar
   
Dries committed
233
    $args = array_map('db_escape_string', $args);
Dries's avatar
Dries committed
234
    $args[0] = $query;
Dries's avatar
   
Dries committed
235
    $query = call_user_func_array('sprintf', $args);
Dries's avatar
Dries committed
236
  }
Dries's avatar
   
Dries committed
237
  $query .= ' LIMIT '. $from .', '. $count;
Dries's avatar
Dries committed
238
  return _db_query($query);
Dries's avatar
   
Dries committed
239
240
}

241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/**
 * Runs a SELECT query and stores its results in a temporary table.
 *
 * Use this as a substitute for db_query() when the results need to stored
 * in a temporary table. Temporary tables exist for the duration of the page
 * request.
 * User-supplied arguments to the query should be passed in as separate parameters
 * so that they can be properly escaped to avoid SQL injection attacks.
 *
 * Note that if you need to know how many results were returned, you should do
 * a SELECT COUNT(*) on the temporary table afterwards. db_num_rows() and
 * db_affected_rows() do not give consistent result across different database
 * types in this case.
 *
 * @param $query
 *   A string containing a normal SELECT SQL query.
 * @param ...
 *   A variable number of arguments which are substituted into the query using
 *   printf() syntax. Instead of a variable number of query arguments, you may
 *   also pass a single array containing the query arguments.
 * @param $table
 *   The name of the temporary table to select into. This name will not be
 *   prefixed as there is no risk of collision.
 * @return
 *   A database query result resource, or FALSE if the query was not executed
 *   correctly.
 */
function db_query_temporary($query) {
  $args = func_get_args();
  $tablename = array_pop($args);

  $query = preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE '. $tablename .' SELECT', db_prefix_tables($query));
  if (count($args) > 1) {
    // Check for array (alternative syntax).
    if (is_array($args[1])) {
      $args = array_merge(array($query), $args[1]);
    }
    $args = array_map('db_escape_string', $args);
    $args[0] = $query;
    $query = call_user_func_array('sprintf', $args);
  }
  return _db_query($query);
}

Dries's avatar
   
Dries committed
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
/**
 * Returns a properly formatted Binary Large OBject value.
 *
 * @param $data
 *   Data to encode.
 * @return
 *  Encoded data.
 */
function db_encode_blob($data) {
  return $data;
}

/**
 * Returns text from a Binary Large OBject value.
 *
 * @param $data
 *   Data to decode.
 * @return
 *  Decoded data.
 */
function db_decode_blob($data) {
  return $data;
}

Dries's avatar
   
Dries committed
309
310
311
312
/**
 * Prepare user input for use in a database query, preventing SQL injection attacks.
 */
function db_escape_string($text) {
313
  return mysql_real_escape_string($text);
Dries's avatar
   
Dries committed
314
315
}

316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
/**
 * Lock a table.
 */
function db_lock_table($table) {
  db_query('LOCK TABLES {%s} WRITE', $table);
}

/**
 * Unlock all locked tables.
 */
function db_unlock_tables() {
  db_query('UNLOCK TABLES');
}


Dries's avatar
   
Dries committed
331
/**
Dries's avatar
   
Dries committed
332
 * @} End of "ingroup database".
Dries's avatar
   
Dries committed
333
334
 */

335