annotate includes/database/schema.inc @ 13:134d4b2e75f6

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