Code coverage for /20081101/includes/database/schema.inc

Line #Times calledCode
1
<?php
2
// $Id: schema.inc,v 1.4 2008/10/31 15:46:16 webchick Exp $
3
4
/**
5
 * @file
6
 * Generic Database schema code.
7
 */
8
9
/**
10
 * @defgroup schemaapi Schema API
11
 * @{
12
 *
13
 * A Drupal schema definition is an array structure representing one or
14
 * more tables and their related keys and indexes. A schema is defined by
15
 * hook_schema(), which usually lives in a modulename.install file.
16
 *
17
 * By implementing hook_schema() and specifying the tables your module
18
 * declares, you can easily create and drop these tables on all
19
 * supported database engines. You don't have to deal with the
20
 * different SQL dialects for table creation and alteration of the
21
 * supported database engines.
22
 *
23
 * hook_schema() should return an array with a key for each table that
24
 * the module defines.
25
 *
26
 * The following keys are defined:
27
 *
28
 *   - 'description': A string describing this table and its purpose.
29
 *     References to other tables should be enclosed in
30
 *     curly-brackets.  For example, the node_revisions table
31
 *     description field might contain "Stores per-revision title and
32
 *     body data for each {node}."
33
 *   - 'fields': An associative array ('fieldname' => specification)
34
 *     that describes the table's database columns.  The specification
35
 *     is also an array.  The following specification parameters are
defined:
36
 *
37
 *     - 'description': A string describing this field and its purpose.
38
 *       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_revisions}.vid value for this nid."
42
 *     - 'type': The generic datatype: 'varchar', 'int', 'serial'
43
 *       'float', 'numeric', 'text', 'blob' or 'datetime'.  Most types
44
 *       just map to the according database engine specific
45
 *       datatypes.  Use 'serial' for auto incrementing fields. This
46
 *       will expand to 'int auto_increment' on mysql.
47
 *     - 'size': The data size: 'tiny', 'small', 'medium', 'normal',
48
 *       'big'.  This is a hint about the largest value the field will
49
 *       store and determines which of the database engine specific
50
 *       datatypes will be used (e.g. on MySQL, TINYINT vs. INT vs.
BIGINT).
51
 *       'normal', the default, selects the base type (e.g. on MySQL,
52
 *       INT, VARCHAR, BLOB, etc.).
53
 *
54
 *       Not all sizes are available for all data types. See
55
 *       db_type_map() for possible combinations.
56
 *     - 'not null': If true, no NULL values will be allowed in this
57
 *       database column.  Defaults to false.
58
 *     - 'default': The field's default value.  The PHP type of the
59
 *       value matters: '', '0', and 0 are all different.  If you
60
 *       specify '0' as the default value for a type 'int' field it
61
 *       will not work because '0' is a string containing the
62
 *       character "zero", not an integer.
63
 *     - 'length': The maximal length of a type 'varchar' or 'text'
64
 *       field.  Ignored for other field types.
65
 *     - 'unsigned': A boolean indicating whether a type 'int', 'float'
66
 *       and 'numeric' only is signed or unsigned.  Defaults to
67
 *       FALSE.  Ignored for other field types.
68
 *     - 'precision', 'scale': For type 'numeric' fields, indicates
69
 *       the precision (total number of significant digits) and scale
70
 *       (decimal digits right of the decimal point).  Both values are
71
 *       mandatory.  Ignored for other field types.
72
 *
73
 *     All parameters apart from 'type' are optional except that type
74
 *     'numeric' columns must specify 'precision' and 'scale'.
75
 *
76
 *  - 'primary key': An array of one or more key column specifiers (see
below)
77
 *    that form the primary key.
78
 *  - 'unique key': An associative array of unique keys ('keyname' =>
79
 *    specification).  Each specification is an array of one or more
80
 *    key column specifiers (see below) that form a unique key on the
table.
81
 *  - 'indexes':  An associative array of indexes ('indexame' =>
82
 *    specification).  Each specification is an array of one or more
83
 *    key column specifiers (see below) that form an index on the
84
 *    table.
85
 *
86
 * A key column specifier is either a string naming a column or an
87
 * array of two elements, column name and length, specifying a prefix
88
 * of the named column.
89
 *
90
 * As an example, here is a SUBSET of the schema definition for
91
 * Drupal's 'node' table.  It show four fields (nid, vid, type, and
92
 * title), the primary key on field 'nid', a unique key named 'vid' on
93
 * field 'vid', and two indexes, one named 'nid' on field 'nid' and
94
 * one named 'node_title_type' on the field 'title' and the first four
95
 * bytes of the field 'type':
96
 *
97
 * @code
98
 * $schema['node'] = array(
99
 *   'fields' => array(
100
 *     'nid'      => array('type' => 'serial', 'unsigned' => TRUE, 'not
null' => TRUE),
101
 *     'vid'      => array('type' => 'int', 'unsigned' => TRUE, 'not null'
=> TRUE, 'default' => 0),
102
 *     'type'     => array('type' => 'varchar', 'length' => 32, 'not null'
=> TRUE, 'default' => ''),
103
 *     'title'    => array('type' => 'varchar', 'length' => 128, 'not null'
=> TRUE, 'default' => ''),
104
 *   ),
105
 *   'primary key' => array('nid'),
106
 *   'unique keys' => array(
107
 *     'vid'     => array('vid')
108
 *   ),
109
 *   'indexes' => array(
110
 *     'nid'                 => array('nid'),
111
 *     'node_title_type'     => array('title', array('type', 4)),
112
 *   ),
113
 * );
114
 * @endcode
115
 *
116
 * @see drupal_install_schema()
117
 */
