Commit 3cafffe6 authored by Dries's avatar Dries

- Killer patch #144765 by bjaspan, frando et al: schema API 1 hits core. Oh, behave.

parent ae762838
......@@ -2513,6 +2513,160 @@ function drupal_common_themes() {
);
}
/**
* @ingroup schemaapi
* @{
*/
/**
* Get the schema defintion of a table, or the whole database schema.
* The returned schema will include any modifications made by any
* module that implements hook_schema_alter().
*
* @param $name
* The name of the table. If not given, the schema of all tables is returned.
* @param $rebuild
* If true, the schema will be rebuilt instead of retreived from the cache.
*/
function drupal_get_schema($name = NULL, $rebuild = FALSE) {
static $schema = array();
if (empty($schema) || $rebuild) {
// Try to load the schema from cache.
if (!$rebuild && $cached = cache_get('schema')) {
$schema = $cached->data;
}
// Otherwise, rebuild the schema cache.
else {
// Load the .schema files.
module_load_all_includes('schema');
// Invoke hook_schema for all modules.
foreach (module_implements('schema') as $module) {
$current = module_invoke($module, 'schema');
_drupal_initialize_schema($module, $current);
$schema = array_merge($current, $schema);
}
drupal_alter('schema', $schema);
cache_set('schema', $schema);
}
}
if (!isset($name)) {
return $schema;
}
elseif (isset($schema[$name])) {
return $schema[$name];
}
else {
return FALSE;
}
}
/**
* Create all tables that a module defines in its hook_schema().
*
* Note: This function does not pass the module's schema through
* hook_schema_alter(). The module's tables will be created exactly
* as the module defines them.
*
* @param $module
* The module for which the tables will be created.
*/
function drupal_install_schema($module) {
$schema = drupal_get_schema_unprocessed($module);
_drupal_initialize_schema($module, $schema);
$ret = array();
foreach ($schema as $table) {
db_create_table($ret, $table);
}
}
/**
* Remove all tables that a module defines in its hook_schema().
*
* Note: This function does not pass the module's schema through
* hook_schema_alter(). The module's tables will be created exactly
* as the module defines them.
*
* @param $module
* The module for which the tables will be removed.
*/
function drupal_uninstall_schema($module) {
$schema = drupal_get_schema_unprocessed($module);
_drupal_initialize_schema($module, $schema);
$ret = array();
foreach ($schema as $table) {
db_drop_table($ret, $table['name']);
}
}
/**
* Returns the unprocessed and unaltered version of a module's schema.
*
* Use this function only if you explicitly need the original
* specification of a schema, as it was defined in a module's
* hook_schema(). No additional default values will be set,
* hook_schema_alter() is not invoked and these unprocessed
* definitions won't be cached.
*
* This function can be used to retrieve a schema specification in
* hook_schema(), so it allows you to derive your tables from existing
* specifications.
*
* It is also used by drupal_install_schema() and
* drupal_uninstall_schema() to ensure that a module's tables are
* created exactly as specified without any changes introduced by a
* module that implements hook_schema_alter().
*
* @param $module
* The module to which the table belongs.
* @param $table
* The name of the table. If not given, the module's complete schema
* is returned.
*/
function drupal_get_schema_unprocessed($module, $table = NULL) {
// Load the .schema file.
module_load_include('schema', $module);
$schema = module_invoke($module, 'schema');
if (!is_null($table) && isset($schema[$table])) {
return $schema[$table];
}
else {
return $schema;
}
}
/**
* Fill in required default values for table definitions returned by
* hook_schema().
*
* @param $module
* The module for which hook_schema() was invoked.
* @param $schema
* The schema definition array as it was returned by the module's
* hook_schema().
*/
function _drupal_initialize_schema($module, &$schema) {
// Set the name and module key for all tables.
foreach ($schema as $name => $table) {
if (empty($table['module'])) {
$schema[$name]['module'] = $module;
}
if (!isset($table['name'])) {
$schema[$name]['name'] = $name;
}
}
}
/**
* @} End of "ingroup schemaapi".
*/
/**
* Parse Drupal info file format.
*
......
......@@ -43,6 +43,22 @@
* common pattern of iterating over the result set using db_fetch_object().
*/
/**
* Perform an SQL query and return success or failure.
*
* @param $sql
* A string containing a complete SQL query. %-substitution
* parameters are not supported.
* @return
* An array containing the keys:
* success: a boolean indicating whether the query succeeded
* query: the SQL query executed, passed through check_plain()
*/
function update_sql($sql) {
$result = db_query($sql, true);
return array('success' => $result !== FALSE, 'query' => check_plain($sql));
}
/**
* Append a database prefix to all tables in a query.
*
......@@ -317,3 +333,144 @@ function db_escape_table($string) {
* @} End of "defgroup database".
*/
/**
* @defgroup schemaapi Schema API
* @{
*
* A Drupal schema definition is an array structure representing one or
* more tables and their related keys and indexes. A schema is defined by
* hook_schema(), which usually lives in a modulename.schema file.
*
* By implenting hook_schema() and specifying the tables your module
* declares, you can easily create and drop these tables on all
* supported database engines. You don't have to deal with the
* different SQL dialects for table creation and alteration of the
* supported database engines.
*
* hook_schema() should return an array with a key for each table that
* the module defines.
*
* The following keys in the table definition are processed during
* table creation:
*
* - 'fields': An associative array ('fieldname' => specification)
* that describes the table's database columns. The specification
* is also an array. The following specification parameters are defined:
*
* - 'type': The generic datatype: 'varchar', 'int', 'serial'
* 'float', 'numeric', 'text', 'blob' or 'datetime'. Most types
* just map to the according database engine specific
* datatypes. Use 'serial' for auto incrementing fields. This
* will expand to 'int auto_increment' on mysql.
* - 'size': The data size: 'tiny', 'small', 'medium', 'normal',
* 'big'. This is a hint about the largest value the field will
* store and determines which of the database engine specific
* datatypes will be used (e.g. on MySQL, TINYINT vs. INT vs. BIGINT).
* 'normal', the default, selects the base type (e.g. on MySQL,
* INT, VARCHAR, BLOB, etc.).
*
* Not all sizes are available for all data types. See
* db_type_map() for possible combinations.
* - 'not null': If true, no NULL values will be allowed in this
* database column. Defaults to false.
* - 'default': The field's default value. The PHP type of the
* value matters: '', '0', and 0 are all different. If you
* specify '0' as the default value for a type 'int' field it
* will not work because '0' is a string containing the
* character "zero", not an integer.
* - 'length': The maximal length of a type 'varchar' or 'text'
* field. Ignored for other field types.
* - 'unsigned': A boolean indicating whether a type 'int', 'float'
* and 'numeric' only is signed or unsigned. Defaults to
* FALSE. Ignored for other field types.
* - 'precision', 'scale': For type 'numeric' fields, indicates
* the precision (total number of significant digits) and scale
* (decimal digits right of the decimal point). Both values are
* mandatory. Ignored for other field types.
*
* All parameters apart from 'type' are optional except that type
* 'numeric' columns must specify 'precision' and 'scale'.
*
* - 'primary key': An array of one or more key column specifers (see below)
* that form the primary key.
* - 'unique key': An associative array of unique keys ('keyname' =>
* specification). Each specification is an array of one or more
* key column specifiers (see below) that form a unique key on the table.
* - 'indexes': An associative array of indexes ('indexame' =>
* specification). Each specification is an array of one or more
* key column specifiers (see below) that form an index on the
* table.
*
* A key column specifier is either a string naming a column or an
* array of two elements, column name and length, specifying a prefix
* of the named column.
*
* As an example, here is a SUBSET of the schema definition for
* Drupal's 'node' table. It show four fields (nid, vid, type, and
* title), the primary key on field 'nid', a unique key named 'vid' on
* field 'vid', and two indexes, one named 'nid' on field 'nid' and
* one named 'node_title_type' on the field 'title' and the first four
* bytes of the field 'type':
*
* $schema['node'] = array(
* 'fields' => array(
* 'nid' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
* 'vid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
* 'type' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''),
'title' => array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''),
* ),
* 'primary key' => array('nid'),
* 'unique keys' => array(
* 'vid' => array('vid')
* ),
* 'indexes' => array(
* 'nid' => array('nid'),
* 'node_title_type' => array('title', array('type', 4)),
* ),
* );
*
* @see drupal_install_schema()
*/
/**
* Create a new table from a Drupal table definition.
*
* @param $ret
* Array to which query results will be added.
* @param $table
* A valid and processed table schema definition array.
*/
function db_create_table(&$ret, $table) {
$statements = db_create_table_sql($table);
foreach ($statements as $statement) {
$ret[] = update_sql($statement);
}
}
/**
* Return an array of field names from an array of key/index column
* specifiers. This is usually an identity function but if a
* key/index uses a column prefix specification, this function
* extracts just the name.
*
* @param $fields
* An array of key/index column specifiers.
* @return
* An array of field names.
*/
function db_field_names($fields) {
$ret = array();
foreach ($fields as $field) {
if (is_array($field)) {
$ret[] = $field[0];
}
else {
$ret[] = $field;
}
}
return $ret;
}
/**
* @} End of "defgroup schemaapi".
*/
This diff is collapsed.
......@@ -11,6 +11,8 @@
* @{
*/
// Include functions shared between mysql and mysqli.
require_once './includes/database.mysql-common.inc';
/**
* Report database status.
......@@ -437,5 +439,3 @@ function db_distinct_field($table, $field, $query) {
/**
* @} End of "ingroup database".
*/
......@@ -15,6 +15,9 @@
* @{
*/
// Include functions shared between mysql and mysqli.
require_once './includes/database.mysql-common.inc';
/**
* Report database status.
*/
......
This diff is collapsed.
......@@ -189,9 +189,42 @@ function module_load_install($module) {
// Make sure the installation API is available
include_once './includes/install.inc';
$install_file = './'. drupal_get_path('module', $module) .'/'. $module .'.install';
if (is_file($install_file)) {
include_once $install_file;
module_load_include('install', $module);
}
/**
* Load a module include file.
*
* @param $type
* The include file's type (file extension).
* @param $module
* The module to which the include file belongs.
* @param $name
* Optionally, specify the file name. If not set, the module's name is used.
*/
function module_load_include($type, $module, $name = NULL) {
if (empty($name)) {
$name = $module;
}
$file = './'. drupal_get_path('module', $module) ."/$name.$type";
if (is_file($file)) {
require_once $file;
}
else {
return FALSE;
}
}
/**
* Load an include file for each of the modules that have been enabled in
* the system table.
*/
function module_load_all_includes($type, $name = NULL) {
$modules = module_list();
foreach ($modules as $module) {
module_load_include($type, $module, $name);
}
}
......
......@@ -5,126 +5,17 @@
* Implementation of hook_install().
*/
function aggregator_install() {
switch ($GLOBALS['db_type']) {
case 'mysql':
case 'mysqli':
db_query("CREATE TABLE {aggregator_category} (
cid int NOT NULL auto_increment,
title varchar(255) NOT NULL default '',
description longtext NOT NULL,
block tinyint NOT NULL default '0',
PRIMARY KEY (cid),
UNIQUE KEY title (title)
) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
db_query("CREATE TABLE {aggregator_category_feed} (
fid int NOT NULL default '0',
cid int NOT NULL default '0',
PRIMARY KEY (fid,cid)
) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
db_query("CREATE TABLE {aggregator_category_item} (
iid int NOT NULL default '0',
cid int NOT NULL default '0',
PRIMARY KEY (iid,cid)
) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
db_query("CREATE TABLE {aggregator_feed} (
fid int NOT NULL auto_increment,
title varchar(255) NOT NULL default '',
url varchar(255) NOT NULL default '',
refresh int NOT NULL default '0',
checked int NOT NULL default '0',
link varchar(255) NOT NULL default '',
description longtext NOT NULL,
image longtext NOT NULL,
etag varchar(255) NOT NULL default '',
modified int NOT NULL default '0',
block tinyint NOT NULL default '0',
PRIMARY KEY (fid),
UNIQUE KEY link (url),
UNIQUE KEY title (title)
) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
db_query("CREATE TABLE {aggregator_item} (
iid int NOT NULL auto_increment,
fid int NOT NULL default '0',
title varchar(255) NOT NULL default '',
link varchar(255) NOT NULL default '',
author varchar(255) NOT NULL default '',
description longtext NOT NULL,
timestamp int default NULL,
guid varchar(255),
PRIMARY KEY (iid),
KEY fid (fid)
) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
break;
case 'pgsql':
db_query("CREATE TABLE {aggregator_category} (
cid serial,
title varchar(255) NOT NULL default '',
description text NOT NULL,
block smallint NOT NULL default '0',
PRIMARY KEY (cid),
UNIQUE (title)
)");
db_query("CREATE TABLE {aggregator_category_feed} (
fid int NOT NULL default '0',
cid int NOT NULL default '0',
PRIMARY KEY (fid,cid)
)");
db_query("CREATE TABLE {aggregator_category_item} (
iid int NOT NULL default '0',
cid int NOT NULL default '0',
PRIMARY KEY (iid,cid)
)");
db_query("CREATE TABLE {aggregator_feed} (
fid serial,
title varchar(255) NOT NULL default '',
url varchar(255) NOT NULL default '',
refresh int NOT NULL default '0',
checked int NOT NULL default '0',
link varchar(255) NOT NULL default '',
description text NOT NULL default '',
image text NOT NULL default '',
etag varchar(255) NOT NULL default '',
modified int NOT NULL default '0',
block smallint NOT NULL default '0',
PRIMARY KEY (fid),
UNIQUE (url),
UNIQUE (title)
)");
db_query("CREATE TABLE {aggregator_item} (
iid serial,
fid int NOT NULL default '0',
title varchar(255) NOT NULL default '',
link varchar(255) NOT NULL default '',
author varchar(255) NOT NULL default '',
description text NOT NULL,
timestamp int default NULL,
guid varchar(255),
PRIMARY KEY (iid)
)");
db_query("CREATE INDEX {aggregator_item}_fid_idx ON {aggregator_item} (fid)");
break;
}
// Create tables.
drupal_install_schema('aggregator');
}
/**
* Implementation of hook_uninstall().
*/
function aggregator_uninstall() {
db_query('DROP TABLE {aggregator_category}');
db_query('DROP TABLE {aggregator_category_feed}');
db_query('DROP TABLE {aggregator_category_item}');
db_query('DROP TABLE {aggregator_feed}');
db_query('DROP TABLE {aggregator_item}');
// Remove tables.
drupal_uninstall_schema('aggregator');
variable_del('aggregator_allowed_html_tags');
variable_del('aggregator_summary_items');
variable_del('aggregator_clear');
......
<?php
// $Id$
function aggregator_schema() {
$schema['aggregator_category'] = array(
'fields' => array(
'cid' => array('type' => 'serial', 'not null' => TRUE),
'title' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
'description' => array('type' => 'text', 'not null' => TRUE, 'size' => 'big'),
'block' => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'tiny')
),
'primary key' => array('cid'),
'unique keys' => array('title' => array('title')),
);
$schema['aggregator_category_feed'] = array(
'fields' => array(
'fid' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
'cid' => array('type' => 'int', 'not null' => TRUE, 'default' => 0)
),
'primary key' => array('fid', 'cid'),
);
$schema['aggregator_category_item'] = array(
'fields' => array(
'iid' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
'cid' => array('type' => 'int', 'not null' => TRUE, 'default' => 0)
),
'primary key' => array('iid', 'cid'),
);
$schema['aggregator_feed'] = array(
'fields' => array(
'fid' => array('type' => 'serial', 'not null' => TRUE),
'title' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
'url' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
'refresh' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
'checked' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
'link' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
'description' => array('type' => 'text', 'not null' => TRUE, 'size' => 'big'),
'image' => array('type' => 'text', 'not null' => TRUE, 'size' => 'big'),
'etag' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
'modified' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
'block' => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'tiny')
),
'unique keys' => array(
'url' => array('url'),
'title' => array('title')
),
'primary key' => array('fid'),
);
$schema['aggregator_item'] = array(
'fields' => array(
'iid' => array('type' => 'serial', 'not null' => TRUE),
'fid' => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
'title' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
'link' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
'author' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
'description' => array('type' => 'text', 'not null' => TRUE, 'size' => 'big'),
'timestamp' => array('type' => 'int', 'not null' => FALSE),
'guid' => array('type' => 'varchar', 'length' => 255, 'not null' => FALSE)
),
'indexes' => array('fid' => array('fid')),
'primary key' => array('iid'),
);
return $schema;
}
<?php
// $Id$
function block_schema() {
$schema['blocks'] = array(
'fields' => array(
'bid' => array('type' => 'serial', 'not null' => TRUE),
'module' => array('type' => 'varchar', 'length' => 64, 'not null' => TRUE, 'default' => ''),
'delta' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => '0'),
'theme' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
'status' => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'tiny'),
'weight' => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'tiny'),
'region' => array('type' => 'varchar', 'length' => 64, 'not null' => TRUE, 'default' => 'left'),
'custom' => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'tiny'),
'throttle' => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'tiny'),
'visibility' => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'tiny'),
'pages' => array('type' => 'text', 'not null' => TRUE),
'title' => array('type' => 'varchar', 'length' => 64, 'not null' => TRUE, 'default' => '')
),
'primary key' => array('bid'),
);
$schema['blocks_roles'] = array(
'fields' => array(
'module' => array('type' => 'varchar', 'length' => 64, 'not null' => TRUE),
'delta' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE),
'rid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE)
),
'primary key' => array(
'module',
'delta',
'rid'
),
);
$schema['boxes'] = array(
'fields' => array(
'bid' => array('type' => 'serial', 'not null' => TRUE),
'body' => array('type' => 'text', 'not null' => FALSE, 'size' => 'big'),
'info' => array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''),
'format' => array('type' => 'int', 'size' => 'small', 'not null' => TRUE, 'default' => 0)
),
'unique keys' => array('info' => array('info')),
'primary key' => array('bid'),
);
return $schema;
}
......@@ -5,36 +5,14 @@
* Implementation of hook_install().
*/
function book_install() {
switch ($GLOBALS['db_type']) {
case 'mysql':
case 'mysqli':
db_query("CREATE TABLE {book} (
vid int unsigned NOT NULL default '0',
nid int unsigned NOT NULL default '0',
parent int NOT NULL default '0',
weight tinyint NOT NULL default '0',
PRIMARY KEY (vid),
KEY nid (nid),
KEY parent (parent)
) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
break;
case 'pgsql':