Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
project
drupal
Commits
3cafffe6
Commit
3cafffe6
authored
May 25, 2007
by
Dries Buytaert
Browse files
- Killer patch
#144765
by bjaspan, frando et al: schema API 1 hits core. Oh, behave.
parent
ae762838
Changes
40
Hide whitespace changes
Inline
Side-by-side
includes/common.inc
View file @
3cafffe6
...
...
@@ -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.
*
...
...
includes/database.inc
View file @
3cafffe6
...
...
@@ -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".
*/
includes/database.mysql-common.inc
0 → 100644
View file @
3cafffe6
<?php
// $Id$
/**
* @file
* Functions shared between mysql and mysqli database engines.
*/
/**
* @ingroup schemaapi
* @{
*/
/**
* Generate SQL to create a new table from a Drupal schema definition.
*
* @param $table
* A valid Drupal table definition array.
* @return
* An array of SQL statements to create the table.
*/
function
db_create_table_sql
(
$table
)
{
if
(
empty
(
$table
[
'mysql_suffix'
]))
{
$table
[
'mysql_suffix'
]
=
"/*!40100 DEFAULT CHARACTER SET UTF8 */"
;
}
$sql
=
"CREATE TABLE {"
.
$table
[
'name'
]
.
"} (
\n
"
;
// Add the SQL statement for each field.
foreach
(
$table
[
'fields'
]
as
$name
=>
$field
)
{
$sql
.
=
_db_create_field_sql
(
$name
,
_db_process_field
(
$field
))
.
",
\n
"
;
}
// Process keys & indexes.
if
(
!
empty
(
$table
[
'primary key'
]))
{
$sql
.
=
" PRIMARY KEY ("
.
_db_create_key_sql
(
$table
[
'primary key'
])
.
"),
\n
"
;
}
if
(
!
empty
(
$table
[
'unique keys'
]))
{
foreach
(
$table
[
'unique keys'
]
as
$key
=>
$fields
)
$sql
.
=
" UNIQUE KEY
$key
("
.
_db_create_key_sql
(
$fields
)
.
"),
\n
"
;
}
if
(
!
empty
(
$table
[
'indexes'
]))
{
foreach
(
$table
[
'indexes'
]
as
$index
=>
$fields
)
$sql
.
=
" INDEX
$index
("
.
_db_create_key_sql
(
$fields
)
.
"),
\n
"
;
}
// Remove the last comma and space.
$sql
=
substr
(
$sql
,
0
,
-
3
)
.
"
\n
) "
;
$sql
.
=
$table
[
'mysql_suffix'
];
return
array
(
$sql
);
}
function
_db_create_key_sql
(
$fields
)
{
$ret
=
array
();
foreach
(
$fields
as
$field
)
{
if
(
is_array
(
$field
))
{
$ret
[]
=
$field
[
0
]
.
'('
.
$field
[
1
]
.
')'
;
}
else
{
$ret
[]
=
$field
;
}
}
return
implode
(
', '
,
$ret
);
}
/**
* Set database-engine specific properties for a field.
*
* @param $field
* A field description array, as specified in the schema documentation.
*/
function
_db_process_field
(
$field
)
{
if
(
!
isset
(
$field
[
'size'
]))
{
$field
[
'size'
]
=
'normal'
;
}
// Set the correct database-engine specific datatype.
if
(
!
isset
(
$field
[
'mysql_type'
]))
{
$map
=
db_type_map
();
$field
[
'mysql_type'
]
=
$map
[
$field
[
'type'
]
.
':'
.
$field
[
'size'
]];
}
if
(
$field
[
'type'
]
==
'serial'
)
{
$field
[
'auto_increment'
]
=
TRUE
;
}
return
$field
;
}
/**
* Create an SQL string for a field to be used in table creation or alteration.
*
* Before passing a field out of a schema definition into this function it has
* to be processed by _db_process_field().
*
* @param $name
* Name of the field.
* @param $spec
* The field specification, as per the schema data structure format.
*/
function
_db_create_field_sql
(
$name
,
$spec
)
{
$sql
=
"`"
.
$name
.
"` "
.
$spec
[
'mysql_type'
];
if
(
isset
(
$spec
[
'length'
]))
{
$sql
.
=
'('
.
$spec
[
'length'
]
.
')'
;
}
elseif
(
isset
(
$spec
[
'precision'
])
&&
isset
(
$spec
[
'scale'
]))
{
$sql
.
=
'('
.
$spec
[
'scale'
]
.
', '
.
$spec
[
'precision'
]
.
')'
;
}
if
(
!
empty
(
$spec
[
'unsigned'
]))
{
$sql
.
=
' unsigned'
;
}
if
(
!
empty
(
$spec
[
'not null'
]))
{
$sql
.
=
' NOT NULL'
;
}
if
(
!
empty
(
$spec
[
'auto_increment'
]))
{
$sql
.
=
' auto_increment'
;
}
if
(
isset
(
$spec
[
'default'
]))
{
if
(
is_string
(
$spec
[
'default'
]))
{
$spec
[
'default'
]
=
"'"
.
$spec
[
'default'
]
.
"'"
;
}
$sql
.
=
' DEFAULT '
.
$spec
[
'default'
];
}
if
(
empty
(
$spec
[
'not null'
])
&&
!
isset
(
$spec
[
'default'
]))
{
$sql
.
=
' DEFAULT NULL'
;
}
return
$sql
;
}
/**
* This maps a generic data type in combination with its data size
* to the engine-specific data type.
*/
function
db_type_map
()
{
// Put :normal last so it gets preserved by array_flip. This makes
// it much easier for modules (such as schema.module) to map
// database types back into schema types.
$map
=
array
(
'varchar:normal'
=>
'VARCHAR'
,
'text:tiny'
=>
'SMALLTEXT'
,
'text:small'
=>
'SMALLTEXT'
,
'text:medium'
=>
'MEDIUMTEXT'
,
'text:big'
=>
'LONGTEXT'
,
'text:normal'
=>
'TEXT'
,
'serial:tiny'
=>
'TINYINT'
,
'serial:small'
=>
'SMALLINT'
,
'serial:medium'
=>
'MEDIUMINT'
,
'serial:big'
=>
'BIGINT'
,
'serial:normal'
=>
'INT'
,
'int:tiny'
=>
'TINYINT'
,
'int:small'
=>
'SMALLINT'
,
'int:medium'
=>
'MEDIUMINT'
,
'int:big'
=>
'BIGINT'
,
'int:normal'
=>
'INT'
,
'float:tiny'
=>
'FLOAT'
,
'float:small'
=>
'FLOAT'
,
'float:medium'
=>
'FLOAT'
,
'float:big'
=>
'DOUBLE'
,
'float:normal'
=>
'FLOAT'
,
'numeric:normal'
=>
'NUMERIC'
,
'blob:big'
=>
'LONGBLOB'
,
'blob:normal'
=>
'BLOB'
,
'datetime:normal'
=>
'DATETIME'
,
);
return
$map
;
}
/**
* Drop a table.
*
* @param $ret
* Array to which query results will be added.
* @param $table
* The table to be dropped.
*/
function
db_drop_table
(
&
$ret
,
$table
)
{
$ret
[]
=
update_sql
(
'DROP TABLE {'
.
$table
.
'}'
);
}
/**
* Add a new field to a table.
*
* @param $ret
* Array to which query results will be added.
* @param $table
* Name of the table to be altered.
* @param $field
* Name of the field to be added.
* @param $spec
* The field specification array, as taken from a schema definition
*/
function
db_add_field
(
&
$ret
,
$table
,
$field
,
$spec
)
{
$query
=
'ALTER TABLE {'
.
$table
.
'} ADD '
.
$field
.
' '
;
$query
.
=
_db_create_field_sql
(
$field
,
_db_process_field
(
$spec
));
$ret
[]
=
update_sql
(
$query
);
}
/**
* Drop a field.
*
* @param $ret
* Array to which query results will be added.
* @param $table
* The table to be altered.
* @param $field
* The field to be dropped.
*/
function
db_drop_field
(
&
$ret
,
$table
,
$field
)
{
$ret
[]
=
update_sql
(
'ALTER TABLE {'
.
$table
.
'} DROP '
.
$field
);
}
/**
* Set the default value for a field.
*
* @param $ret
* Array to which query results will be added.
* @param $table
* The table to be altered.
* @param $field
* The field to be altered.
* @param $default
* Default value to be set. NULL for 'default NULL'.
*/
function
db_field_set_default
(
&
$ret
,
$table
,
$field
,
$default
)
{
if
(
$default
==
NULL
)
{
$default
=
'NULL'
;
}
else
{
$default
=
is_string
(
$default
)
?
"'
$default
'"
:
$default
;
}
$ret
[]
=
update_sql
(
'ALTER TABLE {'
.
$table
.
'} ALTER COLUMN '
.
$field
.
' SET DEFAULT '
.
$default
);
}
/**
* Set a field to have no default value.
*
* @param $ret
* Array to which query results will be added.
* @param $table
* The table to be altered.
* @param $field
* The field to be altered.
*/
function
db_field_set_no_default
(
&
$ret
,
$table
,
$field
)
{
$ret
[]
=
update_sql
(
'ALTER TABLE {'
.
$table
.
'} ALTER COLUMN '
.
$field
.
' DROP DEFAULT'
);
}
/**
* Add a primary key.
*
* @param $ret
* Array to which query results will be added.
* @param $table
* The table to be altered.
* @param $fields
* Fields for the primary key.
*/
function
db_add_primary_key
(
&
$ret
,
$table
,
$fields
)
{
$ret
[]
=
update_sql
(
'ALTER TABLE {'
.
$table
.
'} ADD PRIMARY KEY ('
.
_db_create_key_sql
(
$fields
)
.
')'
);
}
/**
* Drop the primary key.
*
* @param $ret
* Array to which query results will be added.
* @param $table
* The table to be altered.
*/
function
db_drop_primary_key
(
&
$ret
,
$table
)
{
$ret
[]
=
update_sql
(
'ALTER TABLE {'
.
$table
.
'} DROP PRIMARY KEY'
);
}
/**
* Add a unique key.
*
* @param $ret