118
119137
abstract class DatabaseSchema {
120
121
  protected $connection;
122
123
  public function __construct($connection) {
124137
    $this->connection = $connection;
125137
  }
126
127
  /**
128
   * Check if a table exists.
129
   */
130
  abstract public function tableExists($table);
131
132
  /**
133
   * Check if a column exists in the given table.
134
   */
135
  abstract public function columnExists($table, $column);
136
137
  /**
138
   * This maps a generic data type in combination with its data size
139
   * to the engine-specific data type.
140
   */
141
  abstract public function getFieldTypeMap();
142
143
  /**
144
   * Rename a table.
145
   *
146
   * @param $ret
147
   *   Array to which query results will be added.
148
   * @param $table
149
   *   The table to be renamed.
150
   * @param $new_name
151
   *   The new name for the table.
152
   */
153
  abstract public function renameTable(&$ret, $table, $new_name);
154
155
  /**
156
   * Drop a table.
157
   *
158
   * @param $ret
159
   *   Array to which query results will be added.
160
   * @param $table
161
   *   The table to be dropped.
162
   */
163
  abstract public function dropTable(&$ret, $table);
164
165
  /**
166
   * Add a new field to a table.
167
   *
168
   * @param $ret
169
   *   Array to which query results will be added.
170
   * @param $table
171
   *   Name of the table to be altered.
172
   * @param $field
173
   *   Name of the field to be added.
174
   * @param $spec
175
   *   The field specification array, as taken from a schema definition.
176
   *   The specification may also contain the key 'initial', the newly
177
   *   created field will be set to the value of the key in all rows.
178
   *   This is most useful for creating NOT NULL columns with no default
179
   *   value in existing tables.
180
   * @param $keys_new
181
   *   Optional keys and indexes specification to be created on the
182
   *   table along with adding the field. The format is the same as a
183
   *   table specification but without the 'fields' element.  If you are
184
   *   adding a type 'serial' field, you MUST specify at least one key
185
   *   or index including it in this array. @see db_change_field for more
186
   *   explanation why.
187
   */
188
  abstract public function addField(&$ret, $table, $field, $spec, $keys_new
= array());
189
190
  /**
191
   * Drop a field.
192
   *
193
   * @param $ret
194
   *   Array to which query results will be added.
195
   * @param $table
196
   *   The table to be altered.
197
   * @param $field
198
   *   The field to be dropped.
199
   */
200
  abstract public function dropField(&$ret, $table, $field);
201
202
  /**
203
   * Set the default value for a field.
204
   *
205
   * @param $ret
206
   *   Array to which query results will be added.
207
   * @param $table
208
   *   The table to be altered.
209
   * @param $field
210
   *   The field to be altered.
211
   * @param $default
212
   *   Default value to be set. NULL for 'default NULL'.
213
   */
214
  abstract public function fieldSetDefault(&$ret, $table, $field,
$default);
215
216
  /**
217
   * Set a field to have no default value.
218
   *
219
   * @param $ret
220
   *   Array to which query results will be added.
221
   * @param $table
222
   *   The table to be altered.
223
   * @param $field
224
   *   The field to be altered.
225
   */
226
  abstract public function fieldSetNoDefault(&$ret, $table, $field);
227
228
  /**
229
   * Add a primary key.
230
   *
231
   * @param $ret
232
   *   Array to which query results will be added.
233
   * @param $table
234
   *   The table to be altered.
235
   * @param $fields
236
   *   Fields for the primary key.
237
   */
238
  abstract public function addPrimaryKey(&$ret, $table, $fields);
239
240
  /**
241
   * Drop the primary key.
242
   *
243
   * @param $ret
244
   *   Array to which query results will be added.
245
   * @param $table
246
   *   The table to be altered.
247
   */
248
  abstract public function dropPrimaryKey(&$ret, $table);
249
250
  /**
251
   * Add a unique key.
252
   *
253
   * @param $ret
254
   *   Array to which query results will be added.
255
   * @param $table
256
   *   The table to be altered.
257
   * @param $name
258
   *   The name of the key.
259
   * @param $fields
260
   *   An array of field names.
261
   */
262
  abstract public function addUniqueKey(&$ret, $table, $name, $fields);
263
264
  /**
265
   * Drop a unique key.
266
   *
267
   * @param $ret
268
   *   Array to which query results will be added.
269
   * @param $table
270
   *   The table to be altered.
271
   * @param $name
272
   *   The name of the key.
273
   */
274
  abstract public function dropUniqueKey(&$ret, $table, $name);
275
276
  /**
277
   * Add an index.
278
   *
279
   * @param $ret
280
   *   Array to which query results will be added.
281
   * @param $table
282
   *   The table to be altered.
283
   * @param $name
284
   *   The name of the index.
285
   * @param $fields
286
   *   An array of field names.
287
   */
288
  abstract public function addIndex(&$ret, $table, $name, $fields);
289
290
  /**
291
   * Drop an index.
292
   *
293
   * @param $ret
294
   *   Array to which query results will be added.
295
   * @param $table
296
   *   The table to be altered.
297
   * @param $name
298
   *   The name of the index.
299
   */
300
  abstract public function dropIndex(&$ret, $table, $name);
301
302
303
  /**
304
   * Change a field definition.
305
   *
306
   * IMPORTANT NOTE: To maintain database portability, you have to
explicitly
307
   * recreate all indices and primary keys that are using the changed
field.
308
   *
309
   * That means that you have to drop all affected keys and indexes with
310
   * db_drop_{primary_key,unique_key,index}() before calling
db_change_field().
311
   * To recreate the keys and indices, pass the key definitions as the
312
   * optional $keys_new argument directly to db_change_field().
313
   *
314
   * For example, suppose you have:
315
   * @code
316
   * $schema['foo'] = array(
317
   *   'fields' => array(
318
   *     'bar' => array('type' => 'int', 'not null' => TRUE)
319
   *   ),
320
   *   'primary key' => array('bar')
321
   * );
322
   * @endcode
323
   * and you want to change foo.bar to be type serial, leaving it as the
324
   * primary key.  The correct sequence is:
325
   * @code
326
   * db_drop_primary_key($ret, 'foo');
327
   * db_change_field($ret, 'foo', 'bar', 'bar',
328
   *   array('type' => 'serial', 'not null' => TRUE),
329
   *   array('primary key' => array('bar')));
330
   * @endcode
331
   *
332
   * The reasons for this are due to the different database engines:
333
   *
334
   * On PostgreSQL, changing a field definition involves adding a new field
335
   * and dropping an old one which* causes any indices, primary keys and
336
   * sequences (from serial-type fields) that use the changed field to be
dropped.
337
   *
338
   * On MySQL, all type 'serial' fields must be part of at least one key
339
   * or index as soon as they are created.  You cannot use
340
   * db_add_{primary_key,unique_key,index}() for this purpose because
341
   * the ALTER TABLE command will fail to add the column without a key
342
   * or index specification.  The solution is to use the optional
343
   * $keys_new argument to create the key or index at the same time as
344
   * field.
345
   *
346
   * You could use db_add_{primary_key,unique_key,index}() in all cases
347
   * unless you are converting a field to be type serial. You can use
348
   * the $keys_new argument in all cases.
349
   *
350
   * @param $ret
351
   *   Array to which query results will be added.
352
   * @param $table
353
   *   Name of the table.
354
   * @param $field
355
   *   Name of the field to change.
356
   * @param $field_new
357
   *   New name for the field (set to the same as $field if you don't want
to change the name).
358
   * @param $spec
359
   *   The field specification for the new field.
360
   * @param $keys_new
361
   *   Optional keys and indexes specification to be created on the
362
   *   table along with changing the field. The format is the same as a
363
   *   table specification but without the 'fields' element.
364
   */
365
  abstract public function changeField(&$ret, $table, $field, $field_new,
$spec, $keys_new = array());
366
367
  /**
368
   * Create a new table from a Drupal table definition.
369
   *
370
   * @param $ret
371
   *   Array to which query results will be added.
372
   * @param $name
373
   *   The name of the table to create.
374
   * @param $table
375
   *   A Schema API table definition array.
376
   */
377
  public function createTable(&$ret, $name, $table) {
378136
    $statements = $this->createTableSql($name, $table);
379136
    foreach ($statements as $statement) {
380136
      $ret[] = update_sql($statement);
381136
    }
382136
  }
383
384
  /**
385
   * Return an array of field names from an array of key/index column
specifiers.
386
   *
387
   * This is usually an identity function but if a key/index uses a column
prefix
388
   * specification, this function extracts just the name.
389
   *
390
   * @param $fields
391
   *   An array of key/index column specifiers.
392
   * @return
393
   *   An array of field names.
394
   */
395
  public function fieldNames($fields) {
3960
    $ret = array();
3970
    foreach ($fields as $field) {
3980
      if (is_array($field)) {
3990
        $ret[] = $field[0];
4000
      }
401
      else {
4020
        $ret[] = $field;
403
      }
4040
    }
4050
    return $ret;
4060
  }
407
408
  /**
409
   * Find all tables that are like the specified base table name.
410
   *
411
   * @param $table_expression
412
   *   An SQL expression, for example "simpletest%" (without the quotes).
413
   *   BEWARE: this is not prefixed, the caller should take care of that.
414
   * @return
415
   *   Array, both the keys and the values are the matching tables.
416
   */
417
  public function findTables($table_expression) {
4181
    global $db_prefix;
4191
    $info = Database::getConnectionInfo();
4201
    $result = db_query("SELECT table_name FROM information_schema.tables
WHERE table_schema = :database AND table_name LIKE :table_name", array(
4211
      ':database' => $info['default']['database'],
4221
      ':table_name' => $table_expression,
4231
    ));
4241
    return $result->fetchAllKeyed(0, 0);
4250
  }
426
}
427
428
/**
429
 * @} End of "defgroup schemaapi".
430
 */
431
432137