Mercurial > defr > drupal > core
comparison includes/database.mysql-common.inc @ 1:c1f4ac30525a 6.0
Drupal 6.0
author | Franck Deroche <webmaster@defr.org> |
---|---|
date | Tue, 23 Dec 2008 14:28:28 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:5a113a1c4740 | 1:c1f4ac30525a |
---|---|
1 <?php | |
2 // $Id: database.mysql-common.inc,v 1.17.2.1 2008/02/07 10:17:26 goba Exp $ | |
3 | |
4 /** | |
5 * @file | |
6 * Functions shared between mysql and mysqli database engines. | |
7 */ | |
8 | |
9 /** | |
10 * Runs a basic query in the active database. | |
11 * | |
12 * User-supplied arguments to the query should be passed in as separate | |
13 * parameters so that they can be properly escaped to avoid SQL injection | |
14 * attacks. | |
15 * | |
16 * @param $query | |
17 * A string containing an SQL query. | |
18 * @param ... | |
19 * A variable number of arguments which are substituted into the query | |
20 * using printf() syntax. Instead of a variable number of query arguments, | |
21 * you may also pass a single array containing the query arguments. | |
22 * | |
23 * Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose | |
24 * in '') and %%. | |
25 * | |
26 * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, | |
27 * and TRUE values to decimal 1. | |
28 * | |
29 * @return | |
30 * A database query result resource, or FALSE if the query was not | |
31 * executed correctly. | |
32 */ | |
33 function db_query($query) { | |
34 $args = func_get_args(); | |
35 array_shift($args); | |
36 $query = db_prefix_tables($query); | |
37 if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax | |
38 $args = $args[0]; | |
39 } | |
40 _db_query_callback($args, TRUE); | |
41 $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); | |
42 return _db_query($query); | |
43 } | |
44 | |
45 /** | |
46 * @ingroup schemaapi | |
47 * @{ | |
48 */ | |
49 | |
50 /** | |
51 * Generate SQL to create a new table from a Drupal schema definition. | |
52 * | |
53 * @param $name | |
54 * The name of the table to create. | |
55 * @param $table | |
56 * A Schema API table definition array. | |
57 * @return | |
58 * An array of SQL statements to create the table. | |
59 */ | |
60 function db_create_table_sql($name, $table) { | |
61 | |
62 if (empty($table['mysql_suffix'])) { | |
63 $table['mysql_suffix'] = "/*!40100 DEFAULT CHARACTER SET UTF8 */"; | |
64 } | |
65 | |
66 $sql = "CREATE TABLE {". $name ."} (\n"; | |
67 | |
68 // Add the SQL statement for each field. | |
69 foreach ($table['fields'] as $field_name => $field) { | |
70 $sql .= _db_create_field_sql($field_name, _db_process_field($field)) .", \n"; | |
71 } | |
72 | |
73 // Process keys & indexes. | |
74 $keys = _db_create_keys_sql($table); | |
75 if (count($keys)) { | |
76 $sql .= implode(", \n", $keys) .", \n"; | |
77 } | |
78 | |
79 // Remove the last comma and space. | |
80 $sql = substr($sql, 0, -3) ."\n) "; | |
81 | |
82 $sql .= $table['mysql_suffix']; | |
83 | |
84 return array($sql); | |
85 } | |
86 | |
87 function _db_create_keys_sql($spec) { | |
88 $keys = array(); | |
89 | |
90 if (!empty($spec['primary key'])) { | |
91 $keys[] = 'PRIMARY KEY ('. _db_create_key_sql($spec['primary key']) .')'; | |
92 } | |
93 if (!empty($spec['unique keys'])) { | |
94 foreach ($spec['unique keys'] as $key => $fields) { | |
95 $keys[] = 'UNIQUE KEY '. $key .' ('. _db_create_key_sql($fields) .')'; | |
96 } | |
97 } | |
98 if (!empty($spec['indexes'])) { | |
99 foreach ($spec['indexes'] as $index => $fields) { | |
100 $keys[] = 'INDEX '. $index .' ('. _db_create_key_sql($fields) .')'; | |
101 } | |
102 } | |
103 | |
104 return $keys; | |
105 } | |
106 | |
107 function _db_create_key_sql($fields) { | |
108 $ret = array(); | |
109 foreach ($fields as $field) { | |
110 if (is_array($field)) { | |
111 $ret[] = $field[0] .'('. $field[1] .')'; | |
112 } | |
113 else { | |
114 $ret[] = $field; | |
115 } | |
116 } | |
117 return implode(', ', $ret); | |
118 } | |
119 | |
120 /** | |
121 * Set database-engine specific properties for a field. | |
122 * | |
123 * @param $field | |
124 * A field description array, as specified in the schema documentation. | |
125 */ | |
126 function _db_process_field($field) { | |
127 | |
128 if (!isset($field['size'])) { | |
129 $field['size'] = 'normal'; | |
130 } | |
131 | |
132 // Set the correct database-engine specific datatype. | |
133 if (!isset($field['mysql_type'])) { | |
134 $map = db_type_map(); | |
135 $field['mysql_type'] = $map[$field['type'] .':'. $field['size']]; | |
136 } | |
137 | |
138 if ($field['type'] == 'serial') { | |
139 $field['auto_increment'] = TRUE; | |
140 } | |
141 | |
142 return $field; | |
143 } | |
144 | |
145 /** | |
146 * Create an SQL string for a field to be used in table creation or alteration. | |
147 * | |
148 * Before passing a field out of a schema definition into this function it has | |
149 * to be processed by _db_process_field(). | |
150 * | |
151 * @param $name | |
152 * Name of the field. | |
153 * @param $spec | |
154 * The field specification, as per the schema data structure format. | |
155 */ | |
156 function _db_create_field_sql($name, $spec) { | |
157 $sql = "`". $name ."` ". $spec['mysql_type']; | |
158 | |
159 if (isset($spec['length'])) { | |
160 $sql .= '('. $spec['length'] .')'; | |
161 } | |
162 elseif (isset($spec['precision']) && isset($spec['scale'])) { | |
163 $sql .= '('. $spec['precision'] .', '. $spec['scale'] .')'; | |
164 } | |
165 | |
166 if (!empty($spec['unsigned'])) { | |
167 $sql .= ' unsigned'; | |
168 } | |
169 | |
170 if (!empty($spec['not null'])) { | |
171 $sql .= ' NOT NULL'; | |
172 } | |
173 | |
174 if (!empty($spec['auto_increment'])) { | |
175 $sql .= ' auto_increment'; | |
176 } | |
177 | |
178 if (isset($spec['default'])) { | |
179 if (is_string($spec['default'])) { | |
180 $spec['default'] = "'". $spec['default'] ."'"; | |
181 } | |
182 $sql .= ' DEFAULT '. $spec['default']; | |
183 } | |
184 | |
185 if (empty($spec['not null']) && !isset($spec['default'])) { | |
186 $sql .= ' DEFAULT NULL'; | |
187 } | |
188 | |
189 return $sql; | |
190 } | |
191 | |
192 /** | |
193 * This maps a generic data type in combination with its data size | |
194 * to the engine-specific data type. | |
195 */ | |
196 function db_type_map() { | |
197 // Put :normal last so it gets preserved by array_flip. This makes | |
198 // it much easier for modules (such as schema.module) to map | |
199 // database types back into schema types. | |
200 $map = array( | |
201 'varchar:normal' => 'VARCHAR', | |
202 'char:normal' => 'CHAR', | |
203 | |
204 'text:tiny' => 'TINYTEXT', | |
205 'text:small' => 'TINYTEXT', | |
206 'text:medium' => 'MEDIUMTEXT', | |
207 'text:big' => 'LONGTEXT', | |
208 'text:normal' => 'TEXT', | |
209 | |
210 'serial:tiny' => 'TINYINT', | |
211 'serial:small' => 'SMALLINT', | |
212 'serial:medium' => 'MEDIUMINT', | |
213 'serial:big' => 'BIGINT', | |
214 'serial:normal' => 'INT', | |
215 | |
216 'int:tiny' => 'TINYINT', | |
217 'int:small' => 'SMALLINT', | |
218 'int:medium' => 'MEDIUMINT', | |
219 'int:big' => 'BIGINT', | |
220 'int:normal' => 'INT', | |
221 | |
222 'float:tiny' => 'FLOAT', | |
223 'float:small' => 'FLOAT', | |
224 'float:medium' => 'FLOAT', | |
225 'float:big' => 'DOUBLE', | |
226 'float:normal' => 'FLOAT', | |
227 | |
228 'numeric:normal' => 'DECIMAL', | |
229 | |
230 'blob:big' => 'LONGBLOB', | |
231 'blob:normal' => 'BLOB', | |
232 | |
233 'datetime:normal' => 'DATETIME', | |
234 ); | |
235 return $map; | |
236 } | |
237 | |
238 /** | |
239 * Rename a table. | |
240 * | |
241 * @param $ret | |
242 * Array to which query results will be added. | |
243 * @param $table | |
244 * The table to be renamed. | |
245 * @param $new_name | |
246 * The new name for the table. | |
247 */ | |
248 function db_rename_table(&$ret, $table, $new_name) { | |
249 $ret[] = update_sql('ALTER TABLE {'. $table .'} RENAME TO {'. $new_name .'}'); | |
250 } | |
251 | |
252 /** | |
253 * Drop a table. | |
254 * | |
255 * @param $ret | |
256 * Array to which query results will be added. | |
257 * @param $table | |
258 * The table to be dropped. | |
259 */ | |
260 function db_drop_table(&$ret, $table) { | |
261 $ret[] = update_sql('DROP TABLE {'. $table .'}'); | |
262 } | |
263 | |
264 /** | |
265 * Add a new field to a table. | |
266 * | |
267 * @param $ret | |
268 * Array to which query results will be added. | |
269 * @param $table | |
270 * Name of the table to be altered. | |
271 * @param $field | |
272 * Name of the field to be added. | |
273 * @param $spec | |
274 * The field specification array, as taken from a schema definition. | |
275 * The specification may also contain the key 'initial', the newly | |
276 * created field will be set to the value of the key in all rows. | |
277 * This is most useful for creating NOT NULL columns with no default | |
278 * value in existing tables. | |
279 * @param $keys_new | |
280 * Optional keys and indexes specification to be created on the | |
281 * table along with adding the field. The format is the same as a | |
282 * table specification but without the 'fields' element. If you are | |
283 * adding a type 'serial' field, you MUST specify at least one key | |
284 * or index including it in this array. @see db_change_field for more | |
285 * explanation why. | |
286 */ | |
287 function db_add_field(&$ret, $table, $field, $spec, $keys_new = array()) { | |
288 $fixnull = FALSE; | |
289 if (!empty($spec['not null']) && !isset($spec['default'])) { | |
290 $fixnull = TRUE; | |
291 $spec['not null'] = FALSE; | |
292 } | |
293 $query = 'ALTER TABLE {'. $table .'} ADD '; | |
294 $query .= _db_create_field_sql($field, _db_process_field($spec)); | |
295 if (count($keys_new)) { | |
296 $query .= ', ADD '. implode(', ADD ', _db_create_keys_sql($keys_new)); | |
297 } | |
298 $ret[] = update_sql($query); | |
299 if (isset($spec['initial'])) { | |
300 // All this because update_sql does not support %-placeholders. | |
301 $sql = 'UPDATE {'. $table .'} SET '. $field .' = '. db_type_placeholder($spec['type']); | |
302 $result = db_query($sql, $spec['initial']); | |
303 $ret[] = array('success' => $result !== FALSE, 'query' => check_plain($sql .' ('. $spec['initial'] .')')); | |
304 } | |
305 if ($fixnull) { | |
306 $spec['not null'] = TRUE; | |
307 db_change_field($ret, $table, $field, $field, $spec); | |
308 } | |
309 } | |
310 | |
311 /** | |
312 * Drop a field. | |
313 * | |
314 * @param $ret | |
315 * Array to which query results will be added. | |
316 * @param $table | |
317 * The table to be altered. | |
318 * @param $field | |
319 * The field to be dropped. | |
320 */ | |
321 function db_drop_field(&$ret, $table, $field) { | |
322 $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP '. $field); | |
323 } | |
324 | |
325 /** | |
326 * Set the default value for a field. | |
327 * | |
328 * @param $ret | |
329 * Array to which query results will be added. | |
330 * @param $table | |
331 * The table to be altered. | |
332 * @param $field | |
333 * The field to be altered. | |
334 * @param $default | |
335 * Default value to be set. NULL for 'default NULL'. | |
336 */ | |
337 function db_field_set_default(&$ret, $table, $field, $default) { | |
338 if ($default == NULL) { | |
339 $default = 'NULL'; | |
340 } | |
341 else { | |
342 $default = is_string($default) ? "'$default'" : $default; | |
343 } | |
344 | |
345 $ret[] = update_sql('ALTER TABLE {'. $table .'} ALTER COLUMN '. $field .' SET DEFAULT '. $default); | |
346 } | |
347 | |
348 /** | |
349 * Set a field to have no default value. | |
350 * | |
351 * @param $ret | |
352 * Array to which query results will be added. | |
353 * @param $table | |
354 * The table to be altered. | |
355 * @param $field | |
356 * The field to be altered. | |
357 */ | |
358 function db_field_set_no_default(&$ret, $table, $field) { | |
359 $ret[] = update_sql('ALTER TABLE {'. $table .'} ALTER COLUMN '. $field .' DROP DEFAULT'); | |
360 } | |
361 | |
362 /** | |
363 * Add a primary key. | |
364 * | |
365 * @param $ret | |
366 * Array to which query results will be added. | |
367 * @param $table | |
368 * The table to be altered. | |
369 * @param $fields | |
370 * Fields for the primary key. | |
371 */ | |
372 function db_add_primary_key(&$ret, $table, $fields) { | |
373 $ret[] = update_sql('ALTER TABLE {'. $table .'} ADD PRIMARY KEY ('. | |
374 _db_create_key_sql($fields) .')'); | |
375 } | |
376 | |
377 /** | |
378 * Drop the primary key. | |
379 * | |
380 * @param $ret | |
381 * Array to which query results will be added. | |
382 * @param $table | |
383 * The table to be altered. | |
384 */ | |
385 function db_drop_primary_key(&$ret, $table) { | |
386 $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP PRIMARY KEY'); | |
387 } | |
388 | |
389 /** | |
390 * Add a unique key. | |
391 * | |
392 * @param $ret | |
393 * Array to which query results will be added. | |
394 * @param $table | |
395 * The table to be altered. | |
396 * @param $name | |
397 * The name of the key. | |
398 * @param $fields | |
399 * An array of field names. | |
400 */ | |
401 function db_add_unique_key(&$ret, $table, $name, $fields) { | |
402 $ret[] = update_sql('ALTER TABLE {'. $table .'} ADD UNIQUE KEY '. | |
403 $name .' ('. _db_create_key_sql($fields) .')'); | |
404 } | |
405 | |
406 /** | |
407 * Drop a unique key. | |
408 * | |
409 * @param $ret | |
410 * Array to which query results will be added. | |
411 * @param $table | |
412 * The table to be altered. | |
413 * @param $name | |
414 * The name of the key. | |
415 */ | |
416 function db_drop_unique_key(&$ret, $table, $name) { | |
417 $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP KEY '. $name); | |
418 } | |
419 | |
420 /** | |
421 * Add an index. | |
422 * | |
423 * @param $ret | |
424 * Array to which query results will be added. | |
425 * @param $table | |
426 * The table to be altered. | |
427 * @param $name | |
428 * The name of the index. | |
429 * @param $fields | |
430 * An array of field names. | |
431 */ | |
432 function db_add_index(&$ret, $table, $name, $fields) { | |
433 $query = 'ALTER TABLE {'. $table .'} ADD INDEX '. $name .' ('. _db_create_key_sql($fields) .')'; | |
434 $ret[] = update_sql($query); | |
435 } | |
436 | |
437 /** | |
438 * Drop an index. | |
439 * | |
440 * @param $ret | |
441 * Array to which query results will be added. | |
442 * @param $table | |
443 * The table to be altered. | |
444 * @param $name | |
445 * The name of the index. | |
446 */ | |
447 function db_drop_index(&$ret, $table, $name) { | |
448 $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP INDEX '. $name); | |
449 } | |
450 | |
451 /** | |
452 * Change a field definition. | |
453 * | |
454 * IMPORTANT NOTE: To maintain database portability, you have to explicitly | |
455 * recreate all indices and primary keys that are using the changed field. | |
456 * | |
457 * That means that you have to drop all affected keys and indexes with | |
458 * db_drop_{primary_key,unique_key,index}() before calling db_change_field(). | |
459 * To recreate the keys and indices, pass the key definitions as the | |
460 * optional $keys_new argument directly to db_change_field(). | |
461 * | |
462 * For example, suppose you have: | |
463 * @code | |
464 * $schema['foo'] = array( | |
465 * 'fields' => array( | |
466 * 'bar' => array('type' => 'int', 'not null' => TRUE) | |
467 * ), | |
468 * 'primary key' => array('bar') | |
469 * ); | |
470 * @endcode | |
471 * and you want to change foo.bar to be type serial, leaving it as the | |
472 * primary key. The correct sequence is: | |
473 * @code | |
474 * db_drop_primary_key($ret, 'foo'); | |
475 * db_change_field($ret, 'foo', 'bar', 'bar', | |
476 * array('type' => 'serial', 'not null' => TRUE), | |
477 * array('primary key' => array('bar'))); | |
478 * @endcode | |
479 * | |
480 * The reasons for this are due to the different database engines: | |
481 * | |
482 * On PostgreSQL, changing a field definition involves adding a new field | |
483 * and dropping an old one which* causes any indices, primary keys and | |
484 * sequences (from serial-type fields) that use the changed field to be dropped. | |
485 * | |
486 * On MySQL, all type 'serial' fields must be part of at least one key | |
487 * or index as soon as they are created. You cannot use | |
488 * db_add_{primary_key,unique_key,index}() for this purpose because | |
489 * the ALTER TABLE command will fail to add the column without a key | |
490 * or index specification. The solution is to use the optional | |
491 * $keys_new argument to create the key or index at the same time as | |
492 * field. | |
493 * | |
494 * You could use db_add_{primary_key,unique_key,index}() in all cases | |
495 * unless you are converting a field to be type serial. You can use | |
496 * the $keys_new argument in all cases. | |
497 * | |
498 * @param $ret | |
499 * Array to which query results will be added. | |
500 * @param $table | |
501 * Name of the table. | |
502 * @param $field | |
503 * Name of the field to change. | |
504 * @param $field_new | |
505 * New name for the field (set to the same as $field if you don't want to change the name). | |
506 * @param $spec | |
507 * The field specification for the new field. | |
508 * @param $keys_new | |
509 * Optional keys and indexes specification to be created on the | |
510 * table along with changing the field. The format is the same as a | |
511 * table specification but without the 'fields' element. | |
512 */ | |
513 | |
514 function db_change_field(&$ret, $table, $field, $field_new, $spec, $keys_new = array()) { | |
515 $sql = 'ALTER TABLE {'. $table .'} CHANGE '. $field .' '. | |
516 _db_create_field_sql($field_new, _db_process_field($spec)); | |
517 if (count($keys_new)) { | |
518 $sql .= ', ADD '. implode(', ADD ', _db_create_keys_sql($keys_new)); | |
519 } | |
520 $ret[] = update_sql($sql); | |
521 } | |
522 | |
523 /** | |
524 * Returns the last insert id. | |
525 * | |
526 * @param $table | |
527 * The name of the table you inserted into. | |
528 * @param $field | |
529 * The name of the autoincrement field. | |
530 */ | |
531 function db_last_insert_id($table, $field) { | |
532 return db_result(db_query('SELECT LAST_INSERT_ID()')); | |
533 } |