|
1 <?php |
|
2 |
|
3 /** |
|
4 * @file |
|
5 * Generic Database schema code. |
|
6 */ |
|
7 |
|
8 require_once dirname(__FILE__) . '/query.inc'; |
|
9 |
|
10 /** |
|
11 * @defgroup schemaapi Schema API |
|
12 * @{ |
|
13 * API to handle database schemas. |
|
14 * |
|
15 * A Drupal schema definition is an array structure representing one or |
|
16 * more tables and their related keys and indexes. A schema is defined by |
|
17 * hook_schema(), which usually lives in a modulename.install file. |
|
18 * |
|
19 * By implementing hook_schema() and specifying the tables your module |
|
20 * declares, you can easily create and drop these tables on all |
|
21 * supported database engines. You don't have to deal with the |
|
22 * different SQL dialects for table creation and alteration of the |
|
23 * supported database engines. |
|
24 * |
|
25 * hook_schema() should return an array with a key for each table that |
|
26 * the module defines. |
|
27 * |
|
28 * The following keys are defined: |
|
29 * - 'description': A string in non-markup plain text describing this table |
|
30 * and its purpose. References to other tables should be enclosed in |
|
31 * curly-brackets. For example, the node_revisions table |
|
32 * description field might contain "Stores per-revision title and |
|
33 * body data for each {node}." |
|
34 * - 'fields': An associative array ('fieldname' => specification) |
|
35 * that describes the table's database columns. The specification |
|
36 * is also an array. The following specification parameters are defined: |
|
37 * - 'description': A string in non-markup plain text describing this field |
|
38 * and its purpose. References to other tables should be enclosed in |
|
39 * curly-brackets. For example, the node table vid field |
|
40 * description might contain "Always holds the largest (most |
|
41 * recent) {node_revision}.vid value for this nid." |
|
42 * - 'type': The generic datatype: 'char', 'varchar', 'text', 'blob', 'int', |
|
43 * 'float', 'numeric', or 'serial'. Most types just map to the according |
|
44 * database engine specific datatypes. Use 'serial' for auto incrementing |
|
45 * fields. This will expand to 'INT auto_increment' on MySQL. |
|
46 * - 'mysql_type', 'pgsql_type', 'sqlite_type', etc.: If you need to |
|
47 * use a record type not included in the officially supported list |
|
48 * of types above, you can specify a type for each database |
|
49 * backend. In this case, you can leave out the type parameter, |
|
50 * but be advised that your schema will fail to load on backends that |
|
51 * do not have a type specified. A possible solution can be to |
|
52 * use the "text" type as a fallback. |
|
53 * - 'serialize': A boolean indicating whether the field will be stored as |
|
54 * a serialized string. |
|
55 * - 'size': The data size: 'tiny', 'small', 'medium', 'normal', |
|
56 * 'big'. This is a hint about the largest value the field will |
|
57 * store and determines which of the database engine specific |
|
58 * datatypes will be used (e.g. on MySQL, TINYINT vs. INT vs. BIGINT). |
|
59 * 'normal', the default, selects the base type (e.g. on MySQL, |
|
60 * INT, VARCHAR, BLOB, etc.). |
|
61 * Not all sizes are available for all data types. See |
|
62 * DatabaseSchema::getFieldTypeMap() for possible combinations. |
|
63 * - 'not null': If true, no NULL values will be allowed in this |
|
64 * database column. Defaults to false. |
|
65 * - 'default': The field's default value. The PHP type of the |
|
66 * value matters: '', '0', and 0 are all different. If you |
|
67 * specify '0' as the default value for a type 'int' field it |
|
68 * will not work because '0' is a string containing the |
|
69 * character "zero", not an integer. |
|
70 * - 'length': The maximal length of a type 'char', 'varchar' or 'text' |
|
71 * field. Ignored for other field types. |
|
72 * - 'unsigned': A boolean indicating whether a type 'int', 'float' |
|
73 * and 'numeric' only is signed or unsigned. Defaults to |
|
74 * FALSE. Ignored for other field types. |
|
75 * - 'precision', 'scale': For type 'numeric' fields, indicates |
|
76 * the precision (total number of significant digits) and scale |
|
77 * (decimal digits right of the decimal point). Both values are |
|
78 * mandatory. Ignored for other field types. |
|
79 * - 'binary': A boolean indicating that MySQL should force 'char', |
|
80 * 'varchar' or 'text' fields to use case-sensitive binary collation. |
|
81 * This has no effect on other database types for which case sensitivity |
|
82 * is already the default behavior. |
|
83 * All parameters apart from 'type' are optional except that type |
|
84 * 'numeric' columns must specify 'precision' and 'scale', and type |
|
85 * 'varchar' must specify the 'length' parameter. |
|
86 * - 'primary key': An array of one or more key column specifiers (see below) |
|
87 * that form the primary key. |
|
88 * - 'unique keys': An associative array of unique keys ('keyname' => |
|
89 * specification). Each specification is an array of one or more |
|
90 * key column specifiers (see below) that form a unique key on the table. |
|
91 * - 'foreign keys': An associative array of relations ('my_relation' => |
|
92 * specification). Each specification is an array containing the name of |
|
93 * the referenced table ('table'), and an array of column mappings |
|
94 * ('columns'). Column mappings are defined by key pairs ('source_column' => |
|
95 * 'referenced_column'). This key is for documentation purposes only; foreign |
|
96 * keys are not created in the database, nor are they enforced by Drupal. |
|
97 * - 'indexes': An associative array of indexes ('indexname' => |
|
98 * specification). Each specification is an array of one or more |
|
99 * key column specifiers (see below) that form an index on the |
|
100 * table. |
|
101 * |
|
102 * A key column specifier is either a string naming a column or an |
|
103 * array of two elements, column name and length, specifying a prefix |
|
104 * of the named column. |
|
105 * |
|
106 * As an example, here is a SUBSET of the schema definition for |
|
107 * Drupal's 'node' table. It show four fields (nid, vid, type, and |
|
108 * title), the primary key on field 'nid', a unique key named 'vid' on |
|
109 * field 'vid', and two indexes, one named 'nid' on field 'nid' and |
|
110 * one named 'node_title_type' on the field 'title' and the first four |
|
111 * bytes of the field 'type': |
|
112 * |
|
113 * @code |
|
114 * $schema['node'] = array( |
|
115 * 'description' => 'The base table for nodes.', |
|
116 * 'fields' => array( |
|
117 * 'nid' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE), |
|
118 * 'vid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE,'default' => 0), |
|
119 * 'type' => array('type' => 'varchar','length' => 32,'not null' => TRUE, 'default' => ''), |
|
120 * 'language' => array('type' => 'varchar','length' => 12,'not null' => TRUE,'default' => ''), |
|
121 * 'title' => array('type' => 'varchar','length' => 255,'not null' => TRUE, 'default' => ''), |
|
122 * 'uid' => array('type' => 'int', 'not null' => TRUE, 'default' => 0), |
|
123 * 'status' => array('type' => 'int', 'not null' => TRUE, 'default' => 1), |
|
124 * 'created' => array('type' => 'int', 'not null' => TRUE, 'default' => 0), |
|
125 * 'changed' => array('type' => 'int', 'not null' => TRUE, 'default' => 0), |
|
126 * 'comment' => array('type' => 'int', 'not null' => TRUE, 'default' => 0), |
|
127 * 'promote' => array('type' => 'int', 'not null' => TRUE, 'default' => 0), |
|
128 * 'moderate' => array('type' => 'int', 'not null' => TRUE,'default' => 0), |
|
129 * 'sticky' => array('type' => 'int', 'not null' => TRUE, 'default' => 0), |
|
130 * 'tnid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0), |
|
131 * 'translate' => array('type' => 'int', 'not null' => TRUE, 'default' => 0), |
|
132 * ), |
|
133 * 'indexes' => array( |
|
134 * 'node_changed' => array('changed'), |
|
135 * 'node_created' => array('created'), |
|
136 * 'node_moderate' => array('moderate'), |
|
137 * 'node_frontpage' => array('promote', 'status', 'sticky', 'created'), |
|
138 * 'node_status_type' => array('status', 'type', 'nid'), |
|
139 * 'node_title_type' => array('title', array('type', 4)), |
|
140 * 'node_type' => array(array('type', 4)), |
|
141 * 'uid' => array('uid'), |
|
142 * 'tnid' => array('tnid'), |
|
143 * 'translate' => array('translate'), |
|
144 * ), |
|
145 * 'unique keys' => array( |
|
146 * 'vid' => array('vid'), |
|
147 * ), |
|
148 * // For documentation purposes only; foreign keys are not created in the |
|
149 * // database. |
|
150 * 'foreign keys' => array( |
|
151 * 'node_revision' => array( |
|
152 * 'table' => 'node_revision', |
|
153 * 'columns' => array('vid' => 'vid'), |
|
154 * ), |
|
155 * 'node_author' => array( |
|
156 * 'table' => 'users', |
|
157 * 'columns' => array('uid' => 'uid'), |
|
158 * ), |
|
159 * ), |
|
160 * 'primary key' => array('nid'), |
|
161 * ); |
|
162 * @endcode |
|
163 * |
|
164 * @see drupal_install_schema() |
|
165 */ |
|
166 |
|
167 /** |
|
168 * Base class for database schema definitions. |
|
169 */ |
|
170 abstract class DatabaseSchema implements QueryPlaceholderInterface { |
|
171 |
|
172 protected $connection; |
|
173 |
|
174 /** |
|
175 * The placeholder counter. |
|
176 */ |
|
177 protected $placeholder = 0; |
|
178 |
|
179 /** |
|
180 * Definition of prefixInfo array structure. |
|
181 * |
|
182 * Rather than redefining DatabaseSchema::getPrefixInfo() for each driver, |
|
183 * by defining the defaultSchema variable only MySQL has to re-write the |
|
184 * method. |
|
185 * |
|
186 * @see DatabaseSchema::getPrefixInfo() |
|
187 */ |
|
188 protected $defaultSchema = 'public'; |
|
189 |
|
190 /** |
|
191 * A unique identifier for this query object. |
|
192 */ |
|
193 protected $uniqueIdentifier; |
|
194 |
|
195 public function __construct($connection) { |
|
196 $this->uniqueIdentifier = uniqid('', TRUE); |
|
197 $this->connection = $connection; |
|
198 } |
|
199 |
|
200 /** |
|
201 * Implements the magic __clone function. |
|
202 */ |
|
203 public function __clone() { |
|
204 $this->uniqueIdentifier = uniqid('', TRUE); |
|
205 } |
|
206 |
|
207 /** |
|
208 * Implements QueryPlaceHolderInterface::uniqueIdentifier(). |
|
209 */ |
|
210 public function uniqueIdentifier() { |
|
211 return $this->uniqueIdentifier; |
|
212 } |
|
213 |
|
214 /** |
|
215 * Implements QueryPlaceHolderInterface::nextPlaceholder(). |
|
216 */ |
|
217 public function nextPlaceholder() { |
|
218 return $this->placeholder++; |
|
219 } |
|
220 |
|
221 /** |
|
222 * Get information about the table name and schema from the prefix. |
|
223 * |
|
224 * @param |
|
225 * Name of table to look prefix up for. Defaults to 'default' because thats |
|
226 * default key for prefix. |
|
227 * @param $add_prefix |
|
228 * Boolean that indicates whether the given table name should be prefixed. |
|
229 * |
|
230 * @return |
|
231 * A keyed array with information about the schema, table name and prefix. |
|
232 */ |
|
233 protected function getPrefixInfo($table = 'default', $add_prefix = TRUE) { |
|
234 $info = array( |
|
235 'schema' => $this->defaultSchema, |
|
236 'prefix' => $this->connection->tablePrefix($table), |
|
237 ); |
|
238 if ($add_prefix) { |
|
239 $table = $info['prefix'] . $table; |
|
240 } |
|
241 // If the prefix contains a period in it, then that means the prefix also |
|
242 // contains a schema reference in which case we will change the schema key |
|
243 // to the value before the period in the prefix. Everything after the dot |
|
244 // will be prefixed onto the front of the table. |
|
245 if (($pos = strpos($table, '.')) !== FALSE) { |
|
246 // Grab everything before the period. |
|
247 $info['schema'] = substr($table, 0, $pos); |
|
248 // Grab everything after the dot. |
|
249 $info['table'] = substr($table, ++$pos); |
|
250 } |
|
251 else { |
|
252 $info['table'] = $table; |
|
253 } |
|
254 return $info; |
|
255 } |
|
256 |
|
257 /** |
|
258 * Create names for indexes, primary keys and constraints. |
|
259 * |
|
260 * This prevents using {} around non-table names like indexes and keys. |
|
261 */ |
|
262 function prefixNonTable($table) { |
|
263 $args = func_get_args(); |
|
264 $info = $this->getPrefixInfo($table); |
|
265 $args[0] = $info['table']; |
|
266 return implode('_', $args); |
|
267 } |
|
268 |
|
269 /** |
|
270 * Build a condition to match a table name against a standard information_schema. |
|
271 * |
|
272 * The information_schema is a SQL standard that provides information about the |
|
273 * database server and the databases, schemas, tables, columns and users within |
|
274 * it. This makes information_schema a useful tool to use across the drupal |
|
275 * database drivers and is used by a few different functions. The function below |
|
276 * describes the conditions to be meet when querying information_schema.tables |
|
277 * for drupal tables or information associated with drupal tables. Even though |
|
278 * this is the standard method, not all databases follow standards and so this |
|
279 * method should be overwritten by a database driver if the database provider |
|
280 * uses alternate methods. Because information_schema.tables is used in a few |
|
281 * different functions, a database driver will only need to override this function |
|
282 * to make all the others work. For example see includes/databases/mysql/schema.inc. |
|
283 * |
|
284 * @param $table_name |
|
285 * The name of the table in question. |
|
286 * @param $operator |
|
287 * The operator to apply on the 'table' part of the condition. |
|
288 * @param $add_prefix |
|
289 * Boolean to indicate whether the table name needs to be prefixed. |
|
290 * |
|
291 * @return QueryConditionInterface |
|
292 * A DatabaseCondition object. |
|
293 */ |
|
294 protected function buildTableNameCondition($table_name, $operator = '=', $add_prefix = TRUE) { |
|
295 $info = $this->connection->getConnectionOptions(); |
|
296 |
|
297 // Retrieve the table name and schema |
|
298 $table_info = $this->getPrefixInfo($table_name, $add_prefix); |
|
299 |
|
300 $condition = new DatabaseCondition('AND'); |
|
301 $condition->condition('table_catalog', $info['database']); |
|
302 $condition->condition('table_schema', $table_info['schema']); |
|
303 $condition->condition('table_name', $table_info['table'], $operator); |
|
304 return $condition; |
|
305 } |
|
306 |
|
307 /** |
|
308 * Check if a table exists. |
|
309 * |
|
310 * @param $table |
|
311 * The name of the table in drupal (no prefixing). |
|
312 * |
|
313 * @return |
|
314 * TRUE if the given table exists, otherwise FALSE. |
|
315 */ |
|
316 public function tableExists($table) { |
|
317 $condition = $this->buildTableNameCondition($table); |
|
318 $condition->compile($this->connection, $this); |
|
319 // Normally, we would heartily discourage the use of string |
|
320 // concatenation for conditionals like this however, we |
|
321 // couldn't use db_select() here because it would prefix |
|
322 // information_schema.tables and the query would fail. |
|
323 // Don't use {} around information_schema.tables table. |
|
324 return (bool) $this->connection->query("SELECT 1 FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchField(); |
|
325 } |
|
326 |
|
327 /** |
|
328 * Find all tables that are like the specified base table name. |
|
329 * |
|
330 * @param $table_expression |
|
331 * An SQL expression, for example "simpletest%" (without the quotes). |
|
332 * BEWARE: this is not prefixed, the caller should take care of that. |
|
333 * |
|
334 * @return |
|
335 * Array, both the keys and the values are the matching tables. |
|
336 */ |
|
337 public function findTables($table_expression) { |
|
338 $condition = $this->buildTableNameCondition($table_expression, 'LIKE', FALSE); |
|
339 |
|
340 $condition->compile($this->connection, $this); |
|
341 // Normally, we would heartily discourage the use of string |
|
342 // concatenation for conditionals like this however, we |
|
343 // couldn't use db_select() here because it would prefix |
|
344 // information_schema.tables and the query would fail. |
|
345 // Don't use {} around information_schema.tables table. |
|
346 return $this->connection->query("SELECT table_name FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchAllKeyed(0, 0); |
|
347 } |
|
348 |
|
349 /** |
|
350 * Check if a column exists in the given table. |
|
351 * |
|
352 * @param $table |
|
353 * The name of the table in drupal (no prefixing). |
|
354 * @param $name |
|
355 * The name of the column. |
|
356 * |
|
357 * @return |
|
358 * TRUE if the given column exists, otherwise FALSE. |
|
359 */ |
|
360 public function fieldExists($table, $column) { |
|
361 $condition = $this->buildTableNameCondition($table); |
|
362 $condition->condition('column_name', $column); |
|
363 $condition->compile($this->connection, $this); |
|
364 // Normally, we would heartily discourage the use of string |
|
365 // concatenation for conditionals like this however, we |
|
366 // couldn't use db_select() here because it would prefix |
|
367 // information_schema.tables and the query would fail. |
|
368 // Don't use {} around information_schema.columns table. |
|
369 return (bool) $this->connection->query("SELECT 1 FROM information_schema.columns WHERE " . (string) $condition, $condition->arguments())->fetchField(); |
|
370 } |
|
371 |
|
372 /** |
|
373 * Returns a mapping of Drupal schema field names to DB-native field types. |
|
374 * |
|
375 * Because different field types do not map 1:1 between databases, Drupal has |
|
376 * its own normalized field type names. This function returns a driver-specific |
|
377 * mapping table from Drupal names to the native names for each database. |
|
378 * |
|
379 * @return array |
|
380 * An array of Schema API field types to driver-specific field types. |
|
381 */ |
|
382 abstract public function getFieldTypeMap(); |
|
383 |
|
384 /** |
|
385 * Rename a table. |
|
386 * |
|
387 * @param $table |
|
388 * The table to be renamed. |
|
389 * @param $new_name |
|
390 * The new name for the table. |
|
391 * |
|
392 * @throws DatabaseSchemaObjectDoesNotExistException |
|
393 * If the specified table doesn't exist. |
|
394 * @throws DatabaseSchemaObjectExistsException |
|
395 * If a table with the specified new name already exists. |
|
396 */ |
|
397 abstract public function renameTable($table, $new_name); |
|
398 |
|
399 /** |
|
400 * Drop a table. |
|
401 * |
|
402 * @param $table |
|
403 * The table to be dropped. |
|
404 * |
|
405 * @return |
|
406 * TRUE if the table was successfully dropped, FALSE if there was no table |
|
407 * by that name to begin with. |
|
408 */ |
|
409 abstract public function dropTable($table); |
|
410 |
|
411 /** |
|
412 * Add a new field to a table. |
|
413 * |
|
414 * @param $table |
|
415 * Name of the table to be altered. |
|
416 * @param $field |
|
417 * Name of the field to be added. |
|
418 * @param $spec |
|
419 * The field specification array, as taken from a schema definition. |
|
420 * The specification may also contain the key 'initial', the newly |
|
421 * created field will be set to the value of the key in all rows. |
|
422 * This is most useful for creating NOT NULL columns with no default |
|
423 * value in existing tables. |
|
424 * @param $keys_new |
|
425 * (optional) Keys and indexes specification to be created on the |
|
426 * table along with adding the field. The format is the same as a |
|
427 * table specification but without the 'fields' element. If you are |
|
428 * adding a type 'serial' field, you MUST specify at least one key |
|
429 * or index including it in this array. See db_change_field() for more |
|
430 * explanation why. |
|
431 * |
|
432 * @throws DatabaseSchemaObjectDoesNotExistException |
|
433 * If the specified table doesn't exist. |
|
434 * @throws DatabaseSchemaObjectExistsException |
|
435 * If the specified table already has a field by that name. |
|
436 */ |
|
437 abstract public function addField($table, $field, $spec, $keys_new = array()); |
|
438 |
|
439 /** |
|
440 * Drop a field. |
|
441 * |
|
442 * @param $table |
|
443 * The table to be altered. |
|
444 * @param $field |
|
445 * The field to be dropped. |
|
446 * |
|
447 * @return |
|
448 * TRUE if the field was successfully dropped, FALSE if there was no field |
|
449 * by that name to begin with. |
|
450 */ |
|
451 abstract public function dropField($table, $field); |
|
452 |
|
453 /** |
|
454 * Set the default value for a field. |
|
455 * |
|
456 * @param $table |
|
457 * The table to be altered. |
|
458 * @param $field |
|
459 * The field to be altered. |
|
460 * @param $default |
|
461 * Default value to be set. NULL for 'default NULL'. |
|
462 * |
|
463 * @throws DatabaseSchemaObjectDoesNotExistException |
|
464 * If the specified table or field doesn't exist. |
|
465 */ |
|
466 abstract public function fieldSetDefault($table, $field, $default); |
|
467 |
|
468 /** |
|
469 * Set a field to have no default value. |
|
470 * |
|
471 * @param $table |
|
472 * The table to be altered. |
|
473 * @param $field |
|
474 * The field to be altered. |
|
475 * |
|
476 * @throws DatabaseSchemaObjectDoesNotExistException |
|
477 * If the specified table or field doesn't exist. |
|
478 */ |
|
479 abstract public function fieldSetNoDefault($table, $field); |
|
480 |
|
481 /** |
|
482 * Checks if an index exists in the given table. |
|
483 * |
|
484 * @param $table |
|
485 * The name of the table in drupal (no prefixing). |
|
486 * @param $name |
|
487 * The name of the index in drupal (no prefixing). |
|
488 * |
|
489 * @return |
|
490 * TRUE if the given index exists, otherwise FALSE. |
|
491 */ |
|
492 abstract public function indexExists($table, $name); |
|
493 |
|
494 /** |
|
495 * Add a primary key. |
|
496 * |
|
497 * @param $table |
|
498 * The table to be altered. |
|
499 * @param $fields |
|
500 * Fields for the primary key. |
|
501 * |
|
502 * @throws DatabaseSchemaObjectDoesNotExistException |
|
503 * If the specified table doesn't exist. |
|
504 * @throws DatabaseSchemaObjectExistsException |
|
505 * If the specified table already has a primary key. |
|
506 */ |
|
507 abstract public function addPrimaryKey($table, $fields); |
|
508 |
|
509 /** |
|
510 * Drop the primary key. |
|
511 * |
|
512 * @param $table |
|
513 * The table to be altered. |
|
514 * |
|
515 * @return |
|
516 * TRUE if the primary key was successfully dropped, FALSE if there was no |
|
517 * primary key on this table to begin with. |
|
518 */ |
|
519 abstract public function dropPrimaryKey($table); |
|
520 |
|
521 /** |
|
522 * Add a unique key. |
|
523 * |
|
524 * @param $table |
|
525 * The table to be altered. |
|
526 * @param $name |
|
527 * The name of the key. |
|
528 * @param $fields |
|
529 * An array of field names. |
|
530 * |
|
531 * @throws DatabaseSchemaObjectDoesNotExistException |
|
532 * If the specified table doesn't exist. |
|
533 * @throws DatabaseSchemaObjectExistsException |
|
534 * If the specified table already has a key by that name. |
|
535 */ |
|
536 abstract public function addUniqueKey($table, $name, $fields); |
|
537 |
|
538 /** |
|
539 * Drop a unique key. |
|
540 * |
|
541 * @param $table |
|
542 * The table to be altered. |
|
543 * @param $name |
|
544 * The name of the key. |
|
545 * |
|
546 * @return |
|
547 * TRUE if the key was successfully dropped, FALSE if there was no key by |
|
548 * that name to begin with. |
|
549 */ |
|
550 abstract public function dropUniqueKey($table, $name); |
|
551 |
|
552 /** |
|
553 * Add an index. |
|
554 * |
|
555 * @param $table |
|
556 * The table to be altered. |
|
557 * @param $name |
|
558 * The name of the index. |
|
559 * @param $fields |
|
560 * An array of field names. |
|
561 * |
|
562 * @throws DatabaseSchemaObjectDoesNotExistException |
|
563 * If the specified table doesn't exist. |
|
564 * @throws DatabaseSchemaObjectExistsException |
|
565 * If the specified table already has an index by that name. |
|
566 */ |
|
567 abstract public function addIndex($table, $name, $fields); |
|
568 |
|
569 /** |
|
570 * Drop an index. |
|
571 * |
|
572 * @param $table |
|
573 * The table to be altered. |
|
574 * @param $name |
|
575 * The name of the index. |
|
576 * |
|
577 * @return |
|
578 * TRUE if the index was successfully dropped, FALSE if there was no index |
|
579 * by that name to begin with. |
|
580 */ |
|
581 abstract public function dropIndex($table, $name); |
|
582 |
|
583 /** |
|
584 * Change a field definition. |
|
585 * |
|
586 * IMPORTANT NOTE: To maintain database portability, you have to explicitly |
|
587 * recreate all indices and primary keys that are using the changed field. |
|
588 * |
|
589 * That means that you have to drop all affected keys and indexes with |
|
590 * db_drop_{primary_key,unique_key,index}() before calling db_change_field(). |
|
591 * To recreate the keys and indices, pass the key definitions as the |
|
592 * optional $keys_new argument directly to db_change_field(). |
|
593 * |
|
594 * For example, suppose you have: |
|
595 * @code |
|
596 * $schema['foo'] = array( |
|
597 * 'fields' => array( |
|
598 * 'bar' => array('type' => 'int', 'not null' => TRUE) |
|
599 * ), |
|
600 * 'primary key' => array('bar') |
|
601 * ); |
|
602 * @endcode |
|
603 * and you want to change foo.bar to be type serial, leaving it as the |
|
604 * primary key. The correct sequence is: |
|
605 * @code |
|
606 * db_drop_primary_key('foo'); |
|
607 * db_change_field('foo', 'bar', 'bar', |
|
608 * array('type' => 'serial', 'not null' => TRUE), |
|
609 * array('primary key' => array('bar'))); |
|
610 * @endcode |
|
611 * |
|
612 * The reasons for this are due to the different database engines: |
|
613 * |
|
614 * On PostgreSQL, changing a field definition involves adding a new field |
|
615 * and dropping an old one which* causes any indices, primary keys and |
|
616 * sequences (from serial-type fields) that use the changed field to be dropped. |
|
617 * |
|
618 * On MySQL, all type 'serial' fields must be part of at least one key |
|
619 * or index as soon as they are created. You cannot use |
|
620 * db_add_{primary_key,unique_key,index}() for this purpose because |
|
621 * the ALTER TABLE command will fail to add the column without a key |
|
622 * or index specification. The solution is to use the optional |
|
623 * $keys_new argument to create the key or index at the same time as |
|
624 * field. |
|
625 * |
|
626 * You could use db_add_{primary_key,unique_key,index}() in all cases |
|
627 * unless you are converting a field to be type serial. You can use |
|
628 * the $keys_new argument in all cases. |
|
629 * |
|
630 * @param $table |
|
631 * Name of the table. |
|
632 * @param $field |
|
633 * Name of the field to change. |
|
634 * @param $field_new |
|
635 * New name for the field (set to the same as $field if you don't want to change the name). |
|
636 * @param $spec |
|
637 * The field specification for the new field. |
|
638 * @param $keys_new |
|
639 * (optional) Keys and indexes specification to be created on the |
|
640 * table along with changing the field. The format is the same as a |
|
641 * table specification but without the 'fields' element. |
|
642 * |
|
643 * @throws DatabaseSchemaObjectDoesNotExistException |
|
644 * If the specified table or source field doesn't exist. |
|
645 * @throws DatabaseSchemaObjectExistsException |
|
646 * If the specified destination field already exists. |
|
647 */ |
|
648 abstract public function changeField($table, $field, $field_new, $spec, $keys_new = array()); |
|
649 |
|
650 /** |
|
651 * Create a new table from a Drupal table definition. |
|
652 * |
|
653 * @param $name |
|
654 * The name of the table to create. |
|
655 * @param $table |
|
656 * A Schema API table definition array. |
|
657 * |
|
658 * @throws DatabaseSchemaObjectExistsException |
|
659 * If the specified table already exists. |
|
660 */ |
|
661 public function createTable($name, $table) { |
|
662 if ($this->tableExists($name)) { |
|
663 throw new DatabaseSchemaObjectExistsException(t('Table @name already exists.', array('@name' => $name))); |
|
664 } |
|
665 $statements = $this->createTableSql($name, $table); |
|
666 foreach ($statements as $statement) { |
|
667 $this->connection->query($statement); |
|
668 } |
|
669 } |
|
670 |
|
671 /** |
|
672 * Return an array of field names from an array of key/index column specifiers. |
|
673 * |
|
674 * This is usually an identity function but if a key/index uses a column prefix |
|
675 * specification, this function extracts just the name. |
|
676 * |
|
677 * @param $fields |
|
678 * An array of key/index column specifiers. |
|
679 * |
|
680 * @return |
|
681 * An array of field names. |
|
682 */ |
|
683 public function fieldNames($fields) { |
|
684 $return = array(); |
|
685 foreach ($fields as $field) { |
|
686 if (is_array($field)) { |
|
687 $return[] = $field[0]; |
|
688 } |
|
689 else { |
|
690 $return[] = $field; |
|
691 } |
|
692 } |
|
693 return $return; |
|
694 } |
|
695 |
|
696 /** |
|
697 * Prepare a table or column comment for database query. |
|
698 * |
|
699 * @param $comment |
|
700 * The comment string to prepare. |
|
701 * @param $length |
|
702 * Optional upper limit on the returned string length. |
|
703 * |
|
704 * @return |
|
705 * The prepared comment. |
|
706 */ |
|
707 public function prepareComment($comment, $length = NULL) { |
|
708 return $this->connection->quote($comment); |
|
709 } |
|
710 } |
|
711 |
|
712 /** |
|
713 * Exception thrown if an object being created already exists. |
|
714 * |
|
715 * For example, this exception should be thrown whenever there is an attempt to |
|
716 * create a new database table, field, or index that already exists in the |
|
717 * database schema. |
|
718 */ |
|
719 class DatabaseSchemaObjectExistsException extends Exception {} |
|
720 |
|
721 /** |
|
722 * Exception thrown if an object being modified doesn't exist yet. |
|
723 * |
|
724 * For example, this exception should be thrown whenever there is an attempt to |
|
725 * modify a database table, field, or index that does not currently exist in |
|
726 * the database schema. |
|
727 */ |
|
728 class DatabaseSchemaObjectDoesNotExistException extends Exception {} |
|
729 |
|
730 /** |
|
731 * @} End of "defgroup schemaapi". |
|
732 */ |
|
733 |