Index: INSTALL.oracle.txt =================================================================== RCS file: INSTALL.oracle.txt diff -N INSTALL.oracle.txt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ INSTALL.oracle.txt 31 Mar 2008 17:25:27 -0000 @@ -0,0 +1,71 @@ +// $Id: INSTALL.oracle.txt,v 1.1 2007/12/09 17:45:21 hswong3i Exp $ + +CREATE THE Oracle DATABASE +-------------------------- + +This file describes how to create a Oracle database for Drupal. + +If you control your databases through a web-based control panel, +check its documentation, as the following instructions are for the +command line only. + +This step is only necessary if you don't already have a database +set-up (e.g. by your host). In the following examples, 'dba_user' is +an example Oracle user which has the CREATE and GRANT privileges. Use +the appropriate user name for your system. + +Optionally, you can create a new tablespace for your Drupal site +datebase. Log into sqlplus by following command: + + sqlplus dba_user + +sqlplus will prompt for the 'dba_user' database password. At the +sqlplus prompt, enter following command: + + CREATE TABLESPACE tablespace_name + DATAFILE 'file_directory_path' + SIZE filesize AUTOEXTEND ON NEXT extend_size; + +where + + 'tablespace_name' is the name of you new tablespace + 'file_directory_path' is the file location in database server + 'filesize' is the initial file size, e.g. 50K, 1000M. + 'extend_size' is the volumn for extension when data file is full + +First, you must create a new user for your Drupal site. At the +sqlplus prompt, enter the following command: + + CREATE USER username + IDENTIFIED BY "password"; + DEFAULT TABLESPACE tablespace_name; + GRANT CONNECT, RESOURCE TO username; + +where + + 'tablespace_name' is the name of you tablespace + 'username' is the username of your Oracle account + 'password' is the password required for that username + + Note: Unless your database user has all of the privileges listed + above, you will not be able to run Drupal. + +Oracle SPECIAL REQUIREMENTS +--------------------------- + +1. SYSTEM REQUIREMENT + + Oracle driver for Drupal is fully tested with below softwares: + Oracle Database 10g Release 2 (10.2.0.1.0) for Linux x86, + Zend Core for Oracle v.2 Linux x86, + Zend Framework 1.0.0, + PHP Version 5.2.3, + Apache 2.2.3 (Debian) + + You may use something newer than above, but there is no guarantee for + backward compatible. + +2. TABLE PREFIX LIMITATION + + Table prefix are limited in maximum 12 characters. Proved by testing, it + is suggested to use table prefix within 10 characters. Index: INSTALL.pgsql.txt =================================================================== RCS file: INSTALL.pgsql.txt diff -N INSTALL.pgsql.txt --- INSTALL.pgsql.txt 26 Nov 2007 16:36:42 -0000 1.7 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,28 +0,0 @@ -// $Id: INSTALL.pgsql.txt,v 1.7 2007/11/26 16:36:42 dries Exp $ - -CREATE THE PostgreSQL DATABASE ------------------------------- - -Note that the database must be created with UTF-8 (Unicode) encoding. - -1. CREATE DATABASE USER - - This step is only necessary if you don't already have a user set up (e.g. - by your host) or you want to create new user for use with Drupal only. The - following command creates a new user named "username" and asks for a - password for that user: - - createuser --pwprompt --encrypted --no-adduser --no-createdb username - - If everything works correctly, you'll see a "CREATE USER" notice. - -2. CREATE THE DRUPAL DATABASE - - This step is only necessary if you don't already have a database set up (e.g. - by your host) or you want to create new database for use with Drupal only. - The following command creates a new database named "databasename", which is - owned by previously created "username": - - createdb --encoding=UNICODE --owner=username databasename - - If everything works correctly, you'll see a "CREATE DATABASE" notice. Index: INSTALL.postgresql.txt =================================================================== RCS file: INSTALL.postgresql.txt diff -N INSTALL.postgresql.txt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ INSTALL.postgresql.txt 31 Mar 2008 17:25:27 -0000 @@ -0,0 +1,28 @@ +// $Id: INSTALL.postgresql.txt,v 1.1 2007/12/09 17:45:21 hswong3i Exp $ + +CREATE THE PostgreSQL DATABASE +------------------------------ + +Note that the database must be created with UTF-8 (Unicode) encoding. + +1. CREATE DATABASE USER + + This step is only necessary if you don't already have a user set up (e.g. + by your host) or you want to create new user for use with Drupal only. The + following command creates a new user named "username" and asks for a + password for that user: + + createuser --pwprompt --encrypted --no-adduser --no-createdb username + + If everything works correctly, you'll see a "CREATE USER" notice. + +2. CREATE THE DRUPAL DATABASE + + This step is only necessary if you don't already have a database set up (e.g. + by your host) or you want to create new database for use with Drupal only. + The following command creates a new database named "databasename", which is + owned by previously created "username": + + createdb --encoding=UNICODE --owner=username databasename + + If everything works correctly, you'll see a "CREATE DATABASE" notice. Index: MAINTAINERS.siren.txt =================================================================== RCS file: MAINTAINERS.siren.txt diff -N MAINTAINERS.siren.txt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ MAINTAINERS.siren.txt 31 Mar 2008 17:25:28 -0000 @@ -0,0 +1,24 @@ +// $Id$ + +List of maintainers +-------------------------------------------------------------------------------- + +LEGEND +====== + +- M: the maintainer +- S: status: + "supported" : someone is actually paid to look after this. + "maintained" : someone actually looks after it. + "fixes/patches" : it has a maintainer but they don't have time to + do much other than throw the odd patch in. + "orphan" : no current maintainer, but maybe you could take + the role as you write new code? +- W: website with status or information + +-------------------------------------------------------------------------------- + +Siren +M: Edison Wong +S: maintained +W: http://edin.no-ip.com/project/siren/ Index: README.siren.txt =================================================================== RCS file: README.siren.txt diff -N README.siren.txt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ README.siren.txt 31 Mar 2008 17:25:28 -0000 @@ -0,0 +1,60 @@ +// $Id$ + +WHAT IS SIREN? +-------------- + +This is my personal project besides Drupal, which try to research the +possibility of other database supporting for Drupal, e.g. Oracle, IBM DB2, +MSSQL, SQLite, etc; on the other hand, I will provide unofficial database +supporting during Drupal-6.x life cycle, and further more contribute the +research progress for Drupal-7.x. + +For more information on Siren visit +the Siren project homepage at http://edin.no-ip.com/project/siren/ + +CURRENT RESEARCH PROGRESS +------------------------- + +Besides official Drupal-6.x mysql, mysqli and pgsql, Siren also provide +pdo_mysql, pdo_pgsql and oci8 database driver supporting. According to the +needs of PDO and Oracle drivers implementation, ALL core queries and some +APIs are hacked for compatibility concern. + +3rd PARTY MODULE HACK HOWTO +--------------------------- + +Based on cross database compatibility concern, Siren come with lots of core +queries hack. Most works are done for you, and it should run across +MySQl/PgSQL/Oracle without any critical problem. + +Anyway, you will also need to apply some 3rd party module. So how to let them +work together with this unofficial core? + +1. ENCLOSE ALL TABLE/COLUMN/CONSTRAINT NAME WITH [] + + Go though you target module, and enclose all table/column/constraint name + with [] syntax, which similar as {} syntax for all table. + + This can be helped by using VI + regex: /{[A-Za-z0-9_]*} + +2. REPLACE ALL '%s' SYNTAX WITH %s + + This is very important for unofficial PDO supporting. + + This can be helped by using VI + regex: :%s/'%s'/%s/gc + +3. REMOVE ANY %% SYNTAX + + PDO don't allow inline % syntax when using with ? placeholder. + + This can be helped by using VI + regex: /%% + +4. UTILIZE ALL DB_* ABSTRACTION IF POSSIBLE + + These abstraction are mainly duel with syntax different among different DB. + +5. USE %s EVEN IT IS AN EMPTY STRING + + Using empty string as placeholder will cause problem among Oracle and + MSSQL. Escape it by using %s. Oracle and MSSQL driver will able to catch + them and replace it as required empty string placeholder internally. Index: UPGRADE.siren.txt =================================================================== RCS file: UPGRADE.siren.txt diff -N UPGRADE.siren.txt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ UPGRADE.siren.txt 31 Mar 2008 17:25:28 -0000 @@ -0,0 +1,12 @@ +// $Id$ + +UPGRADING FOR SIREN +------------------- + +As a flash new research project, Siren 1.x remove the direct upgrade handling +from Drupal 5.x. You should always use Siren for flash install. + +On the other hand, you may first upgrade your site from Drupal 5.x to +Drupal 6.x, and handle the convert from Drupal 6.x to Siren 1.x manually. +There is no guarantee about this handling, and please backup and do this with +your own risk. Index: install.php =================================================================== RCS file: /cvs/drupal/drupal/install.php,v retrieving revision 1.113.2.2 diff -u -p -r1.113.2.2 install.php --- install.php 8 Feb 2008 22:00:45 -0000 1.113.2.2 +++ install.php 31 Mar 2008 17:25:30 -0000 @@ -136,7 +136,7 @@ function install_main() { */ function install_verify_drupal() { // Read the variable manually using the @ so we don't trigger an error if it fails. - $result = @db_query("SELECT value FROM {variable} WHERE name = '%s'", 'install_task'); + $result = @db_query("SELECT [value] FROM [{variable}] WHERE [name] = %s", 'install_task'); if ($result) { return unserialize(db_result($result)); } @@ -153,16 +153,16 @@ function install_verify_settings() { // We need this because we want to run form_get_errors. include_once './includes/form.inc'; - $url = parse_url(is_array($db_url) ? $db_url['default'] : $db_url); - $db_user = urldecode($url['user']); - $db_pass = isset($url['pass']) ? urldecode($url['pass']) : NULL; - $db_host = urldecode($url['host']); - $db_port = isset($url['port']) ? urldecode($url['port']) : ''; - $db_path = ltrim(urldecode($url['path']), '/'); + $url = isset($db_url['default']) ? $db_url['default'] : $db_url; + $db_user = $url['db_user']; + $db_pass = isset($url['db_pass']) ? $url['db_pass'] : NULL; + $db_host = $url['db_host']; + $db_port = isset($url['db_port']) ? $url['db_port'] : ''; + $db_name = $url['db_name']; $settings_file = './'. conf_path(FALSE, TRUE) .'/settings.php'; $form_state = array(); - _install_settings_form_validate($db_prefix, $db_type, $db_user, $db_pass, $db_host, $db_port, $db_path, $settings_file, $form_state); + _install_settings_form_validate($db_prefix, $db_type, $db_user, $db_pass, $db_host, $db_port, $db_name, $settings_file, $form_state); if (!form_get_errors()) { return TRUE; } @@ -176,12 +176,12 @@ function install_verify_settings() { function install_change_settings($profile = 'default', $install_locale = '') { global $db_url, $db_type, $db_prefix; - $url = parse_url(is_array($db_url) ? $db_url['default'] : $db_url); - $db_user = isset($url['user']) ? urldecode($url['user']) : ''; - $db_pass = isset($url['pass']) ? urldecode($url['pass']) : ''; - $db_host = isset($url['host']) ? urldecode($url['host']) : ''; - $db_port = isset($url['port']) ? urldecode($url['port']) : ''; - $db_path = ltrim(urldecode($url['path']), '/'); + $url = isset($db_url['default']) ? $db_url['default'] : $db_url; + $db_user = isset($url['db_user']) ? $url['db_user'] : ''; + $db_pass = isset($url['db_pass']) ? $url['db_pass'] : ''; + $db_host = isset($url['db_host']) ? $url['db_host'] : ''; + $db_port = isset($url['db_port']) ? $url['db_port'] : ''; + $db_name = $url['db_name']; $conf_path = './'. conf_path(FALSE, TRUE); $settings_file = $conf_path .'/settings.php'; @@ -189,15 +189,15 @@ function install_change_settings($profil include_once './includes/form.inc'; install_task_list('database'); - if ($db_url == 'mysql://username:password@localhost/databasename') { - $db_user = $db_pass = $db_path = ''; + if ($db_url == array()) { + $db_user = $db_pass = $db_name = ''; } elseif (!empty($db_url)) { // Do not install over a configured settings.php. install_already_done_error(); } - $output = drupal_get_form('install_settings_form', $profile, $install_locale, $settings_file, $db_url, $db_type, $db_prefix, $db_user, $db_pass, $db_host, $db_port, $db_path); + $output = drupal_get_form('install_settings_form', $profile, $install_locale, $settings_file, $db_url, $db_type, $db_prefix, $db_user, $db_pass, $db_host, $db_port, $db_name); drupal_set_title(st('Database configuration')); print theme('install_page', $output); exit; @@ -207,7 +207,7 @@ function install_change_settings($profil /** * Form API array definition for install_settings. */ -function install_settings_form(&$form_state, $profile, $install_locale, $settings_file, $db_url, $db_type, $db_prefix, $db_user, $db_pass, $db_host, $db_port, $db_path) { +function install_settings_form(&$form_state, $profile, $install_locale, $settings_file, $db_url, $db_type, $db_prefix, $db_user, $db_pass, $db_host, $db_port, $db_name) { if (empty($db_host)) { $db_host = 'localhost'; } @@ -217,6 +217,15 @@ function install_settings_form(&$form_st if (isset($db_types['mysqli'])) { unset($db_types['mysql']); } + // If both 'mysqli' and 'pdo_mysql' are available, we disable 'mysqli': + if (isset($db_types['pdo_mysql'])) { + unset($db_types['mysqli']); + } + + // If both 'pgsql' and 'pdo_pgsql' are available, we disable 'pgsql': + if (isset($db_types['pdo_pgsql'])) { + unset($db_types['pgsql']); + } if (count($db_types) == 0) { $form['no_db_types'] = array( @@ -239,7 +248,7 @@ function install_settings_form(&$form_st '#default_value' => ($db_type ? $db_type : current($db_types)), '#description' => st('The type of database your @drupal data will be stored in.', array('@drupal' => drupal_install_profile_name())), ); - $db_path_description = st('The name of the database your @drupal data will be stored in. It must exist on your server before @drupal can be installed.', array('@drupal' => drupal_install_profile_name())); + $db_name_description = st('The name of the database your @drupal data will be stored in. It must exist on your server before @drupal can be installed.', array('@drupal' => drupal_install_profile_name())); } else { if (count($db_types) == 1) { @@ -248,19 +257,19 @@ function install_settings_form(&$form_st '#type' => 'hidden', '#value' => $db_types[0], ); - $db_path_description = st('The name of the %db_type database your @drupal data will be stored in. It must exist on your server before @drupal can be installed.', array('%db_type' => $db_types[0], '@drupal' => drupal_install_profile_name())); + $db_name_description = st('The name of the %db_type database your @drupal data will be stored in. It must exist on your server before @drupal can be installed.', array('%db_type' => $db_types[0], '@drupal' => drupal_install_profile_name())); } } // Database name - $form['basic_options']['db_path'] = array( + $form['basic_options']['db_name'] = array( '#type' => 'textfield', '#title' => st('Database name'), - '#default_value' => $db_path, + '#default_value' => $db_name, '#size' => 45, '#maxlength' => 45, '#required' => TRUE, - '#description' => $db_path_description + '#description' => $db_name_description ); // Database username @@ -341,13 +350,13 @@ function install_settings_form(&$form_st */ function install_settings_form_validate($form, &$form_state) { global $db_url; - _install_settings_form_validate($form_state['values']['db_prefix'], $form_state['values']['db_type'], $form_state['values']['db_user'], $form_state['values']['db_pass'], $form_state['values']['db_host'], $form_state['values']['db_port'], $form_state['values']['db_path'], $form_state['values']['settings_file'], $form_state, $form); + _install_settings_form_validate($form_state['values']['db_prefix'], $form_state['values']['db_type'], $form_state['values']['db_user'], $form_state['values']['db_pass'], $form_state['values']['db_host'], $form_state['values']['db_port'], $form_state['values']['db_name'], $form_state['values']['settings_file'], $form_state, $form); } /** * Helper function for install_settings_validate. */ -function _install_settings_form_validate($db_prefix, $db_type, $db_user, $db_pass, $db_host, $db_port, $db_path, $settings_file, &$form_state, $form = NULL) { +function _install_settings_form_validate($db_prefix, $db_type, $db_user, $db_pass, $db_host, $db_port, $db_name, $settings_file, &$form_state, $form = NULL) { global $db_url; // Verify the table prefix @@ -361,8 +370,7 @@ function _install_settings_form_validate // Check database type if (!isset($form)) { - $_db_url = is_array($db_url) ? $db_url['default'] : $db_url; - $db_type = substr($_db_url, 0, strpos($_db_url, '://')); + $db_type = $db_url['db_type']; } $databases = drupal_detect_database_types(); if (!in_array($db_type, $databases)) { @@ -370,7 +378,15 @@ function _install_settings_form_validate } else { // Verify - $db_url = $db_type .'://'. urlencode($db_user) . ($db_pass ? ':'. urlencode($db_pass) : '') .'@'. ($db_host ? urlencode($db_host) : 'localhost') . ($db_port ? ":$db_port" : '') .'/'. urlencode($db_path); + $db_url = array( + 'db_host' => $db_host ? $db_host : 'localhost', + 'db_port' => $db_port ? $db_port : '', + 'db_name' => $db_name, + 'db_user' => $db_user, + 'db_pass' => $db_pass ? $db_pass : '', + 'db_type' => $db_type, + 'db_prefix' => $db_prefix, + ); if (isset($form)) { form_set_value($form['_db_url'], $db_url, $form_state); } @@ -399,10 +415,6 @@ function install_settings_form_submit($f 'value' => $form_state['values']['_db_url'], 'required' => TRUE, ); - $settings['db_prefix'] = array( - 'value' => $form_state['values']['db_prefix'], - 'required' => TRUE, - ); drupal_rewrite_settings($settings); // Continue to install profile step Index: update.php =================================================================== RCS file: /cvs/drupal/drupal/update.php,v retrieving revision 1.252 diff -u -p -r1.252 update.php --- update.php 3 Feb 2008 18:41:16 -0000 1.252 +++ update.php 31 Mar 2008 17:25:32 -0000 @@ -55,26 +55,26 @@ function db_add_column(&$ret, $table, $c if (array_key_exists('default', $attributes)) { if (is_null($attributes['default'])) { $default_val = 'NULL'; - $default = 'default NULL'; + $default = 'DEFAULT NULL'; } elseif ($attributes['default'] === FALSE) { $default = ''; } else { - $default_val = "$attributes[default]"; - $default = "default $attributes[default]"; + $default_val = $attributes['default']; + $default = "DEFAULT ". $attributes['default']; } } - $ret[] = update_sql("ALTER TABLE {". $table ."} ADD $column $type"); + $ret[] = update_sql("ALTER TABLE [{". $table ."}] ADD [$column] $type"); if (!empty($default)) { - $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column SET $default"); + $ret[] = update_sql("ALTER TABLE [{". $table ."}] ALTER [$column] SET $default"); } if (!empty($not_null)) { if (!empty($default)) { - $ret[] = update_sql("UPDATE {". $table ."} SET $column = $default_val"); + $ret[] = update_sql("UPDATE [{". $table ."}] SET [$column] = $default_val"); } - $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column SET NOT NULL"); + $ret[] = update_sql("ALTER TABLE [{". $table ."}] ALTER [$column] SET NOT NULL"); } } @@ -111,23 +111,23 @@ function db_change_column(&$ret, $table, if (array_key_exists('default', $attributes)) { if (is_null($attributes['default'])) { $default_val = 'NULL'; - $default = 'default NULL'; + $default = 'DEFAULT NULL'; } elseif ($attributes['default'] === FALSE) { $default = ''; } else { - $default_val = "$attributes[default]"; - $default = "default $attributes[default]"; + $default_val = $attributes['default']; + $default = "DEFAULT ". $attributes['default']; } } - $ret[] = update_sql("ALTER TABLE {". $table ."} RENAME $column TO ". $column ."_old"); - $ret[] = update_sql("ALTER TABLE {". $table ."} ADD $column_new $type"); - $ret[] = update_sql("UPDATE {". $table ."} SET $column_new = ". $column ."_old"); - if ($default) { $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column_new SET $default"); } - if ($not_null) { $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $column_new SET NOT NULL"); } - $ret[] = update_sql("ALTER TABLE {". $table ."} DROP ". $column ."_old"); + $ret[] = update_sql("ALTER TABLE [{". $table ."}] RENAME [$column] TO [". $column ."_old]"); + $ret[] = update_sql("ALTER TABLE [{". $table ."}] ADD [$column_new] $type"); + $ret[] = update_sql("UPDATE [{". $table ."}] SET [$column_new] = [". $column ."_old]"); + if ($default) { $ret[] = update_sql("ALTER TABLE [{". $table ."}] ALTER [$column_new] SET $default"); } + if ($not_null) { $ret[] = update_sql("ALTER TABLE [{". $table ."}] ALTER [$column_new] SET NOT NULL"); } + $ret[] = update_sql("ALTER TABLE [{". $table ."}] DROP [". $column ."_old]"); } /** @@ -428,14 +428,14 @@ function update_create_batch_table() { function update_fix_compatibility() { $ret = array(); $incompatible = array(); - $query = db_query("SELECT name, type, status FROM {system} WHERE status = 1 AND type IN ('module','theme')"); + $query = db_query("SELECT [name], [type], [status] FROM [{system}] WHERE [status] = 1 AND [type] IN ('module', 'theme')"); while ($result = db_fetch_object($query)) { if (update_check_incompatibility($result->name, $result->type)) { $incompatible[] = $result->name; } } if (!empty($incompatible)) { - $ret[] = update_sql("UPDATE {system} SET status = 0 WHERE name IN ('". implode("','", $incompatible) ."')"); + $ret[] = update_sql("UPDATE [{system}] SET [status] = 0 WHERE [name] IN ('". implode("', '", $incompatible) ."')"); } return $ret; } Index: includes/actions.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/actions.inc,v retrieving revision 1.8 diff -u -p -r1.8 actions.inc --- includes/actions.inc 31 Dec 2007 14:51:04 -0000 1.8 +++ includes/actions.inc 31 Mar 2008 17:25:35 -0000 @@ -54,7 +54,7 @@ function actions_do($action_ids, &$objec $where_values = array(); foreach ($action_ids as $action_id) { if (is_numeric($action_id)) { - $where[] = 'OR aid = %d'; + $where[] = 'OR [aid] = %d'; $where_values[] = $action_id; } elseif (isset($available_actions[$action_id])) { @@ -68,7 +68,7 @@ function actions_do($action_ids, &$objec $where_clause = implode(' ', $where); // Strip off leading 'OR '. $where_clause = '('. strstr($where_clause, " ") .')'; - $result_db = db_query('SELECT * FROM {actions} WHERE '. $where_clause, $where_values); + $result_db = db_query('SELECT * FROM [{actions}] WHERE '. $where_clause, $where_values); while ($action = db_fetch_object($result_db)) { $actions[$action->aid] = $action->parameters ? unserialize($action->parameters) : array(); $actions[$action->aid]['callback'] = $action->callback; @@ -93,7 +93,7 @@ function actions_do($action_ids, &$objec else { // If it's a configurable action, retrieve stored parameters. if (is_numeric($action_ids)) { - $action = db_fetch_object(db_query("SELECT * FROM {actions} WHERE aid = %d", $action_ids)); + $action = db_fetch_object(db_query("SELECT * FROM [{actions}] WHERE [aid] = %d", $action_ids)); $function = $action->callback; $context = array_merge($context, unserialize($action->parameters)); $result[$action_ids] = $function($object, $context, $a1, $a2); @@ -177,7 +177,7 @@ function actions_list($reset = FALSE) { */ function actions_get_all_actions() { $actions = array(); - $result = db_query("SELECT * FROM {actions}"); + $result = db_query("SELECT * FROM [{actions}]"); while ($action = db_fetch_object($result)) { $actions[$action->aid] = array( 'callback' => $action->callback, @@ -238,7 +238,7 @@ function actions_function_lookup($hash) } // Must be an instance; must check database. - $aid = db_result(db_query("SELECT aid FROM {actions} WHERE MD5(aid) = '%s' AND parameters != ''", $hash)); + $aid = db_result(db_query("SELECT [aid] FROM [{actions}] WHERE MD5([aid]) = %s AND [parameters] <> %s", $hash, '')); return $aid; } @@ -255,7 +255,7 @@ function actions_synchronize($actions_in $actions_in_code = actions_list(); } $actions_in_db = array(); - $result = db_query("SELECT * FROM {actions} WHERE parameters = ''"); + $result = db_query("SELECT * FROM [{actions}] WHERE [parameters] = %s", ''); while ($action = db_fetch_object($result)) { $actions_in_db[$action->callback] = array('aid' => $action->aid, 'description' => $action->description); } @@ -271,7 +271,7 @@ function actions_synchronize($actions_in } else { // This is a new singleton that we don't have an aid for; assign one. - db_query("INSERT INTO {actions} (aid, type, callback, parameters, description) VALUES ('%s', '%s', '%s', '%s', '%s')", $callback, $array['type'], $callback, '', $array['description']); + db_query("INSERT INTO [{actions}] ([aid], [type], [callback], [parameters], [description]) VALUES (%s, %s, %s, %s, %s)", $callback, $array['type'], $callback, '', $array['description']); watchdog('actions', "Action '%action' added.", array('%action' => filter_xss_admin($array['description']))); } } @@ -284,14 +284,14 @@ function actions_synchronize($actions_in foreach ($actions_in_db as $callback => $array) { $orphaned[] = $callback; - $placeholder[] = "'%s'"; + $placeholder[] = "%s"; } $orphans = implode(', ', $orphaned); if ($delete_orphans) { $placeholders = implode(', ', $placeholder); - $results = db_query("SELECT a.aid, a.description FROM {actions} a WHERE callback IN ($placeholders)", $orphaned); + $results = db_query("SELECT a.[aid], a.[description] FROM [{actions}] a WHERE [callback] IN ($placeholders)", $orphaned); while ($action = db_fetch_object($results)) { actions_delete($action->aid); watchdog('actions', "Removed orphaned action '%action' from database.", array('%action' => filter_xss_admin($action->description))); @@ -325,15 +325,15 @@ function actions_synchronize($actions_in function actions_save($function, $type, $params, $desc, $aid = NULL) { $serialized = serialize($params); if ($aid) { - db_query("UPDATE {actions} SET callback = '%s', type = '%s', parameters = '%s', description = '%s' WHERE aid = %d", $function, $type, $serialized, $desc, $aid); + db_query("UPDATE [{actions}] SET [callback] = %s, [type] = %s, [parameters] = %s, [description] = %s WHERE [aid] = %d", $function, $type, $serialized, $desc, $aid); watchdog('actions', 'Action %action saved.', array('%action' => $desc)); } else { // aid is the callback for singleton actions so we need to keep a // separate table for numeric aids. - db_query('INSERT INTO {actions_aid} VALUES (default)'); + db_query('INSERT INTO [{actions_aid}] VALUES (default)'); $aid = db_last_insert_id('actions_aid', 'aid'); - db_query("INSERT INTO {actions} (aid, callback, type, parameters, description) VALUES (%d, '%s', '%s', '%s', '%s')", $aid, $function, $type, $serialized, $desc); + db_query("INSERT INTO [{actions}] ([aid], [callback], [type], [parameters], [description]) VALUES (%d, %s, %s, %s, %s)", $aid, $function, $type, $serialized, $desc); watchdog('actions', 'Action %action created.', array('%action' => $desc)); } @@ -350,7 +350,7 @@ function actions_save($function, $type, * The appropriate action row from the database as an object. */ function actions_load($aid) { - return db_fetch_object(db_query("SELECT * FROM {actions} WHERE aid = %d", $aid)); + return db_fetch_object(db_query("SELECT * FROM [{actions}] WHERE [aid] = %d", $aid)); } /** @@ -360,6 +360,6 @@ function actions_load($aid) { * integer The ID of the action to delete. */ function actions_delete($aid) { - db_query("DELETE FROM {actions} WHERE aid = %d", $aid); + db_query("DELETE FROM [{actions}] WHERE [aid] = %d", $aid); module_invoke_all('actions_delete', $aid); } Index: includes/batch.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/batch.inc,v retrieving revision 1.14 diff -u -p -r1.14 batch.inc --- includes/batch.inc 20 Dec 2007 11:57:20 -0000 1.14 +++ includes/batch.inc 31 Mar 2008 17:25:35 -0000 @@ -12,7 +12,7 @@ function _batch_page() { $batch =& batch_get(); // Retrieve the current state of batch from db. - if (isset($_REQUEST['id']) && $data = db_result(db_query("SELECT batch FROM {batch} WHERE bid = %d AND token = '%s'", $_REQUEST['id'], drupal_get_token($_REQUEST['id'])))) { + if (isset($_REQUEST['id']) && $data = db_result(db_query("SELECT [batch] FROM [{batch}] WHERE [bid] = %d AND [token] = %s", $_REQUEST['id'], drupal_get_token($_REQUEST['id'])))) { $batch = unserialize($data); } else { @@ -305,7 +305,7 @@ function _batch_finished() { // Cleanup the batch table and unset the global $batch variable. if ($batch['progressive']) { - db_query("DELETE FROM {batch} WHERE bid = %d", $batch['id']); + db_query("DELETE FROM [{batch}] WHERE [bid] = %d", $batch['id']); } $_batch = $batch; $batch = NULL; @@ -349,6 +349,6 @@ function _batch_finished() { */ function _batch_shutdown() { if ($batch = batch_get()) { - db_query("UPDATE {batch} SET batch = '%s' WHERE bid = %d", serialize($batch), $batch['id']); + db_query("UPDATE [{batch}] SET [batch] = %s WHERE [bid] = %d", serialize($batch), $batch['id']); } } Index: includes/bootstrap.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v retrieving revision 1.206.2.2 diff -u -p -r1.206.2.2 bootstrap.inc --- includes/bootstrap.inc 11 Feb 2008 14:36:21 -0000 1.206.2.2 +++ includes/bootstrap.inc 31 Mar 2008 17:25:39 -0000 @@ -384,7 +384,7 @@ function drupal_get_filename($type, $nam // the database. This is required because this function is called both // before we have a database connection (i.e. during installation) and // when a database connection fails. - elseif (db_is_active() && (($file = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s' AND type = '%s'", $name, $type))) && file_exists($file))) { + elseif (db_is_active() && (($file = db_result(db_query("SELECT [filename] FROM [{system}] WHERE [name] = %s AND [type] = %s", $name, $type))) && file_exists($file))) { $files[$type][$name] = $file; } else { @@ -420,7 +420,7 @@ function variable_init($conf = array()) $variables = $cached->data; } else { - $result = db_query('SELECT * FROM {variable}'); + $result = db_query('SELECT * FROM [{variable}]'); while ($variable = db_fetch_object($result)) { $variables[$variable->name] = unserialize($variable->value); } @@ -463,9 +463,9 @@ function variable_set($name, $value) { global $conf; $serialized_value = serialize($value); - db_query("UPDATE {variable} SET value = '%s' WHERE name = '%s'", $serialized_value, $name); + db_query("UPDATE [{variable}] SET [value] = %s WHERE [name] = %s", $serialized_value, $name); if (!db_affected_rows()) { - @db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", $name, $serialized_value); + @db_query("INSERT INTO [{variable}] ([name], [value]) VALUES (%s, %s)", $name, $serialized_value); } cache_clear_all('variables', 'cache'); @@ -482,7 +482,7 @@ function variable_set($name, $value) { function variable_del($name) { global $conf; - db_query("DELETE FROM {variable} WHERE name = '%s'", $name); + db_query("DELETE FROM [{variable}] WHERE [name] = %s", $name); cache_clear_all('variables', 'cache'); unset($conf[$name]); @@ -874,13 +874,19 @@ function drupal_get_messages($type = NUL * TRUE if access is denied, FALSE if access is allowed. */ function drupal_is_denied($type, $mask) { - // Because this function is called for every page request, both cached - // and non-cached pages, we tried to optimize it as much as possible. - // We deny access if the only matching records in the {access} table have - // status 0 (deny). If any have status 1 (allow), or if there are no - // matching records, we allow access. - $sql = "SELECT 1 FROM {access} WHERE type = '%s' AND LOWER('%s') LIKE LOWER(mask) AND status = %d"; - return db_result(db_query_range($sql, $type, $mask, 0, 0, 1)) && !db_result(db_query_range($sql, $type, $mask, 1, 0, 1)); + switch ($GLOBALS['db_type']) { + case 'ibm_db2': + case 'pdo_ibm': + return FALSE; + default: + // Because this function is called for every page request, both cached + // and non-cached pages, we tried to optimize it as much as possible. + // We deny access if the only matching records in the {access} table have + // status 0 (deny). If any have status 1 (allow), or if there are no + // matching records, we allow access. + $sql = "SELECT 1 FROM [{access}] WHERE [type] = %s AND LOWER(%s) LIKE LOWER([mask]) AND [status] = %d"; + return db_result(db_query_range($sql, $type, $mask, 0, 0, 1)) && !db_result(db_query_range($sql, $type, $mask, 1, 0, 1)); + } } /** @@ -1078,7 +1084,7 @@ function language_list($field = 'languag // Init language list if (!isset($languages)) { if (variable_get('language_count', 1) > 1 || module_exists('locale')) { - $result = db_query('SELECT * FROM {languages} ORDER BY weight ASC, name ASC'); + $result = db_query('SELECT * FROM [{languages}] ORDER BY [weight] ASC, [name] ASC'); while ($row = db_fetch_object($result)) { $languages['language'][$row->language] = $row; } Index: includes/cache.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/cache.inc,v retrieving revision 1.17 diff -u -p -r1.17 cache.inc --- includes/cache.inc 29 Jan 2008 11:36:06 -0000 1.17 +++ includes/cache.inc 31 Mar 2008 17:25:39 -0000 @@ -20,10 +20,10 @@ function cache_get($cid, $table = 'cache // Reset the variable immediately to prevent a meltdown in heavy load situations. variable_set('cache_flush', 0); // Time to flush old cache data - db_query("DELETE FROM {". $table ."} WHERE expire != %d AND expire <= %d", CACHE_PERMANENT, $cache_flush); + db_query("DELETE FROM [{". $table ."}] WHERE [expire] <> %d AND [expire] <= %d", CACHE_PERMANENT, $cache_flush); } - $cache = db_fetch_object(db_query("SELECT data, created, headers, expire, serialized FROM {". $table ."} WHERE cid = '%s'", $cid)); + $cache = db_fetch_object(db_query("SELECT [data], [created], [headers], [expire], [serialized] FROM [{". $table ."}] WHERE [cid] = %s", $cid)); if (isset($cache->data)) { // If the data is permanent or we're not enforcing a minimum cache lifetime // always return the cached data. @@ -106,9 +106,17 @@ function cache_set($cid, $data, $table = $serialized = 1; } $created = time(); - db_query("UPDATE {". $table ."} SET data = %b, created = %d, expire = %d, headers = '%s', serialized = %d WHERE cid = '%s'", $data, $created, $expire, $headers, $serialized, $cid); + $values = array( + array('field' => 'data', 'placeholder' => '%b', 'data' => $data), + array('field' => 'created', 'placeholder' => '%d', 'data' => $created), + array('field' => 'expire', 'placeholder' => '%d', 'data' => $expire), + array('field' => 'headers', 'placeholder' => "%s", 'data' => $headers), + array('field' => 'serialized', 'placeholder' => '%d', 'data' => $serialized), + ); + db_query_update($table, $values, "[cid] = %s", $cid); if (!db_affected_rows()) { - @db_query("INSERT INTO {". $table ."} (cid, data, created, expire, headers, serialized) VALUES ('%s', %b, %d, %d, '%s', %d)", $cid, $data, $created, $expire, $headers, $serialized); + $values[] = array('field' => 'cid', 'placeholder' => "%s", 'data' => $cid); + db_query_insert($table, $values); } } @@ -157,26 +165,26 @@ function cache_clear_all($cid = NULL, $t else if (time() > ($cache_flush + variable_get('cache_lifetime', 0))) { // Clear the cache for everyone, cache_flush_delay seconds have // passed since the first request to clear the cache. - db_query("DELETE FROM {". $table ."} WHERE expire != %d AND expire < %d", CACHE_PERMANENT, time()); + db_query("DELETE FROM [{". $table ."}] WHERE [expire] <> %d AND [expire] < %d", CACHE_PERMANENT, time()); variable_set('cache_flush', 0); } } else { // No minimum cache lifetime, flush all temporary cache entries now. - db_query("DELETE FROM {". $table ."} WHERE expire != %d AND expire < %d", CACHE_PERMANENT, time()); + db_query("DELETE FROM [{". $table ."}] WHERE [expire] <> %d AND [expire] < %d", CACHE_PERMANENT, time()); } } else { if ($wildcard) { if ($cid == '*') { - db_query("DELETE FROM {". $table ."}"); + db_query("DELETE FROM [{". $table ."}]"); } else { - db_query("DELETE FROM {". $table ."} WHERE cid LIKE '%s%%'", $cid); + db_query("DELETE FROM [{". $table ."}] WHERE [cid] LIKE %s", $cid ."%"); } } else { - db_query("DELETE FROM {". $table ."} WHERE cid = '%s'", $cid); + db_query("DELETE FROM [{". $table ."}] WHERE [cid] = %s", $cid); } } } Index: includes/common.db2.inc =================================================================== RCS file: includes/common.db2.inc diff -N includes/common.db2.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/common.db2.inc 31 Mar 2008 17:25:39 -0000 @@ -0,0 +1,397 @@ + $t('DB2 database'), + 'value' => $version, + ); + + if (version_compare($version, DRUPAL_MINIMUM_DB2) < 0) { + $form['db2']['severity'] = REQUIREMENT_ERROR; + $form['db2']['description'] = $t('Your DB2 Server is too old. Drupal requires at least DB2 %version.', array('%version' => DRUPAL_MINIMUM_DB2)); + } + + return $form; +} + +/** + * Returns the version of the database server currently in use. + * + * @return Database server version + */ +function db_version() { + $banner = db_result(db_query("SELECT SERVICE_LEVEL FROM TABLE (SYSPROC.ENV_GET_INST_INFO()) AS INSTANCEINFO")); + preg_match('/\s*v([0-9.]+)\s*/', $banner, $version); + return array_pop($version); +} + +/** + * Insert a row of record into database. + * + * @param $table + * Table to insert. + * @param $values + * An array containing the insert values. Each element of the array + * should be an associatie array with the following keys: + * - "field": The database field represented in the table column. + * - "placeholder": The placeholder of the table column, using printf() + * syntax. Valid %-modifiers are: %d, %f, %s and %b. + * - "data": The data to insert into the table column. + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query_insert($table, $values) { + $fields = array(); + $placeholders = array(); + $data = array(); + foreach ($values as $value) { + $fields[] = $value['field']; + $placeholders[] = $value['placeholder']; + $data[] = $value['data']; + } + + if (!count($fields)) { + return FALSE; + } + + $query = "INSERT INTO [{". $table ."}] ([". implode('], [', $fields) ."]) VALUES (". implode(', ', $placeholders) .")"; + return db_query($query, $data); +} + +/** + * Update a row of record in database. + * + * @param $table + * Table to update. + * @param $values + * An array containing the update values. Each element of the array + * should be an associatie array with the following keys: + * - "field": The database field represented in the table column. + * - "placeholder": The placeholder of the table column, using printf() + * syntax. Valid %-modifiers are: %d, %f, %s and %b. + * - "data": The data to insert into the table column. + * @param $where_clause + * A string containing an update condition query (where clause). + * @param ... + * A variable number of arguments which are substituted into the query + * WHERE condition, using printf() syntax. Instead of a variable number + * of query arguments, you may also pass a single array containing the + * query arguments. + * + * Valid %-modifiers are: %d, %f and %s. + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query_update($table, $values, $where_clause = NULL) { + $args = func_get_args(); + $args = array_slice($args, 3); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + + $fields = array(); + $data = array(); + foreach ($values as $value) { + $fields[] = '['. $value['field'] .'] = '. $value['placeholder']; + $data[] = $value['data']; + } + + if (!count($fields)) { + return FALSE; + } + + $query = "UPDATE [{". $table ."}] SET ". implode(', ', $fields); + if ($where_clause) { + $query .= " WHERE ". $where_clause; + $data = array_merge($data, $args); + } + return db_query($query, $data); +} + +/** + * Delete a row of record from database. + * + * @param $table + * Table to delete. + * @param $where_clause + * A string containing an update condition query (where clause). + * @param ... + * A variable number of arguments which are substituted into the query + * WHERE condition, using printf() syntax. Instead of a variable number + * of query arguments, you may also pass a single array containing the + * query arguments. + * + * Valid %-modifiers are: %d, %f and %s. + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query_delete($table, $where_clause = NULL) { + $args = func_get_args(); + $args = array_slice($args, 2); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + + $data = array(); + + $query = "DELETE FROM [{". $table ."}]"; + if ($where_clause) { + $query .= " WHERE ". $where_clause; + $data = $args; + } + return db_query($query, $data); +} + +/** + * Returns the last insert id. This function is thread safe. + * + * @param $table + * The name of the table you inserted into. + * @param $field + * The name of the autoincrement field. + */ +function db_last_insert_id($table, $field) { + return db_result(db_query("SELECT SYSIBM.IDENTITY_VAL_LOCAL() FROM [{". $table ."}]")); +} + +/** + * Runs a limited-range query in the active database. + * + * Use this as a substitute for db_query() when a subset of the query + * is to be returned. + * User-supplied arguments to the query should be passed in as separate + * parameters so that they can be properly escaped to avoid SQL injection + * attacks. + * + * @param $query + * A string containing an SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. Instead of a variable number of query arguments, + * you may also pass a single array containing the query arguments. + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). + * + * NOTE: use NULL as arguments substitution for %b and %c. This will be + * replaced as corresponding empty LOB value placeholder, based on the + * database specific representation. + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @param $from + * The first result row to return. + * @param $count + * The maximum number of result rows to return. + * @return + * A database query result resource, or FALSE if the query was not executed + * correctly. + */ +function db_query_range($query) { + $args = func_get_args(); + $count = array_pop($args); + $from = array_pop($args); + array_shift($args); + + $query = 'SELECT * FROM (SELECT [sub1].*, ROW_NUMBER() OVER() AS [line2] FROM (' . $query . ') AS [sub1]) AS [sub2] WHERE [line2] BETWEEN ' . $from . ' AND ' . ($from + $count); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + return db_query($query, $args); +} + +/** + * Runs a SELECT query and stores its results in a temporary table. + * + * Use this as a substitute for db_query() when the results need to stored + * in a temporary table. Temporary tables exist for the duration of the page + * request. + * User-supplied arguments to the query should be passed in as separate parameters + * so that they can be properly escaped to avoid SQL injection attacks. + * + * Note that if you need to know how many results were returned, you should do + * a SELECT COUNT(*) on the temporary table afterwards. db_affected_rows() do + * not give consistent result across different database types in this case. + * + * @param $query + * A string containing a normal SELECT SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. The query arguments can be enclosed in one + * array instead. + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). + * + * NOTE: use NULL as arguments substitution for %b and %c. This will be + * replaced as corresponding empty LOB value placeholder, based on the + * database specific representation. + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @param $table + * The name of the temporary table to select into. This name will not be + * prefixed as there is no risk of collision. + * @return + * A database query result resource, or FALSE if the query was not executed + * correctly. + */ +function db_query_temporary($query) { + $args = func_get_args(); + $tablename = array_pop($args); + array_shift($args); + + $query = 'DECLARE GLOBAL TEMPORARY TABLE ['. $tablename .'] AS (' . $query . ') DEFINITION ONLY INCLUDING IDENTITY COLUMN ATTRIBUTES INCLUDING COLUMN DEFAULTS ON COMMIT PRESERVE ROWS NOT LOGGED'; + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + return db_query($query, $args); +} + +/** + * Lock a table. + * This function automatically starts a transaction. + */ +function db_lock_table($table) { + db_query('LOCK TABLE [{'. db_escape_table($table) .'}] IN EXCLUSIVE MODE'); +} + +/** + * Unlock all locked tables. + * This function automatically commits a transaction. + */ +function db_unlock_tables() { + db_query('COMMIT'); +} + +/** + * Check if a table exists. + */ +function db_table_exists($table) { + return (bool) db_result(db_query("SELECT COUNT(TABLE_NAME) FROM SYSIBM.TABLES WHERE TABLE_NAME LIKE '{". db_escape_table($table) ."}'")); +} + +/** + * Check if a column exists in the given table. + */ +function db_column_exists($table, $column) { + return (bool) db_result(db_query("SELECT COUNT(COLUMN_NAME) FROM SYSIBM.COLUMNS WHERE TABLE_NAME LIKE '{". db_escape_table($table) ."}' AND COLUMN_NAME LIKE '" . db_escape_table($column) ."'")); +} + +/** + * Wraps the given table.field entry with a DISTINCT(). The wrapper is added to + * the SELECT list entry of the given query and the resulting query is returned. + * This function only applies the wrapper if a DISTINCT doesn't already exist in + * the query. + * + * @param $table Table containing the field to set as DISTINCT + * @param $field Field to set as DISTINCT + * @param $query Query to apply the wrapper to + * @return SQL query with the DISTINCT wrapper surrounding the given table.field. + */ +function db_distinct_field($table, $field, $query) { + $field_to_select = 'DISTINCT (['. $table .'].['. $field .'])'; + // (? %d", $name, ip_address(), time() - 3600)); + $number = db_result(db_query("SELECT COUNT(*) FROM [{flood}] WHERE [event] = %s AND [hostname] = %s AND [timestamp] > %d", $name, ip_address(), time() - 3600)); return ($number < $threshold ? TRUE : FALSE); } @@ -3194,7 +3194,9 @@ function _drupal_initialize_schema($modu **/ function drupal_schema_fields_sql($table, $prefix = NULL) { $schema = drupal_get_schema($table); - $fields = array_keys($schema['fields']); + foreach ($schema['fields'] as $key => $value) { + $fields[] = '['. $key .']'; + } if ($prefix) { $columns = array(); foreach ($fields as $field) { @@ -3219,7 +3221,7 @@ function drupal_schema_fields_sql($table * The object to write. This is a reference, as defaults according to * the schema may be filled in on the object, as well as ID on the serial * type(s). Both array an object types may be passed. - * @param $update + * @param primary_keys * If this is an update, specify the primary keys' field names. It is the * caller's responsibility to know if a record for this object already * exists in the database. If there is only 1 key, you may pass a simple string. @@ -3230,19 +3232,15 @@ function drupal_schema_fields_sql($table * the $table. For example, $object->nid will be populated after inserting * a new node. */ -function drupal_write_record($table, &$object, $update = array()) { - // Standardize $update to an array. - if (is_string($update)) { - $update = array($update); +function drupal_write_record($table, &$object, $primary_keys = array()) { + // Standardize $primary_keys to an array. + if (!is_array($primary_keys)) { + $primary_keys = array($primary_keys); } // Convert to an object if needed. - if (is_array($object)) { + if ($array = is_array($object)) { $object = (object) $object; - $array = TRUE; - } - else { - $array = FALSE; } $schema = drupal_get_schema($table); @@ -3250,18 +3248,19 @@ function drupal_write_record($table, &$o return FALSE; } - $fields = $defs = $values = $serials = $placeholders = array(); + $values = array(); + $serials = array(); // Go through our schema, build SQL, and when inserting, fill in defaults for // fields that are not set. foreach ($schema['fields'] as $field => $info) { // Special case -- skip serial types if we are updating. - if ($info['type'] == 'serial' && count($update)) { + if ($info['type'] == 'serial' && count($primary_keys)) { continue; } // For inserts, populate defaults from Schema if not already provided - if (!isset($object->$field) && !count($update) && isset($info['default'])) { + if (!isset($object->$field) && !count($primary_keys) && isset($info['default'])) { $object->$field = $info['default']; } @@ -3274,44 +3273,52 @@ function drupal_write_record($table, &$o // Build arrays for the fields, placeholders, and values in our query. if (isset($object->$field)) { - $fields[] = $field; - $placeholders[] = db_type_placeholder($info['type']); + $value['field'] = $field; + $value['placeholder'] = db_type_placeholder($info['type']); if (empty($info['serialize'])) { - $values[] = $object->$field; + $value['data'] = $object->$field; + } + elseif (!empty($object->$field)) { + $value['data'] = serialize($object->$field); } else { - $values[] = serialize($object->$field); + $value['data'] = ''; } + + $values[] = $value; + } + } + + if (empty($values)) { + // No changes requested. + // If we began with an array, convert back so we don't surprise the caller. + if ($array) { + $object = (array) $object; } + return; } - // Build the SQL. - $query = ''; - if (!count($update)) { - $query = "INSERT INTO {". $table ."} (". implode(', ', $fields) .') VALUES ('. implode(', ', $placeholders) .')'; + // Execute the SQL. + if (!count($primary_keys)) { + $result = db_query_insert($table, $values); $return = SAVED_NEW; } else { - $query = ''; - foreach ($fields as $id => $field) { - if ($query) { - $query .= ', '; + foreach ($primary_keys as $key => $value){ + // $primary_key is NOT in key-value pair format. + if (!isset($schema['fields'][$key]) && isset($schema['fields'][$value])) { + $key = $value; + $value = $object->$key; } - $query .= $field .' = '. $placeholders[$id]; - } - - foreach ($update as $key){ - $conditions[] = "$key = ". db_type_placeholder($schema['fields'][$key]['type']); - $values[] = $object->$key; + $conditions[] = "[$key] = ". db_type_placeholder($schema['fields'][$key]['type']); + $args[] = $value; } - - $query = "UPDATE {". $table ."} SET $query WHERE ". implode(' AND ', $conditions); + $result = db_query_update($table, $values, implode(' AND ', $conditions), $args); $return = SAVED_UPDATED; } - // Execute the SQL. - if (db_query($query, $values)) { + if ($result) { if ($serials) { // Get last insert ids and fill them in. foreach ($serials as $field) { @@ -3331,6 +3338,47 @@ function drupal_write_record($table, &$o } /** + * Drop a record from the database based upon the schema. + * + * @param $table + * The name of the table; this must exist in schema API. + * @param $object + * The object to drop. This is a reference, as defaults according to + * the schema may be filled in on the object, as well as ID on the serial + * type(s). Both array an object types may be passed. + * @param primary_keys + * Specify the primary keys' field names. If there is only 1 key, you may + * pass a simple string. + * @return (boolean) Failure to write a record will return FALSE. Otherwise, + * TRUE is returned. + */ +function drupal_drop_record($table, $object, $primary_keys = array()) { + // Standardize $primary_keys to an array. + if (!is_array($primary_keys)) { + $primary_keys = array($primary_keys); + } + + // Convert to an object if needed. + if ($array = is_array($object)) { + $object = (object) $object; + } + + $schema = drupal_get_schema($table); + if (empty($schema)) { + return FALSE; + } + + // Execute the request. + foreach ($primary_keys as $key){ + $conditions[] = "[$key] = ". db_type_placeholder($schema['fields'][$key]['type']); + $args[] = $object->$key; + } + db_query_delete($table, implode(' AND ', $conditions), $args); + + return SAVED_DELETED; +} + +/** * @} End of "ingroup schemaapi". */ Index: includes/common.mysql.inc =================================================================== RCS file: includes/common.mysql.inc diff -N includes/common.mysql.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/common.mysql.inc 31 Mar 2008 17:25:48 -0000 @@ -0,0 +1,385 @@ + 0) ? "CONCAT($return)" : ''; +} + +/** + * Returns a string that is the equivalent of MySQL IFNULL or Oracle NVL. + * + * @return + * If $expr1 is not NULL, returns $expr1; otherwise it returns $expr2. + */ +function db_if_null($expr1, $expr2) { + return " IFNULL($expr1, $expr2) "; +} + +/** + * Report database status. + */ +function db_status_report($phase) { + $t = get_t(); + + $version = db_version(); + + $form['mysql'] = array( + 'title' => $t('MySQL database'), + 'value' => ($phase == 'runtime') ? l($version, 'admin/reports/status/sql') : $version, + ); + + if (version_compare($version, DRUPAL_MINIMUM_MYSQL) < 0) { + $form['mysql']['severity'] = REQUIREMENT_ERROR; + $form['mysql']['description'] = $t('Your MySQL Server is too old. Drupal requires at least MySQL %version.', array('%version' => DRUPAL_MINIMUM_MYSQL)); + } + + return $form; +} + +/** + * Returns the version of the database server currently in use. + * + * @return Database server version + */ +function db_version() { + global $active_db; + list($version) = explode('-', db_result(db_query("SELECT VERSION();"))); + return $version; +} + +/** + * Insert a row of record into database. + * + * @param $table + * Table to insert. + * @param $values + * An array containing the insert values. Each element of the array + * should be an associatie array with the following keys: + * - "field": The database field represented in the table column. + * - "placeholder": The placeholder of the table column, using printf() + * syntax. Valid %-modifiers are: %d, %f, %s and %b. + * - "data": The data to insert into the table column. + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query_insert($table, $values) { + $fields = array(); + $placeholders = array(); + $data = array(); + foreach ($values as $value) { + $fields[] = $value['field']; + $placeholders[] = $value['placeholder']; + $data[] = $value['data']; + } + + if (!count($fields)) { + return FALSE; + } + + $query = "INSERT INTO [{". $table ."}] ([". implode('], [', $fields) ."]) VALUES (". implode(', ', $placeholders) .")"; + return db_query($query, $data); +} + +/** + * Update a row of record in database. + * + * @param $table + * Table to update. + * @param $values + * An array containing the update values. Each element of the array + * should be an associatie array with the following keys: + * - "field": The database field represented in the table column. + * - "placeholder": The placeholder of the table column, using printf() + * syntax. Valid %-modifiers are: %d, %f, %s and %b. + * - "data": The data to insert into the table column. + * @param $where_clause + * A string containing an update condition query (where clause). + * @param ... + * A variable number of arguments which are substituted into the query + * WHERE condition, using printf() syntax. Instead of a variable number + * of query arguments, you may also pass a single array containing the + * query arguments. + * + * Valid %-modifiers are: %d, %f and %s. + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query_update($table, $values, $where_clause = NULL) { + $args = func_get_args(); + $args = array_slice($args, 3); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + + $fields = array(); + $data = array(); + foreach ($values as $value) { + $fields[] = '['. $value['field'] .'] = '. $value['placeholder']; + $data[] = $value['data']; + } + + if (!count($fields)) { + return FALSE; + } + + $query = "UPDATE [{". $table ."}] SET ". implode(', ', $fields); + if ($where_clause) { + $query .= " WHERE ". $where_clause; + $data = array_merge($data, $args); + } + return db_query($query, $data); +} + +/** + * Delete a row of record from database. + * + * @param $table + * Table to delete. + * @param $where_clause + * A string containing an update condition query (where clause). + * @param ... + * A variable number of arguments which are substituted into the query + * WHERE condition, using printf() syntax. Instead of a variable number + * of query arguments, you may also pass a single array containing the + * query arguments. + * + * Valid %-modifiers are: %d, %f and %s. + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query_delete($table, $where_clause = NULL) { + $args = func_get_args(); + $args = array_slice($args, 2); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + + $data = array(); + + $query = "DELETE FROM [{". $table ."}]"; + if ($where_clause) { + $query .= " WHERE ". $where_clause; + $data = $args; + } + return db_query($query, $data); +} + +/** + * Returns the last insert id. + * + * @param $table + * The name of the table you inserted into. + * @param $field + * The name of the autoincrement field. + */ +function db_last_insert_id($table, $field) { + return db_result(db_query('SELECT LAST_INSERT_ID()')); +} + +/** + * Runs a limited-range query in the active database. + * + * Use this as a substitute for db_query() when a subset of the query is to be + * returned. + * User-supplied arguments to the query should be passed in as separate parameters + * so that they can be properly escaped to avoid SQL injection attacks. + * + * @param $query + * A string containing an SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. The query arguments can be enclosed in one + * array instead. + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @param $from + * The first result row to return. + * @param $count + * The maximum number of result rows to return. + * @return + * A database query result resource, or FALSE if the query was not executed + * correctly. + */ +function db_query_range($query) { + $args = func_get_args(); + $count = array_pop($args); + $from = array_pop($args); + array_shift($args); + + $query .= ' LIMIT '. (int) $from .', '. (int) $count; + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + return db_query($query, $args); +} + +/** + * Runs a SELECT query and stores its results in a temporary table. + * + * Use this as a substitute for db_query() when the results need to stored + * in a temporary table. Temporary tables exist for the duration of the page + * request. + * User-supplied arguments to the query should be passed in as separate parameters + * so that they can be properly escaped to avoid SQL injection attacks. + * + * Note that if you need to know how many results were returned, you should do + * a SELECT COUNT(*) on the temporary table afterwards. db_affected_rows() does + * not give consistent result across different database types in this case. + * + * @param $query + * A string containing a normal SELECT SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. The query arguments can be enclosed in one + * array instead. + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @param $table + * The name of the temporary table to select into. This name will not be + * prefixed as there is no risk of collision. + * @return + * A database query result resource, or FALSE if the query was not executed + * correctly. + */ +function db_query_temporary($query) { + $args = func_get_args(); + $tablename = array_pop($args); + array_shift($args); + + $query = preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE '. $tablename .' Engine=HEAP SELECT', $query); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + return db_query($query, $args); +} + +/** + * Lock a table. + */ +function db_lock_table($table) { + db_query('LOCK TABLES [{'. db_escape_table($table) .'}] WRITE'); +} + +/** + * Unlock all locked tables. + */ +function db_unlock_tables() { + db_query('UNLOCK TABLES'); +} + +/** + * Check if a table exists. + */ +function db_table_exists($table) { + return (bool) db_fetch_object(db_query("SHOW TABLES LIKE '{". db_escape_table($table) ."}'")); +} + +/** + * Check if a column exists in the given table. + */ +function db_column_exists($table, $column) { + return (bool) db_fetch_object(db_query("SHOW COLUMNS FROM [{". db_escape_table($table) ."}] LIKE '". db_escape_table($column) ."'")); +} + +/** + * Wraps the given table.field entry with a DISTINCT(). The wrapper is added to + * the SELECT list entry of the given query and the resulting query is returned. + * This function only applies the wrapper if a DISTINCT doesn't already exist in + * the query. + * + * @param $table Table containing the field to set as DISTINCT + * @param $field Field to set as DISTINCT + * @param $query Query to apply the wrapper to + * @return SQL query with the DISTINCT wrapper surrounding the given table.field. + */ +function db_distinct_field($table, $field, $query) { + $field_to_select = 'DISTINCT(['. $table .'].['. $field .'])'; + // (? 30) { + // Try to fetch mapping, if not exists, set it up. + $trim = variable_get('oracle_'. $match, NULL); + if (!$trim) { + // Fetch last counter, and +1 for next mapping. + $count = variable_get('_db_escape_quote', 0) + 1; + variable_set('_db_escape_quote', $count); + // Setup mapping and reverse mapping. + $trim = substr($match, 0, 30 - strlen($count)) . $count; + variable_set('oracle_'. $match, $trim); + variable_set('oracle_'. $trim, $match); + $match = $trim; + } + } + return DB_QUOTE_OPERATOR . $match . DB_QUOTE_OPERATOR; +} + +/** + * Return a portably concatenate strings. + * + * @param ... + * Variable number of string parameters. + * @return + * Portably concatenate strings. + */ +function db_concat() { + $args = func_get_args(); + return implode(DB_CONCAT_OPERATOR, $args); +} + +/** + * Returns a string that is the equivalent of MySQL IFNULL or Oracle NVL. + * + * @return + * If $expr1 is not NULL, returns $expr1; otherwise it returns $expr2. + */ +function db_if_null($expr1, $expr2) { + return " NVL($expr1, $expr2) "; +} + +/** + * Report database status. + */ +function db_status_report($phase) { + $t = get_t(); + + $version = db_version(); + + $form['oracle'] = array( + 'title' => $t('Oracle database'), + 'value' => $version, + ); + + if (version_compare($version, DRUPAL_MINIMUM_ORACLE) < 0) { + $form['oracle']['severity'] = REQUIREMENT_ERROR; + $form['oracle']['description'] = $t('Your Oracle Server is too old. Drupal requires at least Oracle %version.', array('%version' => DRUPAL_MINIMUM_ORACLE)); + } + + return $form; +} + +/** + * Returns the version of the database server currently in use. + * + * @return Database server version + */ +function db_version() { + $banner = db_result(db_query('SELECT BANNER FROM SYS.V_$VERSION')); + preg_match('/\s([0-9.]+)\s/', $banner, $version); + return array_pop($version); +} + +/** + * Insert a row of record into database. + * + * @param $table + * Table to insert. + * @param $values + * An array containing the insert values. Each element of the array + * should be an associatie array with the following keys: + * - "field": The database field represented in the table column. + * - "placeholder": The placeholder of the table column, using printf() + * syntax. Valid %-modifiers are: %d, %f, %s and %b. + * - "data": The data to insert into the table column. + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query_insert($table, $values) { + $fields = array(); + $placeholders = array(); + $args = array(); + $lob_fields = array(); + $lob_placeholders = array(); + $lob_args = array(); + foreach ($values as $value) { + $fields[] = $value['field']; + switch ($value['placeholder']) { + case '%b': + $placeholders[] = 'EMPTY_BLOB()'; + $lob_fields[] = $value['field']; + $lob_placeholders[] = $value['placeholder']; + $lob_args[] = $value['data']; + break; + case '%c': + $placeholders[] = 'EMPTY_CLOB()'; + $lob_fields[] = $value['field']; + $lob_placeholders[] = $value['placeholder']; + $lob_args[] = $value['data']; + break; + default: + $placeholders[] = $value['placeholder']; + $args[] = $value['data']; + } + } + + $query = "INSERT INTO [{". $table ."}] ([". implode('], [', $fields) ."]) VALUES (". implode(', ', $placeholders) .")"; + if (count($lob_fields)) { + $query .= " RETURNING [". implode('], [', $lob_fields) ."] INTO ". implode(', ', $lob_placeholders); + $args = array_merge($args, $lob_args); + } + return db_query($query, $args); +} + +/** + * Update a row of record in database. + * + * @param $table + * Table to update. + * @param $values + * An array containing the update values. Each element of the array + * should be an associatie array with the following keys: + * - "field": The database field represented in the table column. + * - "placeholder": The placeholder of the table column, using printf() + * syntax. Valid %-modifiers are: %d, %f, %s and %b. + * - "data": The data to insert into the table column. + * @param $where_clause + * A string containing an update condition query (where clause). + * @param ... + * A variable number of arguments which are substituted into the query + * WHERE condition, using printf() syntax. Instead of a variable number + * of query arguments, you may also pass a single array containing the + * query arguments. + * + * Valid %-modifiers are: %d, %f and %s. + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query_update($table, $values, $where_clause = NULL) { + global $active_db, $last_result, $queries; + + $where_args = func_get_args(); + $where_args = array_slice($where_args, 3); + if (isset($where_args[0]) and is_array($where_args[0])) { // 'All arguments in one array' syntax + $where_args = $where_args[0]; + } + + $fields = array(); + $args = array(); + $lob_fields = array(); + $lob_placeholders = array(); + $lob_args = array(); + foreach ($values as $value) { + switch ($value['placeholder']) { + case '%b': + $fields[] = '['. $value['field'] .'] = EMPTY_BLOB()'; + $lob_fields[] = $value['field']; + $lob_placeholders[] = $value['placeholder']; + $lob_args[] = $value['data']; + break; + case '%c': + $fields[] = '['. $value['field'] .'] = EMPTY_CLOB()'; + $lob_fields[] = $value['field']; + $lob_placeholders[] = $value['placeholder']; + $lob_args[] = $value['data']; + break; + default: + $fields[] = '['. $value['field'] .'] = '. $value['placeholder']; + $args[] = $value['data']; + } + } + + $query = "UPDATE [{". $table ."}] SET ". implode(', ', $fields); + if ($where_clause) { + $query .= " WHERE ". $where_clause; + $args = array_merge($args, $where_args); + } + if (count($lob_fields)) { + $query .= " RETURNING [". implode('], [', $lob_fields) ."] INTO ". implode(', ', $lob_placeholders); + $args = array_merge($args, $lob_args); + } + return db_query($query, $args); +} + +/** + * Delete a row of record from database. + * + * @param $table + * Table to delete. + * @param $where_clause + * A string containing an update condition query (where clause). + * @param ... + * A variable number of arguments which are substituted into the query + * WHERE condition, using printf() syntax. Instead of a variable number + * of query arguments, you may also pass a single array containing the + * query arguments. + * + * Valid %-modifiers are: %d, %f and %s. + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query_delete($table, $where_clause = NULL) { + $args = func_get_args(); + $args = array_slice($args, 2); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + + $query['query'] = "DELETE FROM [{". $table ."}]"; + if ($where_clause) { + $query['query'] .= " WHERE ". $where_clause; + } + return db_query($query, $args); +} + +/** + * Returns the last insert id. This function is thread safe. + * + * @param $table + * The name of the table you inserted into. + * @param $field + * The name of the autoincrement field. + */ +function db_last_insert_id($table, $field) { + return db_result(db_query("SELECT [seq_{". $table ."}_" . $field ."].CURRVAL FROM DUAL")); +} + +/** + * Runs a limited-range query in the active database. + * + * Use this as a substitute for db_query() when a subset of the query + * is to be returned. + * User-supplied arguments to the query should be passed in as separate + * parameters so that they can be properly escaped to avoid SQL injection + * attacks. + * + * @param $query + * A string containing an SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. Instead of a variable number of query arguments, + * you may also pass a single array containing the query arguments. + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). + * + * NOTE: use NULL as arguments substitution for %b and %c. This will be + * replaced as corresponding empty LOB value placeholder, based on the + * database specific representation. + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @param $from + * The first result row to return. + * @param $count + * The maximum number of result rows to return. + * @return + * A database query result resource, or FALSE if the query was not executed + * correctly. + */ +function db_query_range($query) { + $args = func_get_args(); + $count = array_pop($args); + $from = array_pop($args); + array_shift($args); + + $query = 'SELECT * FROM (SELECT [sub1].*, ROWNUM AS [line2] FROM ('. $query .') [sub1]) WHERE [line2] BETWEEN '. ($from + 1) .' AND '. ($from + $count); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + return db_query($query, $args); +} + +/** + * Runs a SELECT query and stores its results in a temporary table. + * + * Use this as a substitute for db_query() when the results need to stored + * in a temporary table. Temporary tables exist for the duration of the page + * request. + * User-supplied arguments to the query should be passed in as separate parameters + * so that they can be properly escaped to avoid SQL injection attacks. + * + * Note that if you need to know how many results were returned, you should do + * a SELECT COUNT(*) on the temporary table afterwards. db_affected_rows() do + * not give consistent result across different database types in this case. + * + * @param $query + * A string containing a normal SELECT SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. The query arguments can be enclosed in one + * array instead. + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). + * + * NOTE: use NULL as arguments substitution for %b and %c. This will be + * replaced as corresponding empty LOB value placeholder, based on the + * database specific representation. + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @param $table + * The name of the temporary table to select into. This name will not be + * prefixed as there is no risk of collision. + * @return + * A database query result resource, or FALSE if the query was not executed + * correctly. + */ +function db_query_temporary($query) { + $args = func_get_args(); + $tablename = array_pop($args); + array_shift($args); + + $query = preg_replace('/^SELECT/i', 'CREATE GLOBAL TEMPORARY TABLE ['. $tablename .'] ON COMMIT PRESERVE ROWS AS SELECT', $query); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + return db_query($query, $args); +} + +/** + * Lock a table. + * This function automatically starts a transaction. + */ +function db_lock_table($table) { + db_query('LOCK TABLE [{'. db_escape_table($table) .'}] IN EXCLUSIVE MODE'); +} + +/** + * Unlock all locked tables. + * This function automatically commits a transaction. + */ +function db_unlock_tables() { + db_query('COMMIT'); +} + +/** + * Check if a table exists. + */ +function db_table_exists($table) { + return db_result(db_query("SELECT COUNT(TABLE_NAME) FROM USER_TABLES WHERE TABLE_NAME LIKE '{". db_escape_table($table) ."}'")) ? TRUE : FALSE; +} + +/** + * Check if a column exists in the given table. + */ +function db_column_exists($table, $column) { + return db_result(db_query("SELECT COUNT(COLUMN_NAME) FROM USER_TAB_COLS WHERE TABLE_NAME LIKE '{". db_escape_table($table) ."}' AND COLUMN_NAME LIKE '". db_escape_table($column) ."'")) ? TRUE : FALSE; +} + +/** + * Check if constraint exists in the given table. + */ +function db_constraint_exists($table, $fields) { + $queries = array(); + foreach ($fields as $key => $value) { + $queries[] = "SELECT CONSTRAINT_NAME FROM USER_CONS_COLUMNS WHERE TABLE_NAME LIKE '{". db_escape_table($table) ."}' AND COLUMN_NAME LIKE '". db_escape_table($value) ."'"; + } + return db_result(db_query(implode(' INTERSECT ', $queries))) ? TRUE : FALSE; +} + +/** + * Wraps the given table.field entry with a DISTINCT(). The wrapper is added to + * the SELECT list entry of the given query and the resulting query is returned. + * This function only applies the wrapper if a DISTINCT doesn't already exist in + * the query. + * + * @param $table Table containing the field to set as DISTINCT + * @param $field Field to set as DISTINCT + * @param $query Query to apply the wrapper to + * @return SQL query with the DISTINCT wrapper surrounding the given table.field. + */ +function db_distinct_field($table, $field, $query) { + $field_to_select = 'DISTINCT (['. $table .'].['. $field .'])'; + // (? $t('PostgreSQL database'), + 'value' => $version, + ); + + if (version_compare($version, DRUPAL_MINIMUM_POSTGRESQL) < 0) { + $form['postgresql']['severity'] = REQUIREMENT_ERROR; + $form['postgresql']['description'] = $t('Your PostgreSQL Server is too old. Drupal requires at least PostgreSQL %version.', array('%version' => DRUPAL_MINIMUM_POSTGRESQL)); + } + + return $form; +} + +/** + * Returns the version of the database server currently in use. + * + * @return Database server version + */ +function db_version() { + return db_result(db_query("SHOW SERVER_VERSION")); +} + +/** + * Insert a row of record into database. + * + * @param $table + * Table to insert. + * @param $values + * An array containing the insert values. Each element of the array + * should be an associatie array with the following keys: + * - "field": The database field represented in the table column. + * - "placeholder": The placeholder of the table column, using printf() + * syntax. Valid %-modifiers are: %d, %f, %s and %b. + * - "data": The data to insert into the table column. + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query_insert($table, $values) { + $fields = array(); + $placeholders = array(); + $data = array(); + foreach ($values as $value) { + $fields[] = $value['field']; + $placeholders[] = $value['placeholder']; + $data[] = $value['data']; + } + + if (!count($fields)) { + return FALSE; + } + + $query = "INSERT INTO [{". $table ."}] ([". implode('], [', $fields) ."]) VALUES (". implode(', ', $placeholders) .")"; + return db_query($query, $data); +} + +/** + * Update a row of record in database. + * + * @param $table + * Table to update. + * @param $values + * An array containing the update values. Each element of the array + * should be an associatie array with the following keys: + * - "field": The database field represented in the table column. + * - "placeholder": The placeholder of the table column, using printf() + * syntax. Valid %-modifiers are: %d, %f, %s and %b. + * - "data": The data to insert into the table column. + * @param $where_clause + * A string containing an update condition query (where clause). + * @param ... + * A variable number of arguments which are substituted into the query + * WHERE condition, using printf() syntax. Instead of a variable number + * of query arguments, you may also pass a single array containing the + * query arguments. + * + * Valid %-modifiers are: %d, %f and %s. + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query_update($table, $values, $where_clause = NULL) { + $args = func_get_args(); + $args = array_slice($args, 3); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + + $fields = array(); + $data = array(); + foreach ($values as $value) { + $fields[] = '['. $value['field'] .'] = '. $value['placeholder']; + $data[] = $value['data']; + } + + if (!count($fields)) { + return FALSE; + } + + $query = "UPDATE [{". $table ."}] SET ". implode(', ', $fields); + if ($where_clause) { + $query .= " WHERE ". $where_clause; + $data = array_merge($data, $args); + } + return db_query($query, $data); +} + +/** + * Delete a row of record from database. + * + * @param $table + * Table to delete. + * @param $where_clause + * A string containing an update condition query (where clause). + * @param ... + * A variable number of arguments which are substituted into the query + * WHERE condition, using printf() syntax. Instead of a variable number + * of query arguments, you may also pass a single array containing the + * query arguments. + * + * Valid %-modifiers are: %d, %f and %s. + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query_delete($table, $where_clause = NULL) { + $args = func_get_args(); + $args = array_slice($args, 2); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + + $data = array(); + + $query = "DELETE FROM [{". $table ."}]"; + if ($where_clause) { + $query .= " WHERE ". $where_clause; + $data = $args; + } + return db_query($query, $data); +} + +/** + * Returns the last insert id. This function is thread safe. + * + * @param $table + * The name of the table you inserted into. + * @param $field + * The name of the autoincrement field. + */ +function db_last_insert_id($table, $field) { + return db_result(db_query("SELECT CURRVAL('{". db_escape_table($table) ."}_". db_escape_table($field) ."_seq')")); +} + +/** + * Runs a limited-range query in the active database. + * + * Use this as a substitute for db_query() when a subset of the query + * is to be returned. + * User-supplied arguments to the query should be passed in as separate + * parameters so that they can be properly escaped to avoid SQL injection + * attacks. + * + * @param $query + * A string containing an SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. Instead of a variable number of query arguments, + * you may also pass a single array containing the query arguments. + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @param $from + * The first result row to return. + * @param $count + * The maximum number of result rows to return. + * @return + * A database query result resource, or FALSE if the query was not executed + * correctly. + */ +function db_query_range($query) { + $args = func_get_args(); + $count = array_pop($args); + $from = array_pop($args); + array_shift($args); + + $query .= ' LIMIT '. (int) $count .' OFFSET '. (int) $from; + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + return db_query($query, $args); +} + +/** + * Runs a SELECT query and stores its results in a temporary table. + * + * Use this as a substitute for db_query() when the results need to stored + * in a temporary table. Temporary tables exist for the duration of the page + * request. + * User-supplied arguments to the query should be passed in as separate parameters + * so that they can be properly escaped to avoid SQL injection attacks. + * + * Note that if you need to know how many results were returned, you should do + * a SELECT COUNT(*) on the temporary table afterwards. db_affected_rows() does + * not give consistent result across different database types in this case. + * + * @param $query + * A string containing a normal SELECT SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. The query arguments can be enclosed in one + * array instead. + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @param $table + * The name of the temporary table to select into. This name will not be + * prefixed as there is no risk of collision. + * @return + * A database query result resource, or FALSE if the query was not executed + * correctly. + */ +function db_query_temporary($query) { + $args = func_get_args(); + $tablename = array_pop($args); + array_shift($args); + + $query = preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE '. $tablename .' AS SELECT', $query); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + return db_query($query, $args); +} + +/** + * Lock a table. + * This function automatically starts a transaction. + */ +function db_lock_table($table) { + db_query('LOCK TABLE [{'. db_escape_table($table) .'}] IN EXCLUSIVE MODE'); +} + +/** + * Unlock all locked tables. + * This function automatically commits a transaction. + */ +function db_unlock_tables() { + db_query('COMMIT'); +} + +/** + * Check if a table exists. + */ +function db_table_exists($table) { + return (bool) db_result(db_query("SELECT COUNT(*) FROM [pg_class] WHERE [relname] = '{". db_escape_table($table) ."}'")); +} + +/** + * Check if a column exists in the given table. + */ +function db_column_exists($table, $column) { + return (bool) db_result(db_query("SELECT COUNT([pg_attribute].[attname]) FROM [pg_class], [pg_attribute] WHERE [pg_attribute].[attrelid] = [pg_class].[oid] AND [pg_class].[relname] = '{". db_escape_table($table) ."}' AND [attname] = '". db_escape_table($column) ."'")); +} + +/** + * Wraps the given table.field entry with a DISTINCT(). The wrapper is added to + * the SELECT list entry of the given query and the resulting query is returned. + * This function only applies the wrapper if a DISTINCT doesn't already exist in + * the query. + * + * @param $table Table containing the field to set as DISTINCT + * @param $field Field to set as DISTINCT + * @param $query Query to apply the wrapper to + * @return SQL query with the DISTINCT wrapper surrounding the given table.field. + */ +function db_distinct_field($table, $field, $query) { + $field_to_select = 'DISTINCT ON (['. $table .'].['. $field ."]) [$table].[$field]"; + // (?PostgreSQL documentation.', array('%encoding' => $encoding, '@url' => 'http://www.postgresql.org/docs/7.4/interactive/multibyte.html')), 'status'); + } +} + +/** + * @} End of "ingroup database". + */ Index: includes/common.sqlite.inc =================================================================== RCS file: includes/common.sqlite.inc diff -N includes/common.sqlite.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/common.sqlite.inc 31 Mar 2008 17:25:51 -0000 @@ -0,0 +1,393 @@ + $t('SQLite database'), + 'value' => $version, + ); + + if (version_compare($version, DRUPAL_MINIMUM_SQLITE) < 0) { + $form['sqlite']['severity'] = REQUIREMENT_ERROR; + $form['sqlite']['description'] = $t('Your SQLite Server is too old. Drupal requires at least SQLite %version.', array('%version' => DRUPAL_MINIMUM_SQLITE)); + } + + return $form; +} + +/** + * Returns the version of the database server currently in use. + * + * @return Database server version + */ +function db_version() { + return db_result(db_query("SELECT SQLITE_VERSION()")); +} + +/** + * Insert a row of record into database. + * + * @param $table + * Table to insert. + * @param $values + * An array containing the insert values. Each element of the array + * should be an associatie array with the following keys: + * - "field": The database field represented in the table column. + * - "placeholder": The placeholder of the table column, using printf() + * syntax. Valid %-modifiers are: %d, %f, %s and %b. + * - "data": The data to insert into the table column. + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query_insert($table, $values) { + $fields = array(); + $placeholders = array(); + $data = array(); + foreach ($values as $value) { + $fields[] = $value['field']; + $placeholders[] = $value['placeholder']; + $data[] = $value['data']; + } + + if (!count($fields)) { + return FALSE; + } + + $query = "INSERT INTO [{". $table ."}] ([". implode('], [', $fields) ."]) VALUES (". implode(', ', $placeholders) .")"; + return db_query($query, $data); +} + +/** + * Update a row of record in database. + * + * @param $table + * Table to update. + * @param $values + * An array containing the update values. Each element of the array + * should be an associatie array with the following keys: + * - "field": The database field represented in the table column. + * - "placeholder": The placeholder of the table column, using printf() + * syntax. Valid %-modifiers are: %d, %f, %s and %b. + * - "data": The data to insert into the table column. + * @param $where_clause + * A string containing an update condition query (where clause). + * @param ... + * A variable number of arguments which are substituted into the query + * WHERE condition, using printf() syntax. Instead of a variable number + * of query arguments, you may also pass a single array containing the + * query arguments. + * + * Valid %-modifiers are: %d, %f and %s. + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query_update($table, $values, $where_clause = NULL) { + $args = func_get_args(); + $args = array_slice($args, 3); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + + $fields = array(); + $data = array(); + foreach ($values as $value) { + $fields[] = '['. $value['field'] .'] = '. $value['placeholder']; + $data[] = $value['data']; + } + + if (!count($fields)) { + return FALSE; + } + + $query = "UPDATE [{". $table ."}] SET ". implode(', ', $fields); + if ($where_clause) { + $query .= " WHERE ". $where_clause; + $data = array_merge($data, $args); + } + return db_query($query, $data); +} + +/** + * Delete a row of record from database. + * + * @param $table + * Table to delete. + * @param $where_clause + * A string containing an update condition query (where clause). + * @param ... + * A variable number of arguments which are substituted into the query + * WHERE condition, using printf() syntax. Instead of a variable number + * of query arguments, you may also pass a single array containing the + * query arguments. + * + * Valid %-modifiers are: %d, %f and %s. + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query_delete($table, $where_clause = NULL) { + $args = func_get_args(); + $args = array_slice($args, 2); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + + $data = array(); + + $query = "DELETE FROM [{". $table ."}]"; + if ($where_clause) { + $query .= " WHERE ". $where_clause; + $data = $args; + } + return db_query($query, $data); +} + +/** + * Returns the last insert id. This function is thread safe. + * + * @param $table + * The name of the table you inserted into. + * @param $field + * The name of the autoincrement field. + */ +function db_last_insert_id($table, $field) { + return db_result(db_query("SELECT LAST_INSERT_ROWID()")); +} + +/** + * Runs a limited-range query in the active database. + * + * Use this as a substitute for db_query() when a subset of the query + * is to be returned. + * User-supplied arguments to the query should be passed in as separate + * parameters so that they can be properly escaped to avoid SQL injection + * attacks. + * + * @param $query + * A string containing an SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. Instead of a variable number of query arguments, + * you may also pass a single array containing the query arguments. + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @param $from + * The first result row to return. + * @param $count + * The maximum number of result rows to return. + * @return + * A database query result resource, or FALSE if the query was not executed + * correctly. + */ +function db_query_range($query) { + $args = func_get_args(); + $count = array_pop($args); + $from = array_pop($args); + array_shift($args); + + $query .= ' LIMIT '. (int) $count .' OFFSET '. (int) $from; + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + return db_query($query, $args); +} + +/** + * Runs a SELECT query and stores its results in a temporary table. + * + * Use this as a substitute for db_query() when the results need to stored + * in a temporary table. Temporary tables exist for the duration of the page + * request. + * User-supplied arguments to the query should be passed in as separate parameters + * so that they can be properly escaped to avoid SQL injection attacks. + * + * Note that if you need to know how many results were returned, you should do + * a SELECT COUNT(*) on the temporary table afterwards. db_affected_rows() does + * not give consistent result across different database types in this case. + * + * @param $query + * A string containing a normal SELECT SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. The query arguments can be enclosed in one + * array instead. + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @param $table + * The name of the temporary table to select into. This name will not be + * prefixed as there is no risk of collision. + * @return + * A database query result resource, or FALSE if the query was not executed + * correctly. + */ +function db_query_temporary($query) { + $args = func_get_args(); + $tablename = array_pop($args); + array_shift($args); + + $query = preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE '. $tablename .' AS SELECT', $query); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + return db_query($query, $args); +} + +/** + * Lock a table. + * This function automatically starts a transaction. + */ +function db_lock_table($table) { + db_query('BEGIN'); +} + +/** + * Unlock all locked tables. + * This function automatically commits a transaction. + */ +function db_unlock_tables() { + db_query('COMMIT'); +} + +/** + * Check if a table exists. + */ +function db_table_exists($table) { + return (bool) db_result(db_query("SELECT COUNT(*) FROM SQLITE_MASTER WHERE TBL_NAME LIKE '{". db_escape_table($table) ."}'")); +} + +/** + * Check if a column exists in the given table. + */ +function db_column_exists($table, $column) { + $result = db_query("PRAGMA TABLE_INFO('{". db_escape_table($table) ."}')"); + while ($column = db_fetch_array($result)) { + if ($column['name'] == $column) { + return TRUE; + } + } + return FALSE; +} + +/** + * Wraps the given table.field entry with a DISTINCT(). The wrapper is added to + * the SELECT list entry of the given query and the resulting query is returned. + * This function only applies the wrapper if a DISTINCT doesn't already exist in + * the query. + * + * @param $table Table containing the field to set as DISTINCT + * @param $field Field to set as DISTINCT + * @param $query Query to apply the wrapper to + * @return SQL query with the DISTINCT wrapper surrounding the given table.field. + */ +function db_distinct_field($table, $field, $query) { + $field_to_select = 'DISTINCT ON (['. $table .'].['. $field ."]) [$table].[$field]"; + // (? $field) { - $sql .= _db_create_field_sql($field_name, _db_process_field($field)) .", \n"; - } - - // Process keys & indexes. - $keys = _db_create_keys_sql($table); - if (count($keys)) { - $sql .= implode(", \n", $keys) .", \n"; - } - - // Remove the last comma and space. - $sql = substr($sql, 0, -3) ."\n) "; - - $sql .= $table['mysql_suffix']; - - return array($sql); -} - -function _db_create_keys_sql($spec) { - $keys = array(); - - if (!empty($spec['primary key'])) { - $keys[] = 'PRIMARY KEY ('. _db_create_key_sql($spec['primary key']) .')'; - } - if (!empty($spec['unique keys'])) { - foreach ($spec['unique keys'] as $key => $fields) { - $keys[] = 'UNIQUE KEY '. $key .' ('. _db_create_key_sql($fields) .')'; - } - } - if (!empty($spec['indexes'])) { - foreach ($spec['indexes'] as $index => $fields) { - $keys[] = 'INDEX '. $index .' ('. _db_create_key_sql($fields) .')'; - } - } - - return $keys; -} - -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', - 'char:normal' => 'CHAR', - - 'text:tiny' => 'TINYTEXT', - 'text:small' => 'TINYTEXT', - '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' => 'DECIMAL', - - 'blob:big' => 'LONGBLOB', - 'blob:normal' => 'BLOB', - - 'datetime:normal' => 'DATETIME', - ); - return $map; -} - -/** - * Rename a table. - * - * @param $ret - * Array to which query results will be added. - * @param $table - * The table to be renamed. - * @param $new_name - * The new name for the table. - */ -function db_rename_table(&$ret, $table, $new_name) { - $ret[] = update_sql('ALTER TABLE {'. $table .'} RENAME TO {'. $new_name .'}'); -} - -/** - * 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. - * The specification may also contain the key 'initial', the newly - * created field will be set to the value of the key in all rows. - * This is most useful for creating NOT NULL columns with no default - * value in existing tables. - * @param $keys_new - * Optional keys and indexes specification to be created on the - * table along with adding the field. The format is the same as a - * table specification but without the 'fields' element. If you are - * adding a type 'serial' field, you MUST specify at least one key - * or index including it in this array. @see db_change_field for more - * explanation why. - */ -function db_add_field(&$ret, $table, $field, $spec, $keys_new = array()) { - $fixnull = FALSE; - if (!empty($spec['not null']) && !isset($spec['default'])) { - $fixnull = TRUE; - $spec['not null'] = FALSE; - } - $query = 'ALTER TABLE {'. $table .'} ADD '; - $query .= _db_create_field_sql($field, _db_process_field($spec)); - if (count($keys_new)) { - $query .= ', ADD '. implode(', ADD ', _db_create_keys_sql($keys_new)); - } - $ret[] = update_sql($query); - if (isset($spec['initial'])) { - // All this because update_sql does not support %-placeholders. - $sql = 'UPDATE {'. $table .'} SET '. $field .' = '. db_type_placeholder($spec['type']); - $result = db_query($sql, $spec['initial']); - $ret[] = array('success' => $result !== FALSE, 'query' => check_plain($sql .' ('. $spec['initial'] .')')); - } - if ($fixnull) { - $spec['not null'] = TRUE; - db_change_field($ret, $table, $field, $field, $spec); - } -} - -/** - * 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 - * Array to which query results will be added. - * @param $table - * The table to be altered. - * @param $name - * The name of the key. - * @param $fields - * An array of field names. - */ -function db_add_unique_key(&$ret, $table, $name, $fields) { - $ret[] = update_sql('ALTER TABLE {'. $table .'} ADD UNIQUE KEY '. - $name .' ('. _db_create_key_sql($fields) .')'); -} - -/** - * Drop a unique key. - * - * @param $ret - * Array to which query results will be added. - * @param $table - * The table to be altered. - * @param $name - * The name of the key. - */ -function db_drop_unique_key(&$ret, $table, $name) { - $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP KEY '. $name); -} - -/** - * Add an index. - * - * @param $ret - * Array to which query results will be added. - * @param $table - * The table to be altered. - * @param $name - * The name of the index. - * @param $fields - * An array of field names. - */ -function db_add_index(&$ret, $table, $name, $fields) { - $query = 'ALTER TABLE {'. $table .'} ADD INDEX '. $name .' ('. _db_create_key_sql($fields) .')'; - $ret[] = update_sql($query); -} - -/** - * Drop an index. - * - * @param $ret - * Array to which query results will be added. - * @param $table - * The table to be altered. - * @param $name - * The name of the index. - */ -function db_drop_index(&$ret, $table, $name) { - $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP INDEX '. $name); -} - -/** - * Change a field definition. - * - * IMPORTANT NOTE: To maintain database portability, you have to explicitly - * recreate all indices and primary keys that are using the changed field. - * - * That means that you have to drop all affected keys and indexes with - * db_drop_{primary_key,unique_key,index}() before calling db_change_field(). - * To recreate the keys and indices, pass the key definitions as the - * optional $keys_new argument directly to db_change_field(). - * - * For example, suppose you have: - * @code - * $schema['foo'] = array( - * 'fields' => array( - * 'bar' => array('type' => 'int', 'not null' => TRUE) - * ), - * 'primary key' => array('bar') - * ); - * @endcode - * and you want to change foo.bar to be type serial, leaving it as the - * primary key. The correct sequence is: - * @code - * db_drop_primary_key($ret, 'foo'); - * db_change_field($ret, 'foo', 'bar', 'bar', - * array('type' => 'serial', 'not null' => TRUE), - * array('primary key' => array('bar'))); - * @endcode - * - * The reasons for this are due to the different database engines: - * - * On PostgreSQL, changing a field definition involves adding a new field - * and dropping an old one which* causes any indices, primary keys and - * sequences (from serial-type fields) that use the changed field to be dropped. - * - * On MySQL, all type 'serial' fields must be part of at least one key - * or index as soon as they are created. You cannot use - * db_add_{primary_key,unique_key,index}() for this purpose because - * the ALTER TABLE command will fail to add the column without a key - * or index specification. The solution is to use the optional - * $keys_new argument to create the key or index at the same time as - * field. - * - * You could use db_add_{primary_key,unique_key,index}() in all cases - * unless you are converting a field to be type serial. You can use - * the $keys_new argument in all cases. - * - * @param $ret - * Array to which query results will be added. - * @param $table - * Name of the table. - * @param $field - * Name of the field to change. - * @param $field_new - * New name for the field (set to the same as $field if you don't want to change the name). - * @param $spec - * The field specification for the new field. - * @param $keys_new - * Optional keys and indexes specification to be created on the - * table along with changing the field. The format is the same as a - * table specification but without the 'fields' element. - */ - -function db_change_field(&$ret, $table, $field, $field_new, $spec, $keys_new = array()) { - $sql = 'ALTER TABLE {'. $table .'} CHANGE '. $field .' '. - _db_create_field_sql($field_new, _db_process_field($spec)); - if (count($keys_new)) { - $sql .= ', ADD '. implode(', ADD ', _db_create_keys_sql($keys_new)); - } - $ret[] = update_sql($sql); -} - -/** - * Returns the last insert id. - * - * @param $table - * The name of the table you inserted into. - * @param $field - * The name of the autoincrement field. - */ -function db_last_insert_id($table, $field) { - return db_result(db_query('SELECT LAST_INSERT_ID()')); -} Index: includes/database.mysql.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/database.mysql.inc,v retrieving revision 1.89 diff -u -p -r1.89 database.mysql.inc --- includes/database.mysql.inc 24 Jan 2008 10:46:54 -0000 1.89 +++ includes/database.mysql.inc 31 Mar 2008 17:25:54 -0000 @@ -11,61 +11,24 @@ * @{ */ -// Include functions shared between mysql and mysqli. -require_once './includes/database.mysql-common.inc'; +// Include functions shared between mysql, mysqli and pdo_mysql. +require_once './includes/common.mysql.inc'; -/** - * Report database status. - */ -function db_status_report($phase) { - $t = get_t(); - - $version = db_version(); - - $form['mysql'] = array( - 'title' => $t('MySQL database'), - 'value' => ($phase == 'runtime') ? l($version, 'admin/reports/status/sql') : $version, - ); - - if (version_compare($version, DRUPAL_MINIMUM_MYSQL) < 0) { - $form['mysql']['severity'] = REQUIREMENT_ERROR; - $form['mysql']['description'] = $t('Your MySQL Server is too old. Drupal requires at least MySQL %version.', array('%version' => DRUPAL_MINIMUM_MYSQL)); - } - - return $form; -} - -/** - * Returns the version of the database server currently in use. - * - * @return Database server version - */ -function db_version() { - list($version) = explode('-', mysql_get_server_info()); - return $version; -} +// Include schema API shared between mysql, mysqli and pdo_mysql. +require_once './includes/schema.mysql.inc'; /** * Initialize a database connection. */ function db_connect($url) { - $url = parse_url($url); - // Check if MySQL support is present in PHP - if (!function_exists('mysql_connect')) { - _db_error_page('Unable to use the MySQL database because the MySQL extension for PHP is not installed. Check your php.ini to see how you can enable it.'); + if (!(function_exists('mysql_connect') && extension_loaded('mysql'))) { + _db_error_page('Unable to use the MySQL database because the mysql extension for PHP is not installed. Check your php.ini to see how you can enable it.'); } - // Decode url-encoded information in the db connection string - $url['user'] = urldecode($url['user']); - // Test if database url has a password. - $url['pass'] = isset($url['pass']) ? urldecode($url['pass']) : ''; - $url['host'] = urldecode($url['host']); - $url['path'] = urldecode($url['path']); - // Allow for non-standard MySQL port. - if (isset($url['port'])) { - $url['host'] = $url['host'] .':'. $url['port']; + if (isset($url['db_port'])) { + $url['db_host'] = $url['db_host'] .':'. $url['db_port']; } // - TRUE makes mysql_connect() always open a new link, even if @@ -74,22 +37,61 @@ function db_connect($url) { // server. // - 2 means CLIENT_FOUND_ROWS: return the number of found // (matched) rows, not the number of affected rows. - $connection = @mysql_connect($url['host'], $url['user'], $url['pass'], TRUE, 2); - if (!$connection || !mysql_select_db(substr($url['path'], 1))) { + $connection = @mysql_connect($url['db_host'], $url['db_user'], $url['db_pass'], TRUE, 2); + if (!$connection || !mysql_select_db($url['db_name'])) { // Show error screen otherwise _db_error_page(mysql_error()); } + // Require ANSI mode to improve SQL portability. + mysql_query("SET SESSION SQL_MODE = 'ANSI'", $connection); // Force UTF-8. - mysql_query('SET NAMES "utf8"', $connection); + mysql_query('SET NAMES "UTF8"', $connection); return $connection; } /** + * Runs a basic query in the active database. + * + * User-supplied arguments to the query should be passed in as separate + * parameters so that they can be properly escaped to avoid SQL injection + * attacks. + * + * @param $query + * A string containing an SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. Instead of a variable number of query arguments, + * you may also pass a single array containing the query arguments. + * + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query($query) { + $args = func_get_args(); + array_shift($args); + $query = db_prefix_tables($query); + $query = db_escape_quote($query); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + _db_query_callback(array('query' => $query, 'args' => $args), TRUE); + $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); + return _db_query($query); +} + +/** * Helper function for db_query(). */ function _db_query($query, $debug = 0) { - global $active_db, $queries, $user; + global $active_db, $last_result, $queries, $user; if (variable_get('dev_query', 0)) { list($usec, $sec) = explode(' ', microtime()); @@ -105,7 +107,14 @@ function _db_query($query, $debug = 0) { $query = '/* '. $name .' : '. $bt[2]['function'] .' */ '. $query; } - $result = mysql_query($query, $active_db); + // Execute the statement. + $stmt = mysql_query($query, $active_db); + if (mysql_errno($active_db)) { + // Indicate to drupal_error_handler that this is a database error. + ${DB_ERROR} = TRUE; + trigger_error(check_plain(mysql_error($active_db) ."\nquery: ". $query), E_USER_WARNING); + return FALSE; + } if (variable_get('dev_query', 0)) { $query = $bt[2]['function'] ."\n". $query; @@ -119,15 +128,8 @@ function _db_query($query, $debug = 0) { print '

query: '. $query .'
error:'. mysql_error($active_db) .'

'; } - if (!mysql_errno($active_db)) { - return $result; - } - else { - // Indicate to drupal_error_handler that this is a database error. - ${DB_ERROR} = TRUE; - trigger_error(check_plain(mysql_error($active_db) ."\nquery: ". $query), E_USER_WARNING); - return FALSE; - } + $last_result = $stmt; + return $last_result; } /** @@ -141,8 +143,10 @@ function _db_query($query, $debug = 0) { */ function db_fetch_object($result) { if ($result) { - return mysql_fetch_object($result); + $object = mysql_fetch_object($result); + return isset($object) ? $object : FALSE; } + return FALSE; } /** @@ -157,8 +161,10 @@ function db_fetch_object($result) { */ function db_fetch_array($result) { if ($result) { - return mysql_fetch_array($result, MYSQL_ASSOC); + $array = mysql_fetch_array($result, MYSQL_ASSOC); + return isset($array) ? $array : FALSE; } + return FALSE; } /** @@ -177,7 +183,7 @@ function db_result($result) { // The mysql_fetch_row function has an optional second parameter $row // but that can't be used for compatibility with Oracle, DB2, etc. $array = mysql_fetch_row($result); - return $array[0]; + return isset($array[0]) ? $array[0] : FALSE; } return FALSE; } @@ -198,172 +204,66 @@ function db_affected_rows() { return mysql_affected_rows($active_db); } -/** - * Runs a limited-range query in the active database. - * - * Use this as a substitute for db_query() when a subset of the query is to be - * returned. - * User-supplied arguments to the query should be passed in as separate parameters - * so that they can be properly escaped to avoid SQL injection attacks. - * - * @param $query - * A string containing an SQL query. - * @param ... - * A variable number of arguments which are substituted into the query - * using printf() syntax. The query arguments can be enclosed in one - * array instead. - * Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose - * in '') and %%. - * - * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, - * and TRUE values to decimal 1. +/* + * Prepare user input for use in a database query, preventing SQL injection attacks. * - * @param $from - * The first result row to return. - * @param $count - * The maximum number of result rows to return. + * @param $data + * Data to encode. * @return - * A database query result resource, or FALSE if the query was not executed - * correctly. + * Encoded data. */ -function db_query_range($query) { - $args = func_get_args(); - $count = array_pop($args); - $from = array_pop($args); - array_shift($args); - - $query = db_prefix_tables($query); - if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax - $args = $args[0]; - } - _db_query_callback($args, TRUE); - $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); - $query .= ' LIMIT '. (int)$from .', '. (int)$count; - return _db_query($query); +function db_escape_decimal($data) { + return (int) $data; } /** - * Runs a SELECT query and stores its results in a temporary table. - * - * Use this as a substitute for db_query() when the results need to stored - * in a temporary table. Temporary tables exist for the duration of the page - * request. - * User-supplied arguments to the query should be passed in as separate parameters - * so that they can be properly escaped to avoid SQL injection attacks. - * - * Note that if you need to know how many results were returned, you should do - * a SELECT COUNT(*) on the temporary table afterwards. db_affected_rows() does - * not give consistent result across different database types in this case. - * - * @param $query - * A string containing a normal SELECT SQL query. - * @param ... - * A variable number of arguments which are substituted into the query - * using printf() syntax. The query arguments can be enclosed in one - * array instead. - * Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose - * in '') and %%. - * - * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, - * and TRUE values to decimal 1. + * Prepare user input for use in a database query, preventing SQL injection attacks. * - * @param $table - * The name of the temporary table to select into. This name will not be - * prefixed as there is no risk of collision. + * @param $data + * Data to encode. * @return - * A database query result resource, or FALSE if the query was not executed - * correctly. + * Encoded data. */ -function db_query_temporary($query) { - $args = func_get_args(); - $tablename = array_pop($args); - array_shift($args); - - $query = preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE '. $tablename .' Engine=HEAP SELECT', db_prefix_tables($query)); - if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax - $args = $args[0]; - } - _db_query_callback($args, TRUE); - $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); - return _db_query($query); +function db_escape_float($data) { + return (float) $data; } /** - * Returns a properly formatted Binary Large OBject value. + * Prepare user input for use in a database query, preventing SQL injection attacks. * * @param $data * Data to encode. * @return - * Encoded data. + * Encoded data. */ -function db_encode_blob($data) { +function db_escape_string($data) { global $active_db; return "'". mysql_real_escape_string($data, $active_db) ."'"; } /** - * Returns text from a Binary Large Object value. + * Returns a properly formatted Binary Large OBject value. * * @param $data - * Data to decode. + * Data to encode. * @return - * Decoded data. - */ -function db_decode_blob($data) { - return $data; -} - -/** - * Prepare user input for use in a database query, preventing SQL injection attacks. + * Encoded data. */ -function db_escape_string($text) { +function db_encode_blob($data) { global $active_db; - return mysql_real_escape_string($text, $active_db); -} - -/** - * Lock a table. - */ -function db_lock_table($table) { - db_query('LOCK TABLES {'. db_escape_table($table) .'} WRITE'); -} - -/** - * Unlock all locked tables. - */ -function db_unlock_tables() { - db_query('UNLOCK TABLES'); -} - -/** - * Check if a table exists. - */ -function db_table_exists($table) { - return (bool) db_fetch_object(db_query("SHOW TABLES LIKE '{". db_escape_table($table) ."}'")); -} - -/** - * Check if a column exists in the given table. - */ -function db_column_exists($table, $column) { - return (bool) db_fetch_object(db_query("SHOW COLUMNS FROM {". db_escape_table($table) ."} LIKE '". db_escape_table($column) ."'")); + return "'". mysql_real_escape_string($data, $active_db) ."'"; } /** - * Wraps the given table.field entry with a DISTINCT(). The wrapper is added to - * the SELECT list entry of the given query and the resulting query is returned. - * This function only applies the wrapper if a DISTINCT doesn't already exist in - * the query. + * Returns text from a Binary Large OBject value. * - * @param $table Table containing the field to set as DISTINCT - * @param $field Field to set as DISTINCT - * @param $query Query to apply the wrapper to - * @return SQL query with the DISTINCT wrapper surrounding the given table.field. + * @param $data + * Data to decode. + * @return + * Decoded data. */ -function db_distinct_field($table, $field, $query) { - $field_to_select = 'DISTINCT('. $table .'.'. $field .')'; - // (? $t('MySQL database'), - 'value' => ($phase == 'runtime') ? l($version, 'admin/reports/status/sql') : $version, - ); - - if (version_compare($version, DRUPAL_MINIMUM_MYSQL) < 0) { - $form['mysql']['severity'] = REQUIREMENT_ERROR; - $form['mysql']['description'] = $t('Your MySQL Server is too old. Drupal requires at least MySQL %version.', array('%version' => DRUPAL_MINIMUM_MYSQL)); - } - - return $form; -} +// Include schema API shared between mysql, mysqli and pdo_mysql. +require_once './includes/schema.mysql.inc'; /** - * Returns the version of the database server currently in use. - * - * @return Database server version - */ -function db_version() { - global $active_db; - list($version) = explode('-', mysqli_get_server_info($active_db)); - return $version; -} - -/** - * Initialise a database connection. + * Initialize a database connection. * * Note that mysqli does not support persistent connections. */ function db_connect($url) { - // Check if MySQLi support is present in PHP - if (!function_exists('mysqli_init') && !extension_loaded('mysqli')) { - _db_error_page('Unable to use the MySQLi database because the MySQLi extension for PHP is not installed. Check your php.ini to see how you can enable it.'); - } - - $url = parse_url($url); - - // Decode url-encoded information in the db connection string - $url['user'] = urldecode($url['user']); - // Test if database url has a password. - $url['pass'] = isset($url['pass']) ? urldecode($url['pass']) : ''; - $url['host'] = urldecode($url['host']); - $url['path'] = urldecode($url['path']); - if (!isset($url['port'])) { - $url['port'] = NULL; + // Check if MySQL support is present in PHP + if (!(function_exists('mysqli_init') && extension_loaded('mysqli'))) { + _db_error_page('Unable to use the MySQL database because the mysqli extension for PHP is not installed. Check your php.ini to see how you can enable it.'); } $connection = mysqli_init(); - @mysqli_real_connect($connection, $url['host'], $url['user'], $url['pass'], substr($url['path'], 1), $url['port'], NULL, MYSQLI_CLIENT_FOUND_ROWS); + @mysqli_real_connect($connection, $url['db_host'], $url['db_user'], $url['db_pass'], $url['db_name'], $url['db_port'], NULL, MYSQLI_CLIENT_FOUND_ROWS); if (mysqli_connect_errno() > 0) { _db_error_page(mysqli_connect_error()); } + // Require ANSI mode to improve SQL portability. + mysqli_query($connection, "SET SESSION SQL_MODE = 'ANSI'"); // Force UTF-8. - mysqli_query($connection, 'SET NAMES "utf8"'); + mysqli_query($connection, 'SET NAMES "UTF8"'); return $connection; } /** + * Runs a basic query in the active database. + * + * User-supplied arguments to the query should be passed in as separate + * parameters so that they can be properly escaped to avoid SQL injection + * attacks. + * + * @param $query + * A string containing an SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. Instead of a variable number of query arguments, + * you may also pass a single array containing the query arguments. + * + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query($query) { + $args = func_get_args(); + array_shift($args); + $query = db_prefix_tables($query); + $query = db_escape_quote($query); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + _db_query_callback(array('query' => $query, 'args' => $args), TRUE); + $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); + return _db_query($query); +} + +/** * Helper function for db_query(). */ function _db_query($query, $debug = 0) { - global $active_db, $queries, $user; + global $active_db, $last_result, $queries, $user; if (variable_get('dev_query', 0)) { list($usec, $sec) = explode(' ', microtime()); @@ -98,14 +96,21 @@ function _db_query($query, $debug = 0) { // to the SQL string. This is useful when running mysql's SHOW PROCESSLIST to learn what exact // code is issueing the slow query. $bt = debug_backtrace(); - // t() may not be available yet so we don't wrap 'Anonymous' + // t() may not be available yet so we don't wrap 'Anonymous'. $name = $user->uid ? $user->name : variable_get('anonymous', 'Anonymous'); // str_replace() to prevent SQL injection via username or anonymous name. $name = str_replace(array('*', '/'), '', $name); $query = '/* '. $name .' : '. $bt[2]['function'] .' */ '. $query; } - $result = mysqli_query($active_db, $query); + // Execute the statement. + $stmt = mysqli_query($active_db, $query); + if (mysqli_errno($active_db)) { + // Indicate to drupal_error_handler that this is a database error. + ${DB_ERROR} = TRUE; + trigger_error(check_plain(mysqli_error($active_db) ."\nquery: ". $query), E_USER_WARNING); + return FALSE; + } if (variable_get('dev_query', 0)) { $query = $bt[2]['function'] ."\n". $query; @@ -119,15 +124,8 @@ function _db_query($query, $debug = 0) { print '

query: '. $query .'
error:'. mysqli_error($active_db) .'

'; } - if (!mysqli_errno($active_db)) { - return $result; - } - else { - // Indicate to drupal_error_handler that this is a database error. - ${DB_ERROR} = TRUE; - trigger_error(check_plain(mysqli_error($active_db) ."\nquery: ". $query), E_USER_WARNING); - return FALSE; - } + $last_result = $stmt; + return $last_result; } /** @@ -144,6 +142,7 @@ function db_fetch_object($result) { $object = mysqli_fetch_object($result); return isset($object) ? $object : FALSE; } + return FALSE; } /** @@ -161,6 +160,7 @@ function db_fetch_array($result) { $array = mysqli_fetch_array($result, MYSQLI_ASSOC); return isset($array) ? $array : FALSE; } + return FALSE; } /** @@ -179,7 +179,7 @@ function db_result($result) { // The mysqli_fetch_row function has an optional second parameter $row // but that can't be used for compatibility with Oracle, DB2, etc. $array = mysqli_fetch_row($result); - return $array[0]; + return isset($array[0]) ? $array[0] : FALSE; } return FALSE; } @@ -196,179 +196,72 @@ function db_error() { * Determine the number of rows changed by the preceding query. */ function db_affected_rows() { - global $active_db; /* mysqli connection resource */ + global $active_db; return mysqli_affected_rows($active_db); } -/** - * Runs a limited-range query in the active database. - * - * Use this as a substitute for db_query() when a subset of the query is to be - * returned. - * User-supplied arguments to the query should be passed in as separate parameters - * so that they can be properly escaped to avoid SQL injection attacks. - * - * @param $query - * A string containing an SQL query. - * @param ... - * A variable number of arguments which are substituted into the query - * using printf() syntax. The query arguments can be enclosed in one - * array instead. - * Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose - * in '') and %%. - * - * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, - * and TRUE values to decimal 1. +/* + * Prepare user input for use in a database query, preventing SQL injection attacks. * - * @param $from - * The first result row to return. - * @param $count - * The maximum number of result rows to return. + * @param $data + * Data to encode. * @return - * A database query result resource, or FALSE if the query was not executed - * correctly. + * Encoded data. */ -function db_query_range($query) { - $args = func_get_args(); - $count = array_pop($args); - $from = array_pop($args); - array_shift($args); - - $query = db_prefix_tables($query); - if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax - $args = $args[0]; - } - _db_query_callback($args, TRUE); - $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); - $query .= ' LIMIT '. (int)$from .', '. (int)$count; - return _db_query($query); +function db_escape_decimal($data) { + return (int) $data; } /** - * Runs a SELECT query and stores its results in a temporary table. - * - * Use this as a substitute for db_query() when the results need to stored - * in a temporary table. Temporary tables exist for the duration of the page - * request. - * User-supplied arguments to the query should be passed in as separate parameters - * so that they can be properly escaped to avoid SQL injection attacks. - * - * Note that if you need to know how many results were returned, you should do - * a SELECT COUNT(*) on the temporary table afterwards. db_affected_rows() does - * not give consistent result across different database types in this case. - * - * @param $query - * A string containing a normal SELECT SQL query. - * @param ... - * A variable number of arguments which are substituted into the query - * using printf() syntax. The query arguments can be enclosed in one - * array instead. - * Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose - * in '') and %%. - * - * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, - * and TRUE values to decimal 1. + * Prepare user input for use in a database query, preventing SQL injection attacks. * - * @param $table - * The name of the temporary table to select into. This name will not be - * prefixed as there is no risk of collision. + * @param $data + * Data to encode. * @return - * A database query result resource, or FALSE if the query was not executed - * correctly. + * Encoded data. */ -function db_query_temporary($query) { - $args = func_get_args(); - $tablename = array_pop($args); - array_shift($args); - - $query = preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE '. $tablename .' Engine=HEAP SELECT', db_prefix_tables($query)); - if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax - $args = $args[0]; - } - _db_query_callback($args, TRUE); - $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); - return _db_query($query); +function db_escape_float($data) { + return (float) $data; } /** - * Returns a properly formatted Binary Large Object value. + * Prepare user input for use in a database query, preventing SQL injection attacks. * * @param $data * Data to encode. * @return - * Encoded data. + * Encoded data. */ -function db_encode_blob($data) { +function db_escape_string($data) { global $active_db; return "'". mysqli_real_escape_string($active_db, $data) ."'"; } /** - * Returns text from a Binary Large OBject value. + * Returns a properly formatted Binary Large OBject value. * * @param $data - * Data to decode. + * Data to encode. * @return - * Decoded data. + * Encoded data. */ -function db_decode_blob($data) { - return $data; -} - -/** - * Prepare user input for use in a database query, preventing SQL injection attacks. - */ -function db_escape_string($text) { +function db_encode_blob($data) { global $active_db; - return mysqli_real_escape_string($active_db, $text); -} - -/** - * Lock a table. - */ -function db_lock_table($table) { - db_query('LOCK TABLES {'. db_escape_table($table) .'} WRITE'); -} - -/** - * Unlock all locked tables. - */ -function db_unlock_tables() { - db_query('UNLOCK TABLES'); -} - -/** - * Check if a table exists. - */ -function db_table_exists($table) { - return (bool) db_fetch_object(db_query("SHOW TABLES LIKE '{". db_escape_table($table) ."}'")); -} - -/** - * Check if a column exists in the given table. - */ -function db_column_exists($table, $column) { - return (bool) db_fetch_object(db_query("SHOW COLUMNS FROM {". db_escape_table($table) ."} LIKE '". db_escape_table($column) ."'")); + return "'". mysqli_real_escape_string($active_db, $data) ."'"; } /** - * Wraps the given table.field entry with a DISTINCT(). The wrapper is added to - * the SELECT list entry of the given query and the resulting query is returned. - * This function only applies the wrapper if a DISTINCT doesn't already exist in - * the query. + * Returns text from a Binary Large OBject value. * - * @param $table Table containing the field to set as DISTINCT - * @param $field Field to set as DISTINCT - * @param $query Query to apply the wrapper to - * @return SQL query with the DISTINCT wrapper surrounding the given table.field. + * @param $data + * Data to decode. + * @return + * Decoded data. */ -function db_distinct_field($table, $field, $query) { - $field_to_select = 'DISTINCT('. $table .'.'. $field .')'; - // (? $query, 'args' => $args), TRUE); + $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); + $args = _db_query_callback(NULL, TRUE); + return _db_query(array('query' => $query, 'args' => $args)); +} + +/** + * Helper function for db_query(). + */ +function _db_query($query, $debug = 0) { + global $active_db, $last_result, $queries, $user; + + // Expand $query if it is in array format. + $args = array(); + if (is_array($query)) { + $args = $query['args']; + $query = $query['query']; + + // Check if locator exists in query, or else unset it. + foreach ($args as $key => $value) { + if (!is_array($args[$key]) || !isset($args[$key]['locator']) || !strstr($query, $args[$key]['locator'])) { + unset($args[$key]); + } + } + } + + if (variable_get('dev_query', 0)) { + list($usec, $sec) = explode(' ', microtime()); + $timer = (float)$usec + (float)$sec; + // If devel.module query logging is enabled, prepend a comment with the username and calling function + // to the SQL string. This is useful when running mysql's SHOW PROCESSLIST to learn what exact + // code is issueing the slow query. + $bt = debug_backtrace(); + // t() may not be available yet so we don't wrap 'Anonymous'. + $name = $user->uid ? $user->name : variable_get('anonymous', 'Anonymous'); + // str_replace() to prevent SQL injection via username or anonymous name. + $name = str_replace(array('*', '/'), '', $name); + $query = '/* '. $name .' : '. $bt[2]['function'] .' */ '. $query; + } + + $stmt = oci_parse($active_db, $query); + if ($stmt === FALSE) { + // Indicate to drupal_error_handler that this is a database error. + ${DB_ERROR} = TRUE; + $error = oci_error($stmt); + trigger_error(check_plain($error['message'] ."\nquery: ". $query), E_USER_WARNING); + // On error, rollback the transaction. + oci_rollback($active_db); + return FALSE; + } + + if (count($args)) { + foreach ($args as $key => $value) { + if (isset($args[$key]['type']) && $args[$key]['type'] == SQLT_BLOB) { + // Bind the returned Oracle LOB locator to the PHP LOB object. + $args[$key]['obj'] = oci_new_descriptor($active_db, OCI_D_LOB); + oci_bind_by_name($stmt, $args[$key]['locator'], $args[$key]['obj'], -1, $args[$key]['type']); + } + else if (isset($args[$key]['type'])) { + oci_bind_by_name($stmt, $args[$key]['locator'], $args[$key]['data'], -1, $args[$key]['type']); + } + else { + oci_bind_by_name($stmt, $args[$key]['locator'], $args[$key]['data']); + } + } + } + + // Oracle need to preform INSERT/UPDATE under a transcation, otherwise the + // newly inserted LOB will be committed with a zero-length. + // Execute the statement using OCI_DEFAULT (begin a transaction). + $result = oci_execute($stmt, OCI_DEFAULT); + if ($result === FALSE) { + // Indicate to drupal_error_handler that this is a database error. + ${DB_ERROR} = TRUE; + $error = oci_error($stmt); + trigger_error(check_plain($error['message'] ."\nquery: ". $query), E_USER_WARNING); + // On error, rollback the transaction. + oci_rollback($active_db); + return FALSE; + } + + // A LOB Locator tells Oracle where it stashed the actual LOB contents + // without making the table rows overly large, and allows some clever + // optimizations when manipulating LOBs. You can't just conjure up a LOB + // Locator though, so you need to insert a brand new empty LOB into a table + // and then fetch it's locator back out before you can start modifying it. + // Check http://netevil.org/uuid/4365876a-cee9-3009-7726-365876a51802 for more information. + if (count($args)) { + foreach ($args as $key => $value) { + if (isset($args[$key]['type']) && $args[$key]['type'] == SQLT_BLOB) { + // Flush existing data before action. + @$args[$key]['obj']->truncate(); + // Save value into Oracle object. + @$args[$key]['obj']->save($args[$key]['data']); + // Free resources. + @$args[$key]['obj']->free(); + } + } + } + + // On success, commit the transaction. + oci_commit($active_db); + + if (variable_get('dev_query', 0)) { + $query = $bt[2]['function'] ."\n". $query; + list($usec, $sec) = explode(' ', microtime()); + $stop = (float)$usec + (float)$sec; + $diff = $stop - $timer; + $queries[] = array($query, $diff); + } + + if ($debug) { + $error = oci_error($stmt); + print '

query: '. $query .'
error:'. $error['message'] .'

'; + } + + $last_result = $stmt; + return $last_result; +} + +/** + * Fetch one result row from the previous query as an object. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * An object representing the next row of the result, or FALSE. The attributes + * of this object are the table fields selected by the query. + */ +function db_fetch_object($result) { + if ($result) { + if ($object = oci_fetch_object($result)) { + $return = new stdClass(); + foreach ((array) $object as $key => $value) { + $column = $key; + // Preform short-to-long mapping if required. + $column = variable_get('oracle_'. $column, $column); + // Replace empty string placeholder. + $return->$column = $value != ORACLE_EMPTY_STRING_PLACEHOLDER ? $value : ''; + } + return isset($return) ? $return : FALSE; + } + } + return FALSE; +} + +/** + * Fetch one result row from the previous query as an array. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * An associative array representing the next row of the result, or FALSE. + * The keys of this object are the names of the table fields selected by the + * query, and the values are the field values for this result row. + */ +function db_fetch_array($result) { + if ($result) { + if ($array = oci_fetch_assoc($result)) { + $return = array(); + foreach ((array) $array as $key => $value) { + $column = $key; + // Preform short-to-long mapping if required. + $column = variable_get('oracle_'. $column, $column); + // Replace empty string placeholder. + $return[$column] = $value != ORACLE_EMPTY_STRING_PLACEHOLDER ? $value : ''; + } + return isset($return) ? $return : FALSE; + } + } + return FALSE; +} + +/** + * Return an individual result field from the previous query. + * + * Only use this function if exactly one field is being selected; otherwise, + * use db_fetch_object() or db_fetch_array(). + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * The resulting field or FALSE. + */ +function db_result($result) { + if ($result && oci_fetch($result)) { + if ($value = oci_result($result, 1)) { + // Replace empty string placeholder. + $return = $value != ORACLE_EMPTY_STRING_PLACEHOLDER ? $value : ''; + return isset($return) ? $return : FALSE; + } + } + return FALSE; +} + +/** + * Determine whether the previous query caused an error. + */ +function db_error() { + $error = oci_error(); + return $error['message']; +} + +/** + * Determine the number of rows changed by the preceding query. + */ +function db_affected_rows() { + global $last_result; + return oci_num_rows($last_result); +} + +/* + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_decimal(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => (int) $data, + ); + return $locator; +} + +/** + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_float(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => (float) $data, + ); + return $locator; +} + +/** + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_string(&$data, $locator) { + // Replace as empty string placeholder, if not an empty string nor NULL. + $data = ($data !== '' && !is_null($data)) ? $data : ORACLE_EMPTY_STRING_PLACEHOLDER; + // Trim first 4000 characters, based on Oracle VARCHAR2(4000) limitation. + $data = preg_replace('/(.{0,4000})(.*)/', '\1', $data); + + $data = array( + 'locator' => $locator, + 'data' => $data, + 'type' => SQLT_CHR, + ); + return $locator; +} + +/** + * Returns a properly formatted Binary Large OBject value. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_encode_blob(&$data, $locator) { + // Replace as empty string placeholder, if not an empty string nor NULL. + $data = ($data !== '' && !is_null($data)) ? $data : ORACLE_EMPTY_STRING_PLACEHOLDER; + + $data = array( + 'locator' => $locator, + 'data' => $data, + 'type' => SQLT_BLOB, + ); + return $locator; +} + +/** + * Returns text from a Binary Large OBject value. + * + * @param $data + * Data to decode. + * @return + * Decoded data. + */ +function db_decode_blob($data) { + // In case of Oracle LOBs are read via LOB->load(). + return $data->load(); +} + +/** + * @} End of "ingroup database". + */ Index: includes/database.pdo_ibm.inc =================================================================== RCS file: includes/database.pdo_ibm.inc diff -N includes/database.pdo_ibm.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/database.pdo_ibm.inc 31 Mar 2008 17:25:55 -0000 @@ -0,0 +1,344 @@ + PDO::ERRMODE_WARNING, + // Leave column names as returned by the database driver. + PDO::ATTR_CASE => PDO::CASE_NATURAL, + ); + + try { + $connection = new PDO($dsn, $url['db_user'], $url['db_pass'], $driver_options); + } catch (PDOExecption $e) { + _db_error_page($e->getMessage()); + } + + return $connection; +} + +/** + * Runs a basic query in the active database. + * + * User-supplied arguments to the query should be passed in as separate + * parameters so that they can be properly escaped to avoid SQL injection + * attacks. + * + * @param $query + * A string containing an SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. Instead of a variable number of query arguments, + * you may also pass a single array containing the query arguments. + * + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query($query) { + $args = func_get_args(); + array_shift($args); + $query = db_prefix_tables($query); + $query = db_escape_quote($query); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + _db_query_callback(array('query' => $query, 'args' => $args), TRUE); + $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); + $args = _db_query_callback(NULL, TRUE); + return _db_query(array('query' => $query, 'args' => $args)); +} + +/** + * Helper function for db_query(). + */ +function _db_query($query, $debug = 0) { + global $active_db, $last_result, $queries, $user; + + // Expand $query if it is in array format. + $args = array(); + if (is_array($query)) { + $args = $query['args']; + $query = $query['query']; + + // Check if locator exists in query, or else unset it. + foreach ($args as $key => $value) { + if (!is_array($args[$key]) || !isset($args[$key]['locator']) || !strstr($query, $args[$key]['locator'])) { + unset($args[$key]); + } + } + } + + if (variable_get('dev_query', 0)) { + list($usec, $sec) = explode(' ', microtime()); + $timer = (float)$usec + (float)$sec; + // If devel.module query logging is enabled, prepend a comment with the username and calling function + // to the SQL string. This is useful when running mysql's SHOW PROCESSLIST to learn what exact + // code is issueing the slow query. + $bt = debug_backtrace(); + // t() may not be available yet so we don't wrap 'Anonymous'. + $name = $user->uid ? $user->name : variable_get('anonymous', 'Anonymous'); + // str_replace() to prevent SQL injection via username or anonymous name. + $name = str_replace(array('*', '/'), '', $name); + $query = '/* '. $name .' : '. $bt[2]['function'] .' */ '. $query; + } + + $stmt = $active_db->prepare($query); + if ($stmt === FALSE) { + $error = $active_db->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + // Indicate to drupal_error_handler that this is a database error. + ${DB_ERROR} = TRUE; + trigger_error(check_plain($error[2] ."\nquery: ". $query), E_USER_WARNING); + } + return FALSE; + } + + if (count($args)) { + foreach ($args as $key => $value) { + if (isset($args[$key]['type'])) { + $stmt->bindValue($args[$key]['locator'], $args[$key]['data'], $args[$key]['type']); + } + else { + $stmt->bindValue($args[$key]['locator'], $args[$key]['data']); + } + } + } + + // Execute the statement. + $result = $stmt->execute(); + if ($result === FALSE) { + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + // Indicate to drupal_error_handler that this is a database error. + ${DB_ERROR} = TRUE; + trigger_error(check_plain($error[2] ."\nquery: ". $query), E_USER_WARNING); + } + return FALSE; + } + + if (variable_get('dev_query', 0)) { + $query = $bt[2]['function'] ."\n". $query; + list($usec, $sec) = explode(' ', microtime()); + $stop = (float)$usec + (float)$sec; + $diff = $stop - $timer; + $queries[] = array($query, $diff); + } + + if ($debug) { + $error = $active_db->errorInfo(); + print '

query: '. $query .'
error:'. $error[2] .'

'; + } + + $last_result = $stmt; + return $last_result; +} + +/** + * Fetch one result row from the previous query as an object. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * An object representing the next row of the result, or FALSE. The attributes + * of this object are the table fields selected by the query. + */ +function db_fetch_object($result) { + if ($result) { + $object = $result->fetch(PDO::FETCH_OBJ); + return isset($object) ? $object : FALSE; + } + return FALSE; +} + +/** + * Fetch one result row from the previous query as an array. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * An associative array representing the next row of the result, or FALSE. + * The keys of this object are the names of the table fields selected by the + * query, and the values are the field values for this result row. + */ +function db_fetch_array($result) { + if ($result) { + $array = $result->fetch(PDO::FETCH_ASSOC); + return isset($array) ? $array : FALSE; + } + return FALSE; +} + +/** + * Return an individual result field from the previous query. + * + * Only use this function if exactly one field is being selected; otherwise, + * use db_fetch_object() or db_fetch_array(). + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * The resulting field or FALSE. + */ +function db_result($result) { + if ($result) { + $array = $result->fetch(PDO::FETCH_NUM); + return isset($array[0]) ? $array[0] : FALSE; + } + return FALSE; +} + +/** + * Determine whether the previous query caused an error. + */ +function db_error() { + global $last_result; + $error = $last_result->errorInfo(); + if (is_array($error) && isset($error[2])) { + return $error[2]; + } +} + +/** + * Determine the number of rows changed by the preceding query. + */ +function db_affected_rows() { + global $last_result; + return $last_result->rowCount(); +} + +/* + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_decimal(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => (int) $data, + ); + return $locator; +} + +/** + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_float(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => (float) $data, + ); + return $locator; +} + +/** + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_string(&$data, $locator) { + // Trim first 4000 characters, since functions in the SYSFUN schema taking + // a VARCHAR as an argument will not accept VARCHARs greater than 4000 + // bytes long as an argument. + $data = preg_replace('/(.{0,4000})(.*)/', '\1', $data); + + $data = array( + 'locator' => $locator, + 'data' => $data, + 'type' => PDO::PARAM_STR, + ); + return $locator; +} + +/** + * Returns a properly formatted Binary Large OBject value. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_encode_blob(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => $data, + 'type' => PDO::PARAM_LOB, + ); + return $locator; +} + +/** + * Returns text from a Binary Large OBject value. + * + * @param $data + * Data to decode. + * @return + * Decoded data. + */ +function db_decode_blob($data) { + // pdo_ibm return bytea as stream, so we just need to use Streams API. + // Check http://bugs.php.net/bug.php?id=37124 for more information. + return stream_get_contents($data); +} + +/** + * @} End of "ingroup database". + */ Index: includes/database.pdo_mysql.inc =================================================================== RCS file: includes/database.pdo_mysql.inc diff -N includes/database.pdo_mysql.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/database.pdo_mysql.inc 31 Mar 2008 17:25:56 -0000 @@ -0,0 +1,346 @@ + PDO::ERRMODE_WARNING, + // Leave column names as returned by the database driver. + PDO::ATTR_CASE => PDO::CASE_NATURAL, + // Force MySQL driver will use the buffered versions of the MySQL API. + PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => TRUE, + ); + + try { + $connection = new PDO($dsn, $url['db_user'], $url['db_pass'], $driver_options); + } catch (PDOExecption $e) { + _db_error_page($e->getMessage()); + } + + // Require ANSI mode to improve SQL portability. + $stmt = $connection->exec("SET SESSION SQL_MODE = 'ANSI'"); + // Force UTF-8 + $stmt = $connection->exec('SET NAMES "UTF8"'); + + // Force MySQL driver will use the buffered versions of the MySQL API. + $connection->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, TRUE); + + return $connection; +} + +/** + * Runs a basic query in the active database. + * + * User-supplied arguments to the query should be passed in as separate + * parameters so that they can be properly escaped to avoid SQL injection + * attacks. + * + * @param $query + * A string containing an SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. Instead of a variable number of query arguments, + * you may also pass a single array containing the query arguments. + * + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query($query) { + $args = func_get_args(); + array_shift($args); + $query = db_prefix_tables($query); + $query = db_escape_quote($query); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + _db_query_callback(array('query' => $query, 'args' => $args), TRUE); + $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); + $args = _db_query_callback(NULL, TRUE); + return _db_query(array('query' => $query, 'args' => $args)); +} + +/** + * Helper function for db_query(). + */ +function _db_query($query, $debug = 0) { + global $active_db, $last_result, $queries, $user; + + // Expand $query if it is in array format. + $args = array(); + if (is_array($query)) { + $args = $query['args']; + $query = $query['query']; + + // Check if locator exists in query, or else unset it. + foreach ($args as $key => $value) { + if (!is_array($args[$key]) || !isset($args[$key]['locator']) || !strstr($query, $args[$key]['locator'])) { + unset($args[$key]); + } + } + } + + if (variable_get('dev_query', 0)) { + list($usec, $sec) = explode(' ', microtime()); + $timer = (float)$usec + (float)$sec; + // If devel.module query logging is enabled, prepend a comment with the username and calling function + // to the SQL string. This is useful when running mysql's SHOW PROCESSLIST to learn what exact + // code is issueing the slow query. + $bt = debug_backtrace(); + // t() may not be available yet so we don't wrap 'Anonymous'. + $name = $user->uid ? $user->name : variable_get('anonymous', 'Anonymous'); + // str_replace() to prevent SQL injection via username or anonymous name. + $name = str_replace(array('*', '/'), '', $name); + $query = '/* '. $name .' : '. $bt[2]['function'] .' */ '. $query; + } + + $stmt = $active_db->prepare($query); + if ($stmt === FALSE) { + $error = $active_db->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + // Indicate to drupal_error_handler that this is a database error. + ${DB_ERROR} = TRUE; + trigger_error(check_plain($error[2] ."\nquery: ". $query), E_USER_WARNING); + } + return FALSE; + } + + if (count($args)) { + foreach ($args as $key => $value) { + if (isset($args[$key]['type'])) { + $stmt->bindValue($args[$key]['locator'], $args[$key]['data'], $args[$key]['type']); + } + else { + $stmt->bindValue($args[$key]['locator'], $args[$key]['data']); + } + } + } + + // Execute the statement. + $result = $stmt->execute(); + if ($result === FALSE) { + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + // Indicate to drupal_error_handler that this is a database error. + ${DB_ERROR} = TRUE; + trigger_error(check_plain($error[2] ."\nquery: ". $query), E_USER_WARNING); + } + return FALSE; + } + + if (variable_get('dev_query', 0)) { + $query = $bt[2]['function'] ."\n". $query; + list($usec, $sec) = explode(' ', microtime()); + $stop = (float)$usec + (float)$sec; + $diff = $stop - $timer; + $queries[] = array($query, $diff); + } + + if ($debug) { + $error = $active_db->errorInfo(); + print '

query: '. $query .'
error:'. $error[2] .'

'; + } + + $last_result = $stmt; + return $last_result; +} + +/** + * Fetch one result row from the previous query as an object. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * An object representing the next row of the result, or FALSE. The attributes + * of this object are the table fields selected by the query. + */ +function db_fetch_object($result) { + if ($result) { + $object = $result->fetch(PDO::FETCH_OBJ); + return isset($object) ? $object : FALSE; + } + return FALSE; +} + +/** + * Fetch one result row from the previous query as an array. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * An associative array representing the next row of the result, or FALSE. + * The keys of this object are the names of the table fields selected by the + * query, and the values are the field values for this result row. + */ +function db_fetch_array($result) { + if ($result) { + $array = $result->fetch(PDO::FETCH_ASSOC); + return isset($array) ? $array : FALSE; + } + return FALSE; +} + +/** + * Return an individual result field from the previous query. + * + * Only use this function if exactly one field is being selected; otherwise, + * use db_fetch_object() or db_fetch_array(). + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * The resulting field or FALSE. + */ +function db_result($result) { + if ($result) { + $array = $result->fetch(PDO::FETCH_NUM); + return isset($array[0]) ? $array[0] : FALSE; + } + return FALSE; +} + +/** + * Determine whether the previous query caused an error. + */ +function db_error() { + global $last_result; + $error = $last_result->errorInfo(); + if (is_array($error) && isset($error[2])) { + return $error[2]; + } +} + +/** + * Determine the number of rows changed by the preceding query. + */ +function db_affected_rows() { + global $last_result; + return $last_result->rowCount(); +} + +/* + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_decimal(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => (int) $data, + ); + return $locator; +} + +/** + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_float(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => (float) $data, + ); + return $locator; +} + +/** + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_string(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => $data, + 'type' => PDO::PARAM_STR, + ); + return $locator; +} + +/** + * Returns a properly formatted Binary Large OBject value. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_encode_blob(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => $data, + 'type' => PDO::PARAM_LOB, + ); + return $locator; +} + +/** + * Returns text from a Binary Large OBject value. + * + * @param $data + * Data to decode. + * @return + * Decoded data. + */ +function db_decode_blob($data) { + return $data; +} + +/** + * @} End of "ingroup database". + */ Index: includes/database.pdo_oci.inc =================================================================== RCS file: includes/database.pdo_oci.inc diff -N includes/database.pdo_oci.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/database.pdo_oci.inc 31 Mar 2008 17:25:56 -0000 @@ -0,0 +1,404 @@ + PDO::ERRMODE_WARNING, + // Leave column names as returned by the database driver. + PDO::ATTR_CASE => PDO::CASE_NATURAL, + // Disable autocommit so that the connection begins a transaction. + PDO::ATTR_AUTOCOMMIT => FALSE, + ); + + try { + $connection = new PDO($dsn, $url['db_user'], $url['db_pass'], $driver_options); + } catch (PDOExecption $e) { + _db_error_page($e->getMessage()); + } + + return $connection; +} + +/** + * Runs a basic query in the active database. + * + * User-supplied arguments to the query should be passed in as separate + * parameters so that they can be properly escaped to avoid SQL injection + * attacks. + * + * @param $query + * A string containing an SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. Instead of a variable number of query arguments, + * you may also pass a single array containing the query arguments. + * + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query($query) { + $args = func_get_args(); + array_shift($args); + $query = db_prefix_tables($query); + $query = db_escape_quote($query); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + _db_query_callback(array('query' => $query, 'args' => $args), TRUE); + $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); + $args = _db_query_callback(NULL, TRUE); + return _db_query(array('query' => $query, 'args' => $args)); +} + +/** + * Helper function for db_query(). + */ +function _db_query($query, $debug = 0) { + global $active_db, $last_result, $queries, $user; + + // Expand $query if it is in array format. + $args = array(); + if (is_array($query)) { + $args = $query['args']; + $query = $query['query']; + + // Check if locator exists in query, or else unset it. + foreach ($args as $key => $value) { + if (!is_array($args[$key]) || !isset($args[$key]['locator']) || !strstr($query, $args[$key]['locator'])) { + unset($args[$key]); + } + } + } + + if (variable_get('dev_query', 0)) { + list($usec, $sec) = explode(' ', microtime()); + $timer = (float)$usec + (float)$sec; + // If devel.module query logging is enabled, prepend a comment with the username and calling function + // to the SQL string. This is useful when running mysql's SHOW PROCESSLIST to learn what exact + // code is issueing the slow query. + $bt = debug_backtrace(); + // t() may not be available yet so we don't wrap 'Anonymous'. + $name = $user->uid ? $user->name : variable_get('anonymous', 'Anonymous'); + // str_replace() to prevent SQL injection via username or anonymous name. + $name = str_replace(array('*', '/'), '', $name); + $query = '/* '. $name .' : '. $bt[2]['function'] .' */ '. $query; + } + + $stmt = $active_db->prepare($query); + if ($stmt === FALSE) { + $error = $active_db->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + // Indicate to drupal_error_handler that this is a database error. + ${DB_ERROR} = TRUE; + trigger_error(check_plain($error[2] ."\nquery: ". $query), E_USER_WARNING); + } + $active_db->rollBack(); + return FALSE; + } + + if (count($args)) { + foreach ($args as $key => $value) { + if (isset($args[$key]['type']) && $args[$key]['type'] == PDO::PARAM_LOB) { + // Bind the returned Oracle LOB locator to the PHP file handler. + // Use PDOStatement->bindParam() here for stream I/O handling. + $stmt->bindParam($args[$key]['locator'], $args[$key]['obj'], $args[$key]['type']); + $args[$key]['obj'] = NULL; + } + else if (isset($args[$key]['type'])) { + $stmt->bindValue($args[$key]['locator'], $args[$key]['data'], $args[$key]['type']); + } + else { + $stmt->bindValue($args[$key]['locator'], $args[$key]['data']); + } + } + } + + // Oracle need to preform INSERT/UPDATE under a transcation, otherwise the + // newly inserted LOB will be committed with a zero-length. + // Check http://php.net/pdo#pdo.lobs for more information. + $active_db->beginTransaction(); + + // Execute the statement. + $result = $stmt->execute(); + if ($result === FALSE) { + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + // Indicate to drupal_error_handler that this is a database error. + ${DB_ERROR} = TRUE; + trigger_error(check_plain($error[2] ."\nquery: ". $query), E_USER_WARNING); + } + $active_db->rollBack(); + return FALSE; + } + + // A LOB Locator tells Oracle where it stashed the actual LOB contents + // without making the table rows overly large, and allows some clever + // optimizations when manipulating LOBs. You can't just conjure up a LOB + // Locator though, so you need to insert a brand new empty LOB into a table + // and then fetch it's locator back out before you can start modifying it. + // Check http://netevil.org/uuid/4365876a-cee9-3009-7726-365876a51802 for more information. + if (count($args)) { + foreach ($args as $key => $value) { + if (isset($args[$key]['type']) && $args[$key]['type'] == PDO::PARAM_LOB) { + // Flush existing data before action. + fflush($args[$key]['obj']); + // Save value into INPUT/OUTPUT BLOB handler. + fwrite($args[$key]['obj'], $args[$key]['data']); + // Free resources. + fclose($args[$key]['obj']); + } + } + } + + // On success, commit the transaction. + $active_db->commit(); + + if (variable_get('dev_query', 0)) { + $query = $bt[2]['function'] ."\n". $query; + list($usec, $sec) = explode(' ', microtime()); + $stop = (float)$usec + (float)$sec; + $diff = $stop - $timer; + $queries[] = array($query, $diff); + } + + if ($debug) { + $error = $active_db->errorInfo(); + print '

query: '. $query .'
error:'. $error[2] .'

'; + } + + $last_result = $stmt; + return $last_result; +} + +/** + * Fetch one result row from the previous query as an object. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * An object representing the next row of the result, or FALSE. The attributes + * of this object are the table fields selected by the query. + */ +function db_fetch_object($result) { + if ($result) { + if ($object = $result->fetch(PDO::FETCH_OBJ)) { + $return = new stdClass(); + foreach ((array) $object as $key => $value) { + $column = $key; + // Preform short-to-long mapping if required. + $column = variable_get('oracle_'. $column, $column); + // Replace empty string placeholder. + $return->$column = $value != ORACLE_EMPTY_STRING_PLACEHOLDER ? $value : ''; + } + return isset($return) ? $return : FALSE; + } + } + return FALSE; +} + +/** + * Fetch one result row from the previous query as an array. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * An associative array representing the next row of the result, or FALSE. + * The keys of this object are the names of the table fields selected by the + * query, and the values are the field values for this result row. + */ +function db_fetch_array($result) { + if ($result) { + if ($array = $result->fetch(PDO::FETCH_ASSOC)) { + $return = array(); + foreach ((array) $array as $key => $value) { + $column = $key; + // Preform short-to-long mapping if required. + $column = variable_get('oracle_'. $column, $column); + // Replace empty string placeholder. + $return[$column] = $value != ORACLE_EMPTY_STRING_PLACEHOLDER ? $value : ''; + } + return isset($return) ? $return : FALSE; + } + } + return FALSE; +} + +/** + * Return an individual result field from the previous query. + * + * Only use this function if exactly one field is being selected; otherwise, + * use db_fetch_object() or db_fetch_array(). + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * The resulting field or FALSE. + */ +function db_result($result) { + if ($result) { + if ($array = $result->fetch(PDO::FETCH_NUM)) { + // Replace empty string placeholder. + $return = $array[0] != ORACLE_EMPTY_STRING_PLACEHOLDER ? $array[0] : ''; + return isset($return) ? $return : FALSE; + } + } + return FALSE; +} + +/** + * Determine whether the previous query caused an error. + */ +function db_error() { + global $last_result; + $error = $last_result->errorInfo(); + if (is_array($error) && isset($error[2])) { + return $error[2]; + } +} + +/** + * Determine the number of rows changed by the preceding query. + */ +function db_affected_rows() { + global $last_result; + return $last_result->rowCount(); +} + +/* + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_decimal(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => (int) $data, + ); + return $locator; +} + +/** + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_float(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => (float) $data, + ); + return $locator; +} + +/** + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_string(&$data, $locator) { + // Replace as empty string placeholder, if not an empty string nor NULL. + $data = ($data !== '' && !is_null($data)) ? $data : ORACLE_EMPTY_STRING_PLACEHOLDER; + // Trim first 4000 characters, based on Oracle VARCHAR2(4000) limitation. + $data = preg_replace('/(.{0,4000})(.*)/', '\1', $data); + + $data = array( + 'locator' => $locator, + 'data' => $data, + 'type' => PDO::PARAM_STR, + ); + return $locator; +} + +/** + * Returns a properly formatted Binary Large OBject value. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_encode_blob(&$data, $locator) { + // Replace as empty string placeholder, if not an empty string nor NULL. + $data = ($data !== '' && !is_null($data)) ? $data : ORACLE_EMPTY_STRING_PLACEHOLDER; + + $data = array( + 'locator' => $locator, + 'data' => $data, + 'type' => PDO::PARAM_LOB, + ); + return $locator; +} + +/** + * Returns text from a Binary Large OBject value. + * + * @param $data + * Data to decode. + * @return + * Decoded data. + */ +function db_decode_blob($data) { + // pdo_oci return bytea as stream, so we just need to use Streams API. + // Check http://bugs.php.net/bug.php?id=37124 for more information. + return stream_get_contents($data); +} + +/** + * @} End of "ingroup database". + */ Index: includes/database.pdo_pgsql.inc =================================================================== RCS file: includes/database.pdo_pgsql.inc diff -N includes/database.pdo_pgsql.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/database.pdo_pgsql.inc 31 Mar 2008 17:25:57 -0000 @@ -0,0 +1,341 @@ + PDO::ERRMODE_WARNING, + // Leave column names as returned by the database driver. + PDO::ATTR_CASE => PDO::CASE_NATURAL, + ); + + try { + $connection = new PDO($dsn, $url['db_user'], $url['db_pass'], $driver_options); + } catch (PDOExecption $e) { + _db_error_page($e->getMessage()); + } + + return $connection; +} + +/** + * Runs a basic query in the active database. + * + * User-supplied arguments to the query should be passed in as separate + * parameters so that they can be properly escaped to avoid SQL injection + * attacks. + * + * @param $query + * A string containing an SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. Instead of a variable number of query arguments, + * you may also pass a single array containing the query arguments. + * + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query($query) { + $args = func_get_args(); + array_shift($args); + $query = db_prefix_tables($query); + $query = db_escape_quote($query); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + _db_query_callback(array('query' => $query, 'args' => $args), TRUE); + $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); + $args = _db_query_callback(NULL, TRUE); + return _db_query(array('query' => $query, 'args' => $args)); +} + +/** + * Helper function for db_query(). + */ +function _db_query($query, $debug = 0) { + global $active_db, $last_result, $queries, $user; + + // Expand $query if it is in array format. + $args = array(); + if (is_array($query)) { + $args = $query['args']; + $query = $query['query']; + + // Check if locator exists in query, or else unset it. + foreach ($args as $key => $value) { + if (!is_array($args[$key]) || !isset($args[$key]['locator']) || !strstr($query, $args[$key]['locator'])) { + unset($args[$key]); + } + } + } + + if (variable_get('dev_query', 0)) { + list($usec, $sec) = explode(' ', microtime()); + $timer = (float)$usec + (float)$sec; + // If devel.module query logging is enabled, prepend a comment with the username and calling function + // to the SQL string. This is useful when running mysql's SHOW PROCESSLIST to learn what exact + // code is issueing the slow query. + $bt = debug_backtrace(); + // t() may not be available yet so we don't wrap 'Anonymous'. + $name = $user->uid ? $user->name : variable_get('anonymous', 'Anonymous'); + // str_replace() to prevent SQL injection via username or anonymous name. + $name = str_replace(array('*', '/'), '', $name); + $query = '/* '. $name .' : '. $bt[2]['function'] .' */ '. $query; + } + + $stmt = $active_db->prepare($query); + if ($stmt === FALSE) { + $error = $active_db->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + // Indicate to drupal_error_handler that this is a database error. + ${DB_ERROR} = TRUE; + trigger_error(check_plain($error[2] ."\nquery: ". $query), E_USER_WARNING); + } + return FALSE; + } + + if (count($args)) { + foreach ($args as $key => $value) { + if (isset($args[$key]['type'])) { + $stmt->bindValue($args[$key]['locator'], $args[$key]['data'], $args[$key]['type']); + } + else { + $stmt->bindValue($args[$key]['locator'], $args[$key]['data']); + } + } + } + + // Execute the statement. + $result = $stmt->execute(); + if ($result === FALSE) { + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + // Indicate to drupal_error_handler that this is a database error. + ${DB_ERROR} = TRUE; + trigger_error(check_plain($error[2] ."\nquery: ". $query), E_USER_WARNING); + } + return FALSE; + } + + if (variable_get('dev_query', 0)) { + $query = $bt[2]['function'] ."\n". $query; + list($usec, $sec) = explode(' ', microtime()); + $stop = (float)$usec + (float)$sec; + $diff = $stop - $timer; + $queries[] = array($query, $diff); + } + + if ($debug) { + $error = $active_db->errorInfo(); + print '

query: '. $query .'
error:'. $error[2] .'

'; + } + + $last_result = $stmt; + return $last_result; +} + +/** + * Fetch one result row from the previous query as an object. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * An object representing the next row of the result, or FALSE. The attributes + * of this object are the table fields selected by the query. + */ +function db_fetch_object($result) { + if ($result) { + $object = $result->fetch(PDO::FETCH_OBJ); + return isset($object) ? $object : FALSE; + } + return FALSE; +} + +/** + * Fetch one result row from the previous query as an array. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * An associative array representing the next row of the result, or FALSE. + * The keys of this object are the names of the table fields selected by the + * query, and the values are the field values for this result row. + */ +function db_fetch_array($result) { + if ($result) { + $array = $result->fetch(PDO::FETCH_ASSOC); + return isset($array) ? $array : FALSE; + } + return FALSE; +} + +/** + * Return an individual result field from the previous query. + * + * Only use this function if exactly one field is being selected; otherwise, + * use db_fetch_object() or db_fetch_array(). + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * The resulting field or FALSE. + */ +function db_result($result) { + if ($result) { + $array = $result->fetch(PDO::FETCH_NUM); + return isset($array[0]) ? $array[0] : FALSE; + } + return FALSE; +} + +/** + * Determine whether the previous query caused an error. + */ +function db_error() { + global $last_result; + $error = $last_result->errorInfo(); + if (is_array($error) && isset($error[2])) { + return $error[2]; + } +} + +/** + * Determine the number of rows changed by the preceding query. + */ +function db_affected_rows() { + global $last_result; + return $last_result->rowCount(); +} + +/* + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_decimal(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => (int) $data, + ); + return $locator; +} + +/** + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_float(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => (float) $data, + ); + return $locator; +} + +/** + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_string(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => $data, + 'type' => PDO::PARAM_STR, + ); + return $locator; +} + +/** + * Returns a properly formatted Binary Large OBject value. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_encode_blob(&$data, $locator) { + // LOB for PgSQL must define by PDO::PARAM_LOB, or else will case error + // during INSER/UPDATE. So we need to use Oracle style locator-data-type + // variable binding for pdo_pgsql. + $data = array( + 'locator' => $locator, + 'data' => $data, + 'type' => PDO::PARAM_LOB, + ); + return $locator; +} + +/** + * Returns text from a Binary Large OBject value. + * + * @param $data + * Data to decode. + * @return + * Decoded data. + */ +function db_decode_blob($data) { + // pdo_pgsql return bytea as stream, so we just need to use Streams API. + // Check http://bugs.php.net/bug.php?id=37124 for more information. + return stream_get_contents($data); +} + +/** + * @} End of "ingroup database". + */ Index: includes/database.pdo_sqlite.inc =================================================================== RCS file: includes/database.pdo_sqlite.inc diff -N includes/database.pdo_sqlite.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/database.pdo_sqlite.inc 31 Mar 2008 17:25:57 -0000 @@ -0,0 +1,342 @@ + PDO::ERRMODE_WARNING, + // Leave column names as returned by the database driver. + PDO::ATTR_CASE => PDO::CASE_NATURAL, + ); + + try { + $connection = new PDO($dsn, $username, $password, $driver_options); + } catch (PDOExecption $e) { + _db_error_page($e->getMessage()); + } + + // Modify the operation of the SQLite library + $connection->exec('PRAGMA SYNCHRONOUS = OFF'); + $connection->exec('PRAGMA SHORT_COLUMN_NAMES = 1'); + $connection->exec('PRAGMA TEMP_STORE = MEMORY'); + $connection->exec('PRAGMA CACHE_SIZE = 5120'); + $connection->exec('PRAGMA COUNT_CHANGES = OFF'); + $connection->exec('PRAGMA ENCODING = "UTF-8"'); + + return $connection; +} + +/** + * Runs a basic query in the active database. + * + * User-supplied arguments to the query should be passed in as separate + * parameters so that they can be properly escaped to avoid SQL injection + * attacks. + * + * @param $query + * A string containing an SQL query. + * @param ... + * A variable number of arguments which are substituted into the query + * using printf() syntax. Instead of a variable number of query arguments, + * you may also pass a single array containing the query arguments. + * + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). + * + * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, + * and TRUE values to decimal 1. + * + * @return + * A database query result resource, or FALSE if the query was not + * executed correctly. + */ +function db_query($query) { + $args = func_get_args(); + array_shift($args); + _debug_query($query); + $query = db_prefix_tables($query); + $query = db_escape_quote($query); + if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax + $args = $args[0]; + } + _db_query_callback(array('query' => $query, 'args' => $args), TRUE); + $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); + $args = _db_query_callback(NULL, TRUE); + return _db_query(array('query' => $query, 'args' => $args)); +} + +/** + * Helper function for db_query(). + */ +function _db_query($query, $debug = 0) { + global $active_db, $last_result, $queries, $user; + + // Expand $query if it is in array format. + $args = array(); + if (is_array($query)) { + $args = $query['args']; + $query = $query['query']; + + // Check if locator exists in query, or else unset it. + foreach ($args as $key => $value) { + if (!is_array($args[$key]) || !isset($args[$key]['locator']) || !strstr($query, $args[$key]['locator'])) { + unset($args[$key]); + } + } + } + + if (variable_get('dev_query', 0)) { + list($usec, $sec) = explode(' ', microtime()); + $timer = (float)$usec + (float)$sec; + // If devel.module query logging is enabled, prepend a comment with the username and calling function + // to the SQL string. This is useful when running mysql's SHOW PROCESSLIST to learn what exact + // code is issueing the slow query. + $bt = debug_backtrace(); + // t() may not be available yet so we don't wrap 'Anonymous'. + $name = $user->uid ? $user->name : variable_get('anonymous', 'Anonymous'); + // str_replace() to prevent SQL injection via username or anonymous name. + $name = str_replace(array('*', '/'), '', $name); + $query = '/* '. $name .' : '. $bt[2]['function'] .' */ '. $query; + } + + $stmt = $active_db->prepare($query); + if ($stmt === FALSE) { + $error = $active_db->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + // Indicate to drupal_error_handler that this is a database error. + ${DB_ERROR} = TRUE; + trigger_error(check_plain($error[2] ."\nquery: ". $query), E_USER_WARNING); + } + return FALSE; + } + + if (count($args)) { + foreach ($args as $key => $value) { + if (isset($args[$key]['type'])) { + $stmt->bindValue($args[$key]['locator'], $args[$key]['data'], $args[$key]['type']); + } + else { + $stmt->bindValue($args[$key]['locator'], $args[$key]['data']); + } + } + } + + // Execute the statement. + $result = $stmt->execute(); + if ($result === FALSE) { + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + // Indicate to drupal_error_handler that this is a database error. + ${DB_ERROR} = TRUE; + trigger_error(check_plain($error[2] ."\nquery: ". $query), E_USER_WARNING); + } + return FALSE; + } + + if (variable_get('dev_query', 0)) { + $query = $bt[2]['function'] ."\n". $query; + list($usec, $sec) = explode(' ', microtime()); + $stop = (float)$usec + (float)$sec; + $diff = $stop - $timer; + $queries[] = array($query, $diff); + } + + if ($debug) { + $error = $active_db->errorInfo(); + print '

query: '. $query .'
error:'. $error[2] .'

'; + } + + $last_result = $stmt; + return $last_result; +} + +/** + * Fetch one result row from the previous query as an object. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * An object representing the next row of the result, or FALSE. The attributes + * of this object are the table fields selected by the query. + */ +function db_fetch_object($result) { + if ($result) { + $object = $result->fetch(PDO::FETCH_OBJ); + return isset($object) ? $object : FALSE; + } + return FALSE; +} + +/** + * Fetch one result row from the previous query as an array. + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * An associative array representing the next row of the result, or FALSE. + * The keys of this object are the names of the table fields selected by the + * query, and the values are the field values for this result row. + */ +function db_fetch_array($result) { + if ($result) { + $array = $result->fetch(PDO::FETCH_ASSOC); + return isset($array) ? $array : FALSE; + } + return FALSE; +} + +/** + * Return an individual result field from the previous query. + * + * Only use this function if exactly one field is being selected; otherwise, + * use db_fetch_object() or db_fetch_array(). + * + * @param $result + * A database query result resource, as returned from db_query(). + * @return + * The resulting field or FALSE. + */ +function db_result($result) { + if ($result) { + $array = $result->fetch(PDO::FETCH_NUM); + return isset($array[0]) ? $array[0] : FALSE; + } + return FALSE; +} + +/** + * Determine whether the previous query caused an error. + */ +function db_error() { + global $last_result; + $error = $last_result->errorInfo(); + if (is_array($error) && isset($error[2])) { + return $error[2]; + } +} + +/** + * Determine the number of rows changed by the preceding query. + */ +function db_affected_rows() { + global $last_result; + return $last_result->rowCount(); +} + +/* + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_decimal(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => (int) $data, + ); + return $locator; +} + +/** + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_float(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => (float) $data, + ); + return $locator; +} + +/** + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_escape_string(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => $data, + 'type' => PDO::PARAM_STR, + ); + return $locator; +} + +/** + * Returns a properly formatted Binary Large OBject value. + * + * @param $data + * Data to encode. Return with processed array pattern for variable binding. + * @param $locator + * Locator for variable binding. + * @return + * Locator for variable binding. + */ +function db_encode_blob(&$data, $locator) { + $data = array( + 'locator' => $locator, + 'data' => $data, + 'type' => PDO::PARAM_LOB, + ); + return $locator; +} + +/** + * Returns text from a Binary Large OBject value. + * + * @param $data + * Data to decode. + * @return + * Decoded data. + */ +function db_decode_blob($data) { + return $data; +} + +/** + * @} End of "ingroup database". + */ Index: includes/database.pgsql.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/database.pgsql.inc,v retrieving revision 1.68.2.1 diff -u -p -r1.68.2.1 database.pgsql.inc --- includes/database.pgsql.inc 7 Feb 2008 10:17:26 -0000 1.68.2.1 +++ includes/database.pgsql.inc 31 Mar 2008 17:25:58 -0000 @@ -11,64 +11,29 @@ * @{ */ -/** - * Report database status. - */ -function db_status_report() { - $t = get_t(); - - $version = db_version(); +// Include functions shared between pgsql and pdo_pgsql. +require_once './includes/common.postgresql.inc'; - $form['pgsql'] = array( - 'title' => $t('PostgreSQL database'), - 'value' => $version, - ); - - if (version_compare($version, DRUPAL_MINIMUM_PGSQL) < 0) { - $form['pgsql']['severity'] = REQUIREMENT_ERROR; - $form['pgsql']['description'] = $t('Your PostgreSQL Server is too old. Drupal requires at least PostgreSQL %version.', array('%version' => DRUPAL_MINIMUM_PGSQL)); - } - - return $form; -} - -/** - * Returns the version of the database server currently in use. - * - * @return Database server version - */ -function db_version() { - return db_result(db_query("SHOW SERVER_VERSION")); -} +// Include schema API shared between pgsql and pdo_pgsql. +require_once './includes/schema.postgresql.inc'; /** * Initialize a database connection. */ function db_connect($url) { // Check if PostgreSQL support is present in PHP - if (!function_exists('pg_connect')) { - _db_error_page('Unable to use the PostgreSQL database because the PostgreSQL extension for PHP is not installed. Check your php.ini to see how you can enable it.'); + if (!(function_exists('pg_connect') && extension_loaded('pgsql'))) { + _db_error_page('Unable to use the PostgreSQL database because the pgsql extension for PHP is not installed. Check your php.ini to see how you can enable it.'); } - $url = parse_url($url); - $conn_string = ''; - // Decode url-encoded information in the db connection string - if (isset($url['user'])) { - $conn_string .= ' user='. urldecode($url['user']); - } - if (isset($url['pass'])) { - $conn_string .= ' password='. urldecode($url['pass']); - } - if (isset($url['host'])) { - $conn_string .= ' host='. urldecode($url['host']); - } - if (isset($url['path'])) { - $conn_string .= ' dbname='. substr(urldecode($url['path']), 1); - } - if (isset($url['port'])) { - $conn_string .= ' port='. urldecode($url['port']); - } + $conn_string[] = isset($url['db_host']) ? 'host='. $url['db_host'] : NULL; + $conn_string[] = isset($url['db_port']) ? 'port='. $url['db_port'] : NULL; + $conn_string[] = isset($url['db_name']) ? 'dbname='. $url['db_name'] : NULL; + $conn_string[] = isset($url['db_user']) ? 'user='. $url['db_user'] : NULL; + $conn_string[] = isset($url['db_pass']) ? 'password='. $url['db_pass'] : NULL; + + $conn_string = implode(' ', array_filter($conn_string)); // pg_last_error() does not return a useful error message for database // connection errors. We must turn on error tracking to get at a good error @@ -102,8 +67,8 @@ function db_connect($url) { * using printf() syntax. Instead of a variable number of query arguments, * you may also pass a single array containing the query arguments. * - * Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose - * in '') and %%. + * Valid %-modifiers are: %s, %d, %f and %b (binary data, do not enclose + * in ''). * * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, * and TRUE values to decimal 1. @@ -116,10 +81,11 @@ function db_query($query) { $args = func_get_args(); array_shift($args); $query = db_prefix_tables($query); + $query = db_escape_quote($query); if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax $args = $args[0]; } - _db_query_callback($args, TRUE); + _db_query_callback(array('query' => $query, 'args' => $args), TRUE); $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); return _db_query($query); } @@ -128,17 +94,31 @@ function db_query($query) { * Helper function for db_query(). */ function _db_query($query, $debug = 0) { - global $active_db, $last_result, $queries; + global $active_db, $last_result, $queries, $user; if (variable_get('dev_query', 0)) { list($usec, $sec) = explode(' ', microtime()); $timer = (float)$usec + (float)$sec; + // If devel.module query logging is enabled, prepend a comment with the username and calling function + // to the SQL string. This is useful when running mysql's SHOW PROCESSLIST to learn what exact + // code is issueing the slow query. + $bt = debug_backtrace(); + // t() may not be available yet so we don't wrap 'Anonymous'. + $name = $user->uid ? $user->name : variable_get('anonymous', 'Anonymous'); + // str_replace() to prevent SQL injection via username or anonymous name. + $name = str_replace(array('*', '/'), '', $name); + $query = '/* '. $name .' : '. $bt[2]['function'] .' */ '. $query; } - $last_result = pg_query($active_db, $query); + $stmt = pg_query($active_db, $query); + if ($stmt === FALSE) { + // Indicate to drupal_error_handler that this is a database error. + ${DB_ERROR} = TRUE; + trigger_error(check_plain(pg_last_error($active_db) ."\nquery: ". $query), E_USER_WARNING); + return FALSE; + } if (variable_get('dev_query', 0)) { - $bt = debug_backtrace(); $query = $bt[2]['function'] ."\n". $query; list($usec, $sec) = explode(' ', microtime()); $stop = (float)$usec + (float)$sec; @@ -150,15 +130,8 @@ function _db_query($query, $debug = 0) { print '

query: '. $query .'
error:'. pg_last_error($active_db) .'

'; } - if ($last_result !== FALSE) { - return $last_result; - } - else { - // Indicate to drupal_error_handler that this is a database error. - ${DB_ERROR} = TRUE; - trigger_error(check_plain(pg_last_error($active_db) ."\nquery: ". $query), E_USER_WARNING); - return FALSE; - } + $last_result = $stmt; + return $last_result; } /** @@ -172,8 +145,10 @@ function _db_query($query, $debug = 0) { */ function db_fetch_object($result) { if ($result) { - return pg_fetch_object($result); + $object = pg_fetch_object($result); + return isset($object) ? $object : FALSE; } + return FALSE; } /** @@ -188,8 +163,10 @@ function db_fetch_object($result) { */ function db_fetch_array($result) { if ($result) { - return pg_fetch_assoc($result); + $array = pg_fetch_assoc($result); + return isset($array) ? $array : FALSE; } + return FALSE; } /** @@ -206,7 +183,7 @@ function db_fetch_array($result) { function db_result($result) { if ($result && pg_num_rows($result) > 0) { $array = pg_fetch_row($result); - return $array[0]; + return isset($array[0]) ? $array[0] : FALSE; } return FALSE; } @@ -220,707 +197,75 @@ function db_error() { } /** - * Returns the last insert id. This function is thread safe. - * - * @param $table - * The name of the table you inserted into. - * @param $field - * The name of the autoincrement field. - */ -function db_last_insert_id($table, $field) { - return db_result(db_query("SELECT CURRVAL('{". db_escape_table($table) ."}_". db_escape_table($field) ."_seq')")); -} - -/** * Determine the number of rows changed by the preceding query. */ function db_affected_rows() { global $last_result; - return empty($last_result) ? 0 : pg_affected_rows($last_result); + return pg_affected_rows($last_result); } -/** - * Runs a limited-range query in the active database. - * - * Use this as a substitute for db_query() when a subset of the query - * is to be returned. - * User-supplied arguments to the query should be passed in as separate - * parameters so that they can be properly escaped to avoid SQL injection - * attacks. - * - * @param $query - * A string containing an SQL query. - * @param ... - * A variable number of arguments which are substituted into the query - * using printf() syntax. Instead of a variable number of query arguments, - * you may also pass a single array containing the query arguments. - * Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose - * in '') and %%. - * - * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, - * and TRUE values to decimal 1. +/* + * Prepare user input for use in a database query, preventing SQL injection attacks. * - * @param $from - * The first result row to return. - * @param $count - * The maximum number of result rows to return. + * @param $data + * Data to encode. * @return - * A database query result resource, or FALSE if the query was not executed - * correctly. + * Encoded data. */ -function db_query_range($query) { - $args = func_get_args(); - $count = array_pop($args); - $from = array_pop($args); - array_shift($args); - - $query = db_prefix_tables($query); - if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax - $args = $args[0]; - } - _db_query_callback($args, TRUE); - $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); - $query .= ' LIMIT '. (int)$count .' OFFSET '. (int)$from; - return _db_query($query); +function db_escape_decimal($data) { + return (int) $data; } /** - * Runs a SELECT query and stores its results in a temporary table. - * - * Use this as a substitute for db_query() when the results need to stored - * in a temporary table. Temporary tables exist for the duration of the page - * request. - * User-supplied arguments to the query should be passed in as separate parameters - * so that they can be properly escaped to avoid SQL injection attacks. - * - * Note that if you need to know how many results were returned, you should do - * a SELECT COUNT(*) on the temporary table afterwards. db_affected_rows() does - * not give consistent result across different database types in this case. - * - * @param $query - * A string containing a normal SELECT SQL query. - * @param ... - * A variable number of arguments which are substituted into the query - * using printf() syntax. The query arguments can be enclosed in one - * array instead. - * Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose - * in '') and %%. - * - * NOTE: using this syntax will cast NULL and FALSE values to decimal 0, - * and TRUE values to decimal 1. + * Prepare user input for use in a database query, preventing SQL injection attacks. * - * @param $table - * The name of the temporary table to select into. This name will not be - * prefixed as there is no risk of collision. + * @param $data + * Data to encode. * @return - * A database query result resource, or FALSE if the query was not executed - * correctly. + * Encoded data. */ -function db_query_temporary($query) { - $args = func_get_args(); - $tablename = array_pop($args); - array_shift($args); +function db_escape_float($data) { + return (float) $data; +} - $query = preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE '. $tablename .' AS SELECT', db_prefix_tables($query)); - if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax - $args = $args[0]; - } - _db_query_callback($args, TRUE); - $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); - return _db_query($query); +/** + * Prepare user input for use in a database query, preventing SQL injection attacks. + * + * @param $data + * Data to encode. + * @return + * Encoded data. + */ +function db_escape_string($data) { + return "'". pg_escape_string($data) ."'"; } /** * Returns a properly formatted Binary Large OBject value. - * In case of PostgreSQL encodes data for insert into bytea field. * * @param $data * Data to encode. * @return - * Encoded data. + * Encoded data. */ function db_encode_blob($data) { + // In case of PostgreSQL encodes data for INSERT into bytea field. return "'". pg_escape_bytea($data) ."'"; } /** * Returns text from a Binary Large OBject value. - * In case of PostgreSQL decodes data after select from bytea field. * * @param $data * Data to decode. * @return - * Decoded data. + * Decoded data. */ function db_decode_blob($data) { + // In case of PostgreSQL decodes data after select from bytea field. return pg_unescape_bytea($data); } /** - * Prepare user input for use in a database query, preventing SQL injection attacks. - * Note: This function requires PostgreSQL 7.2 or later. - */ -function db_escape_string($text) { - return pg_escape_string($text); -} - -/** - * Lock a table. - * This function automatically starts a transaction. - */ -function db_lock_table($table) { - db_query('BEGIN; LOCK TABLE {'. db_escape_table($table) .'} IN EXCLUSIVE MODE'); -} - -/** - * Unlock all locked tables. - * This function automatically commits a transaction. - */ -function db_unlock_tables() { - db_query('COMMIT'); -} - -/** - * Check if a table exists. - */ -function db_table_exists($table) { - return (bool) db_result(db_query("SELECT COUNT(*) FROM pg_class WHERE relname = '{". db_escape_table($table) ."}'")); -} - -/** - * Check if a column exists in the given table. - */ -function db_column_exists($table, $column) { - return (bool) db_result(db_query("SELECT COUNT(pg_attribute.attname) FROM pg_class, pg_attribute WHERE pg_attribute.attrelid = pg_class.oid AND pg_class.relname = '{". db_escape_table($table) ."}' AND attname = '". db_escape_table($column) ."'")); -} - -/** - * Verify if the database is set up correctly. - */ -function db_check_setup() { - $t = get_t(); - - $encoding = db_result(db_query('SHOW server_encoding')); - if (!in_array(strtolower($encoding), array('unicode', 'utf8'))) { - drupal_set_message($t('Your PostgreSQL database is set up with the wrong character encoding (%encoding). It is possible it will not work as expected. It is advised to recreate it with UTF-8/Unicode encoding. More information can be found in the PostgreSQL documentation.', array('%encoding' => $encoding, '@url' => 'http://www.postgresql.org/docs/7.4/interactive/multibyte.html')), 'status'); - } -} - -/** - * Wraps the given table.field entry with a DISTINCT(). The wrapper is added to - * the SELECT list entry of the given query and the resulting query is returned. - * This function only applies the wrapper if a DISTINCT doesn't already exist in - * the query. - * - * @param $table Table containing the field to set as DISTINCT - * @param $field Field to set as DISTINCT - * @param $query Query to apply the wrapper to - * @return SQL query with the DISTINCT wrapper surrounding the given table.field. - */ -function db_distinct_field($table, $field, $query) { - $field_to_select = 'DISTINCT ON ('. $table .'.'. $field .") $table.$field"; - // (? 'varchar', - 'char:normal' => 'character', - - 'text:tiny' => 'text', - 'text:small' => 'text', - 'text:medium' => 'text', - 'text:big' => 'text', - 'text:normal' => 'text', - - 'int:tiny' => 'smallint', - 'int:small' => 'smallint', - 'int:medium' => 'int', - 'int:big' => 'bigint', - 'int:normal' => 'int', - - 'float:tiny' => 'real', - 'float:small' => 'real', - 'float:medium' => 'real', - 'float:big' => 'double precision', - 'float:normal' => 'real', - - 'numeric:normal' => 'numeric', - - 'blob:big' => 'bytea', - 'blob:normal' => 'bytea', - - 'datetime:normal' => 'timestamp', - - 'serial:tiny' => 'serial', - 'serial:small' => 'serial', - 'serial:medium' => 'serial', - 'serial:big' => 'bigserial', - 'serial:normal' => 'serial', - ); - return $map; -} - -/** - * Generate SQL to create a new table from a Drupal schema definition. - * - * @param $name - * The name of the table to create. - * @param $table - * A Schema API table definition array. - * @return - * An array of SQL statements to create the table. - */ -function db_create_table_sql($name, $table) { - $sql_fields = array(); - foreach ($table['fields'] as $field_name => $field) { - $sql_fields[] = _db_create_field_sql($field_name, _db_process_field($field)); - } - - $sql_keys = array(); - if (isset($table['primary key']) && is_array($table['primary key'])) { - $sql_keys[] = 'PRIMARY KEY ('. implode(', ', $table['primary key']) .')'; - } - if (isset($table['unique keys']) && is_array($table['unique keys'])) { - foreach ($table['unique keys'] as $key_name => $key) { - $sql_keys[] = 'CONSTRAINT {'. $name .'}_'. $key_name .'_key UNIQUE ('. implode(', ', $key) .')'; - } - } - - $sql = "CREATE TABLE {". $name ."} (\n\t"; - $sql .= implode(",\n\t", $sql_fields); - if (count($sql_keys) > 0) { - $sql .= ",\n\t"; - } - $sql .= implode(",\n\t", $sql_keys); - $sql .= "\n)"; - $statements[] = $sql; - - if (isset($table['indexes']) && is_array($table['indexes'])) { - foreach ($table['indexes'] as $key_name => $key) { - $statements[] = _db_create_index_sql($name, $key_name, $key); - } - } - - return $statements; -} - -function _db_create_index_sql($table, $name, $fields) { - $query = 'CREATE INDEX {'. $table .'}_'. $name .'_idx ON {'. $table .'} ('; - $query .= _db_create_key_sql($fields) .')'; - return $query; -} - -function _db_create_key_sql($fields) { - $ret = array(); - foreach ($fields as $field) { - if (is_array($field)) { - $ret[] = 'substr('. $field[0] .', 1, '. $field[1] .')'; - } - else { - $ret[] = $field; - } - } - return implode(', ', $ret); -} - -function _db_create_keys(&$ret, $table, $new_keys) { - if (isset($new_keys['primary key'])) { - db_add_primary_key($ret, $table, $new_keys['primary key']); - } - if (isset($new_keys['unique keys'])) { - foreach ($new_keys['unique keys'] as $name => $fields) { - db_add_unique_key($ret, $table, $name, $fields); - } - } - if (isset($new_keys['indexes'])) { - foreach ($new_keys['indexes'] as $name => $fields) { - db_add_index($ret, $table, $name, $fields); - } - } -} - -/** - * 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['pgsql_type'])) { - $map = db_type_map(); - $field['pgsql_type'] = $map[$field['type'] .':'. $field['size']]; - } - if ($field['type'] == 'serial') { - unset($field['not null']); - } - 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['pgsql_type']; - - if ($spec['type'] == 'serial') { - unset($spec['not null']); - } - if (!empty($spec['unsigned'])) { - if ($spec['type'] == 'serial') { - $sql .= " CHECK ($name >= 0)"; - } - else { - $sql .= '_unsigned'; - } - } - - if (!empty($spec['length'])) { - $sql .= '('. $spec['length'] .')'; - } - elseif (isset($spec['precision']) && isset($spec['scale'])) { - $sql .= '('. $spec['precision'] .', '. $spec['scale'] .')'; - } - - if (isset($spec['not null']) && $spec['not null']) { - $sql .= ' NOT NULL'; - } - if (isset($spec['default'])) { - $default = is_string($spec['default']) ? "'". $spec['default'] ."'" : $spec['default']; - $sql .= " default $default"; - } - - return $sql; -} - -/** - * Rename a table. - * - * @param $ret - * Array to which query results will be added. - * @param $table - * The table to be renamed. - * @param $new_name - * The new name for the table. - */ -function db_rename_table(&$ret, $table, $new_name) { - $ret[] = update_sql('ALTER TABLE {'. $table .'} RENAME TO {'. $new_name .'}'); -} - -/** - * 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. - * The specification may also contain the key 'initial', the newly - * created field will be set to the value of the key in all rows. - * This is most useful for creating NOT NULL columns with no default - * value in existing tables. - * @param $keys_new - * Optional keys and indexes specification to be created on the - * table along with adding the field. The format is the same as a - * table specification but without the 'fields' element. If you are - * adding a type 'serial' field, you MUST specify at least one key - * or index including it in this array. @see db_change_field for more - * explanation why. - */ -function db_add_field(&$ret, $table, $field, $spec, $new_keys = array()) { - $fixnull = FALSE; - if (!empty($spec['not null']) && !isset($spec['default'])) { - $fixnull = TRUE; - $spec['not null'] = FALSE; - } - $query = 'ALTER TABLE {'. $table .'} ADD COLUMN '; - $query .= _db_create_field_sql($field, _db_process_field($spec)); - $ret[] = update_sql($query); - if (isset($spec['initial'])) { - // All this because update_sql does not support %-placeholders. - $sql = 'UPDATE {'. $table .'} SET '. $field .' = '. db_type_placeholder($spec['type']); - $result = db_query($sql, $spec['initial']); - $ret[] = array('success' => $result !== FALSE, 'query' => check_plain($sql .' ('. $spec['initial'] .')')); - } - if ($fixnull) { - $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $field SET NOT NULL"); - } - if (isset($new_keys)) { - _db_create_keys($ret, $table, $new_keys); - } -} - -/** - * 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 COLUMN '. $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 ('. - implode(',', $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 CONSTRAINT {'. $table .'}_pkey'); -} - -/** - * Add a unique key. - * - * @param $ret - * Array to which query results will be added. - * @param $table - * The table to be altered. - * @param $name - * The name of the key. - * @param $fields - * An array of field names. - */ -function db_add_unique_key(&$ret, $table, $name, $fields) { - $name = '{'. $table .'}_'. $name .'_key'; - $ret[] = update_sql('ALTER TABLE {'. $table .'} ADD CONSTRAINT '. - $name .' UNIQUE ('. implode(',', $fields) .')'); -} - -/** - * Drop a unique key. - * - * @param $ret - * Array to which query results will be added. - * @param $table - * The table to be altered. - * @param $name - * The name of the key. - */ -function db_drop_unique_key(&$ret, $table, $name) { - $name = '{'. $table .'}_'. $name .'_key'; - $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP CONSTRAINT '. $name); -} - -/** - * Add an index. - * - * @param $ret - * Array to which query results will be added. - * @param $table - * The table to be altered. - * @param $name - * The name of the index. - * @param $fields - * An array of field names. - */ -function db_add_index(&$ret, $table, $name, $fields) { - $ret[] = update_sql(_db_create_index_sql($table, $name, $fields)); -} - -/** - * Drop an index. - * - * @param $ret - * Array to which query results will be added. - * @param $table - * The table to be altered. - * @param $name - * The name of the index. - */ -function db_drop_index(&$ret, $table, $name) { - $name = '{'. $table .'}_'. $name .'_idx'; - $ret[] = update_sql('DROP INDEX '. $name); -} - -/** - * Change a field definition. - * - * IMPORTANT NOTE: To maintain database portability, you have to explicitly - * recreate all indices and primary keys that are using the changed field. - * - * That means that you have to drop all affected keys and indexes with - * db_drop_{primary_key,unique_key,index}() before calling db_change_field(). - * To recreate the keys and indices, pass the key definitions as the - * optional $new_keys argument directly to db_change_field(). - * - * For example, suppose you have: - * @code - * $schema['foo'] = array( - * 'fields' => array( - * 'bar' => array('type' => 'int', 'not null' => TRUE) - * ), - * 'primary key' => array('bar') - * ); - * @endcode - * and you want to change foo.bar to be type serial, leaving it as the - * primary key. The correct sequence is: - * @code - * db_drop_primary_key($ret, 'foo'); - * db_change_field($ret, 'foo', 'bar', 'bar', - * array('type' => 'serial', 'not null' => TRUE), - * array('primary key' => array('bar'))); - * @endcode - * - * The reasons for this are due to the different database engines: - * - * On PostgreSQL, changing a field definition involves adding a new field - * and dropping an old one which* causes any indices, primary keys and - * sequences (from serial-type fields) that use the changed field to be dropped. - * - * On MySQL, all type 'serial' fields must be part of at least one key - * or index as soon as they are created. You cannot use - * db_add_{primary_key,unique_key,index}() for this purpose because - * the ALTER TABLE command will fail to add the column without a key - * or index specification. The solution is to use the optional - * $new_keys argument to create the key or index at the same time as - * field. - * - * You could use db_add_{primary_key,unique_key,index}() in all cases - * unless you are converting a field to be type serial. You can use - * the $new_keys argument in all cases. - * - * @param $ret - * Array to which query results will be added. - * @param $table - * Name of the table. - * @param $field - * Name of the field to change. - * @param $field_new - * New name for the field (set to the same as $field if you don't want to change the name). - * @param $spec - * The field specification for the new field. - * @param $new_keys - * Optional keys and indexes specification to be created on the - * table along with changing the field. The format is the same as a - * table specification but without the 'fields' element. - */ -function db_change_field(&$ret, $table, $field, $field_new, $spec, $new_keys = array()) { - $ret[] = update_sql("ALTER TABLE {". $table ."} RENAME $field TO ". $field ."_old"); - $not_null = isset($spec['not null']) ? $spec['not null'] : FALSE; - unset($spec['not null']); - - db_add_field($ret, $table, "$field_new", $spec); - - $ret[] = update_sql("UPDATE {". $table ."} SET $field_new = ". $field ."_old"); - - if ($not_null) { - $ret[] = update_sql("ALTER TABLE {". $table ."} ALTER $field_new SET NOT NULL"); - } - - db_drop_field($ret, $table, $field .'_old'); - - if (isset($new_keys)) { - _db_create_keys($ret, $table, $new_keys); - } -} - -/** - * @} End of "ingroup schemaapi". - */ - Index: includes/file.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/file.inc,v retrieving revision 1.121.2.1 diff -u -p -r1.121.2.1 file.inc --- includes/file.inc 7 Feb 2008 18:20:37 -0000 1.121.2.1 +++ includes/file.inc 31 Mar 2008 17:26:00 -0000 @@ -22,7 +22,7 @@ define('FILE_EXISTS_ERROR', 2); /** * A files status can be one of two values: temporary or permanent. The status - * for each file Drupal manages is stored in the {files} tables. If the status + * for each file Drupal manages is stored in the [{files}] tables. If the status * is temporary Drupal's file garbage collection will delete the file and * remove it from the files table after a set period of time. * @@ -445,9 +445,9 @@ function file_delete($path) { */ function file_space_used($uid = NULL) { if (isset($uid)) { - return (int) db_result(db_query('SELECT SUM(filesize) FROM {files} WHERE uid = %d', $uid)); + return (int) db_result(db_query('SELECT SUM([filesize]) FROM [{files}] WHERE [uid] = %d', $uid)); } - return (int) db_result(db_query('SELECT SUM(filesize) FROM {files}')); + return (int) db_result(db_query('SELECT SUM([filesize]) FROM [{files}]')); } /** @@ -777,7 +777,7 @@ function file_save_data($data, $dest, $r * status. */ function file_set_status(&$file, $status) { - if (db_query('UPDATE {files} SET status = %d WHERE fid = %d', $status, $file->fid)) { + if (db_query('UPDATE [{files}] SET [status] = %d WHERE [fid] = %d', $status, $file->fid)) { $file->status = $status; return TRUE; } Index: includes/form.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/form.inc,v retrieving revision 1.265.2.4 diff -u -p -r1.265.2.4 form.inc --- includes/form.inc 11 Feb 2008 14:45:57 -0000 1.265.2.4 +++ includes/form.inc 31 Mar 2008 17:26:09 -0000 @@ -2306,10 +2306,10 @@ function form_clean_id($id = NULL, $flus * if (empty($context['sandbox'])) { * $context['sandbox']['progress'] = 0; * $context['sandbox']['current_node'] = 0; - * $context['sandbox']['max'] = db_result(db_query('SELECT COUNT(DISTINCT nid) FROM {node}')); + * $context['sandbox']['max'] = db_result(db_query('SELECT COUNT(DISTINCT [nid]) FROM [{node}]')); * } * $limit = 5; - * $result = db_query_range("SELECT nid FROM {node} WHERE nid > %d ORDER BY nid ASC", $context['sandbox']['current_node'], 0, $limit); + * $result = db_query_range("SELECT [nid] FROM [{node}] WHERE [nid] > %d ORDER BY [nid] ASC", $context['sandbox']['current_node'], 0, $limit); * while ($row = db_fetch_array($result)) { * $node = node_load($row['nid'], NULL, TRUE); * $context['results'][] = $node->nid .' : '. $node->title; @@ -2473,7 +2473,7 @@ function batch_process($redirect = NULL, // Initiate db storage in order to get a batch id. We have to provide // at least an empty string for the (not null) 'token' column. - db_query("INSERT INTO {batch} (token, timestamp) VALUES ('', %d)", time()); + db_query("INSERT INTO [{batch}] ([token], [timestamp]) VALUES (%s, %d)", '', time()); $batch['id'] = db_last_insert_id('batch', 'bid'); // Now that we have a batch id, we can generate the redirection link in @@ -2482,7 +2482,7 @@ function batch_process($redirect = NULL, $batch['error_message'] = $t('Please continue to the error page', array('@error_url' => url($url, array('query' => array('id' => $batch['id'], 'op' => 'finished'))))); // Actually store the batch data and the token generated form the batch id. - db_query("UPDATE {batch} SET token = '%s', batch = '%s' WHERE bid = %d", drupal_get_token($batch['id']), serialize($batch), $batch['id']); + db_query("UPDATE [{batch}] SET [token] = %s, [batch] = %s WHERE [bid] = %d", drupal_get_token($batch['id']), serialize($batch), $batch['id']); drupal_goto($batch['url'], 'op=start&id='. $batch['id']); } Index: includes/install.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/install.inc,v retrieving revision 1.56.2.2 diff -u -p -r1.56.2.2 install.inc --- includes/install.inc 11 Feb 2008 15:10:26 -0000 1.56.2.2 +++ includes/install.inc 31 Mar 2008 17:26:09 -0000 @@ -77,7 +77,7 @@ function drupal_get_installed_schema_ver if (!$versions) { $versions = array(); - $result = db_query("SELECT name, schema_version FROM {system} WHERE type = '%s'", 'module'); + $result = db_query("SELECT [name], [schema_version] FROM [{system}] WHERE [type] = %s", 'module'); while ($row = db_fetch_object($result)) { $versions[$row->name] = $row->schema_version; } @@ -95,7 +95,7 @@ function drupal_get_installed_schema_ver * The new schema version. */ function drupal_set_installed_schema_version($module, $version) { - db_query("UPDATE {system} SET schema_version = %d WHERE name = '%s'", $version, $module); + db_query("UPDATE [{system}] SET [schema_version] = %d WHERE [name] = %s", $version, $module); } /** @@ -151,12 +151,13 @@ function drupal_detect_baseurl($file = ' function drupal_detect_database_types() { $databases = array(); - foreach (array('mysql', 'mysqli', 'pgsql') as $type) { - if (file_exists('./includes/install.'. $type .'.inc')) { - include_once './includes/install.'. $type .'.inc'; - $function = $type .'_is_available'; + foreach (glob('./includes/database.*.inc') as $driver_file) { + list(, $driver) = explode('.', basename($driver_file)); + if (file_exists('./includes/database.'. $driver .'.inc') && file_exists('./includes/install.'. $driver .'.inc')) { + include_once './includes/install.'. $driver .'.inc'; + $function = $driver .'_is_available'; if ($function()) { - $databases[$type] = $type; + $databases[$driver] = $driver; } } } @@ -212,7 +213,7 @@ function drupal_rewrite_settings($settin // Write new value to settings.php in the following format: // $'setting' = 'value'; // 'comment' $setting = $settings[$variable[1]]; - $buffer .= '$'. $variable[1] ." = '". $setting['value'] ."';". (!empty($setting['comment']) ? ' // '. $setting['comment'] ."\n" : "\n"); + $buffer .= '$'. $variable[1] ." = ". var_export($setting['value'], TRUE) .";". (!empty($setting['comment']) ? ' // '. $setting['comment'] ."\n" : "\n"); unset($settings[$variable[1]]); } else { @@ -228,7 +229,7 @@ function drupal_rewrite_settings($settin // Add required settings that were missing from settings.php. foreach ($settings as $setting => $data) { if ($data['required']) { - $buffer .= "\$$setting = '". $data['value'] ."';\n"; + $buffer .= "\$$setting = ". var_export($data['value'], TRUE) .";\n"; } } @@ -359,7 +360,7 @@ function drupal_install_system() { module_invoke('system', 'install'); $system_versions = drupal_get_schema_versions('system'); $system_version = $system_versions ? max($system_versions) : SCHEMA_INSTALLED; - db_query("INSERT INTO {system} (filename, name, type, owner, status, throttle, bootstrap, schema_version) VALUES('%s', '%s', '%s', '%s', %d, %d, %d, %d)", $system_path .'/system.module', 'system', 'module', '', 1, 0, 0, $system_version); + db_query("INSERT INTO [{system}] ([filename], [name], [type], [owner], [status], [throttle], [bootstrap], [schema_version]) VALUES(%s, %s, %s, %s, %d, %d, %d, %d)", $system_path .'/system.module', 'system', 'module', '', 1, 0, 0, $system_version); // Now that we've installed things properly, bootstrap the full Drupal environment drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); module_rebuild_cache(); @@ -394,9 +395,9 @@ function drupal_uninstall_module($module } $paths[$index] = implode('/', $parts); } - $placeholders = implode(', ', array_fill(0, count($paths), "'%s'")); + $placeholders = implode(', ', array_fill(0, count($paths), "%s")); - $result = db_query('SELECT * FROM {menu_links} WHERE router_path IN ('. $placeholders .') AND external = 0 ORDER BY depth DESC', $paths); + $result = db_query('SELECT * FROM [{menu_links}] WHERE [router_path] IN ('. $placeholders .') AND [external] = 0 ORDER BY [depth] DESC', $paths); // Remove all such items. Starting from those with the greatest depth will // minimize the amount of re-parenting done by menu_link_delete(). while ($item = db_fetch_array($result)) { Index: includes/install.mysql.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/install.mysql.inc,v retrieving revision 1.9 diff -u -p -r1.9 install.mysql.inc --- includes/install.mysql.inc 23 Jan 2008 09:59:29 -0000 1.9 +++ includes/install.mysql.inc 31 Mar 2008 17:26:10 -0000 @@ -1,16 +1,16 @@
  • Are you sure you have the correct username and password?
  • Are you sure that you have typed the correct database hostname?
  • Are you sure that the database server is running?
  • For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%error' => mysql_error())), 'error'); return FALSE; } // Test selecting the database. - if (!mysql_select_db(substr($url['path'], 1))) { + if (!mysql_select_db($url['db_name'])) { drupal_set_message(st('Failed to select your database on your MySQL database server, which means the connection username and password are valid, but there is a problem accessing your data. MySQL reports the following message: %error.For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%error' => mysql_error())), 'error'); return FALSE; } @@ -54,7 +46,7 @@ function drupal_test_mysql($url, &$succe $success = array('CONNECT'); // Test CREATE. - $query = 'CREATE TABLE drupal_install_test (id int NULL)'; + $query = 'CREATE TABLE `drupal_install_test` (`id` INT NULL)'; $result = mysql_query($query); if ($error = mysql_error()) { drupal_set_message(st('Failed to create a test table on your MySQL database server with the command %query. MySQL reports the following message: %error.For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%query' => $query, '%error' => $error)), 'error'); @@ -65,7 +57,7 @@ function drupal_test_mysql($url, &$succe $success[] = 'CREATE'; // Test INSERT. - $query = 'INSERT INTO drupal_install_test (id) VALUES (1)'; + $query = 'INSERT INTO `drupal_install_test` (`id`) VALUES (1)'; $result = mysql_query($query); if ($error = mysql_error()) { drupal_set_message(st('Failed to insert a value into a test table on your MySQL database server. We tried inserting a value with the command %query and MySQL reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error'); @@ -76,7 +68,7 @@ function drupal_test_mysql($url, &$succe } // Test UPDATE. - $query = 'UPDATE drupal_install_test SET id = 2'; + $query = 'UPDATE `drupal_install_test` SET `id` = 2'; $result = mysql_query($query); if ($error = mysql_error()) { drupal_set_message(st('Failed to update a value in a test table on your MySQL database server. We tried updating a value with the command %query and MySQL reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error'); @@ -87,7 +79,7 @@ function drupal_test_mysql($url, &$succe } // Test DELETE. - $query = 'DELETE FROM drupal_install_test'; + $query = 'DELETE FROM `drupal_install_test`'; $result = mysql_query($query); if ($error = mysql_error()) { drupal_set_message(st('Failed to delete a value from a test table on your MySQL database server. We tried deleting a value with the command %query and MySQL reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error'); @@ -98,7 +90,7 @@ function drupal_test_mysql($url, &$succe } // Test DROP. - $query = 'DROP TABLE drupal_install_test'; + $query = 'DROP TABLE `drupal_install_test`'; $result = mysql_query($query); if ($error = mysql_error()) { drupal_set_message(st('Failed to drop a test table from your MySQL database server. We tried dropping a table with the command %query and MySQL reported the following error %error.', array('%query' => $query, '%error' => $error)), 'error'); Index: includes/install.mysqli.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/install.mysqli.inc,v retrieving revision 1.12 diff -u -p -r1.12 install.mysqli.inc --- includes/install.mysqli.inc 23 Jan 2008 09:59:29 -0000 1.12 +++ includes/install.mysqli.inc 31 Mar 2008 17:26:10 -0000 @@ -1,16 +1,16 @@ = 2000 || mysqli_connect_errno() == 1045) { drupal_set_message(st('Failed to connect to your MySQL database server. MySQL reports the following message: %error.For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%error' => mysqli_connect_error())), 'error'); return FALSE; @@ -49,7 +41,7 @@ function drupal_test_mysqli($url, &$succ $success = array('CONNECT'); // Test CREATE. - $query = 'CREATE TABLE drupal_install_test (id int NULL)'; + $query = 'CREATE TABLE `drupal_install_test` (`id` INT NULL)'; $result = mysqli_query($connection, $query); if ($error = mysqli_error($connection)) { drupal_set_message(st('Failed to create a test table on your MySQL database server with the command %query. MySQL reports the following message: %error.For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%query' => $query, '%error' => $error)), 'error'); @@ -60,7 +52,7 @@ function drupal_test_mysqli($url, &$succ $success[] = 'CREATE'; // Test INSERT. - $query = 'INSERT INTO drupal_install_test (id) VALUES (1)'; + $query = 'INSERT INTO `drupal_install_test` (`id`) VALUES (1)'; $result = mysqli_query($connection, $query); if ($error = mysqli_error($connection)) { drupal_set_message(st('Failed to insert a value into a test table on your MySQL database server. We tried inserting a value with the command %query and MySQL reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error'); @@ -71,7 +63,7 @@ function drupal_test_mysqli($url, &$succ } // Test UPDATE. - $query = 'UPDATE drupal_install_test SET id = 2'; + $query = 'UPDATE `drupal_install_test` SET `id` = 2'; $result = mysqli_query($connection, $query); if ($error = mysqli_error($connection)) { drupal_set_message(st('Failed to update a value in a test table on your MySQL database server. We tried updating a value with the command %query and MySQL reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error'); @@ -82,7 +74,7 @@ function drupal_test_mysqli($url, &$succ } // Test DELETE. - $query = 'DELETE FROM drupal_install_test'; + $query = 'DELETE FROM `drupal_install_test`'; $result = mysqli_query($connection, $query); if ($error = mysqli_error($connection)) { drupal_set_message(st('Failed to delete a value from a test table on your MySQL database server. We tried deleting a value with the command %query and MySQL reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error'); @@ -93,7 +85,7 @@ function drupal_test_mysqli($url, &$succ } // Test DROP. - $query = 'DROP TABLE drupal_install_test'; + $query = 'DROP TABLE `drupal_install_test`'; $result = mysqli_query($connection, $query); if ($error = mysqli_error($connection)) { drupal_set_message(st('Failed to drop a test table from your MySQL database server. We tried dropping a table with the command %query and MySQL reported the following error %error.', array('%query' => $query, '%error' => $error)), 'error'); Index: includes/install.oci8.inc =================================================================== RCS file: includes/install.oci8.inc diff -N includes/install.oci8.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/install.oci8.inc 31 Mar 2008 17:26:10 -0000 @@ -0,0 +1,134 @@ +
  • Are you sure you have the correct username and password?
  • Are you sure that you have typed the correct database hostname?
  • Are you sure that the database server is running?
  • Are you sure you typed the correct database name?
  • For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.
    Error: '. $error, array('%error' => 'Connection failed. See log file for failure reason')), 'error'); + return FALSE; + } + + $success = array('CONNECT'); + + // Test CREATE. + $query = 'CREATE TABLE "drupal_install_test" ("id" NUMBER(38) NOT NULL)'; + $stmt = @oci_parse($connection, $query); + if (!$stmt && ($error = oci_error($connection))) { + drupal_set_message(st('We were unable to create a test table on your Oracle database server with the command %query. Oracle reports the following message: %error.For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%query' => $query, '%error' => $error)), 'error'); + return FALSE; + } + $result = @oci_execute($stmt); + $err = FALSE; + $success[] = 'SELECT'; + $success[] = 'CREATE'; + + // Test INSERT. + $query = 'INSERT INTO "drupal_install_test" ("id") VALUES (1)'; + $stmt = @oci_parse($connection, $query); + $result = @oci_execute($stmt); + if ($error = oci_error($stmt)) { + drupal_set_message(st('We were unable to insert a value into a test table on your Oracle database server. We tried inserting a value with the command %query and Oracle reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error'); + $err = TRUE; + } + else { + $success[] = 'INSERT'; + } + + // Test UPDATE. + $query = 'UPDATE "drupal_install_test" SET "id" = 2'; + $stmt = @oci_parse($connection, $query); + $result = @oci_execute($stmt); + if ($error = oci_error($stmt)) { + drupal_set_message(st('We were unable to update a value in a test table on your Oracle database server. We tried updating a value with the command %query and Oracle reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error'); + $err = TRUE; + } + else { + $success[] = 'UPDATE'; + } + + // Test LOCK. + $query = 'LOCK TABLE "drupal_install_test" IN EXCLUSIVE MODE'; + $stmt = @oci_parse($connection, $query); + $result = @oci_execute($stmt); + if ($error = oci_error($stmt)) { + drupal_set_message(st('We were unable to lock a test table on your Oracle database server. We tried locking a table with the command %query and Oracle reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error'); + $err = TRUE; + } + else { + $success[] = 'LOCK'; + } + + // Test UNLOCK. + $query = 'COMMIT'; + $stmt = @oci_parse($connection, $query); + $result = @oci_execute($stmt); + if ($error = oci_error($stmt)) { + drupal_set_message(st('We were unable to unlock a test table on your Oracle database server. We tried unlocking a table with the command %query and Oracle reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error'); + $err = TRUE; + } + else { + $success[] = 'UNLOCK'; + } + + // Test DELETE. + $query = 'DELETE FROM "drupal_install_test"'; + $stmt = @oci_parse($connection, $query); + $result = @oci_execute($stmt); + if ($error = oci_error($stmt)) { + drupal_set_message(st('We were unable to delete a value from a test table on your Oracle database server. We tried deleting a value with the command %query and Oracle reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error'); + $err = TRUE; + } + else { + $success[] = 'DELETE'; + } + + // Test DROP. + $query = 'DROP TABLE "drupal_install_test"'; + $stmt = @oci_parse($connection, $query); + $result = @oci_execute($stmt); + if ($error = oci_error($stmt)) { + drupal_set_message(st('We were unable to drop a test table from your Oracle database server. We tried dropping a table with the command %query and Oracle reported the following error %error.', array('%query' => $query, '%error' => $error)), 'error'); + $err = TRUE; + } + else { + $success[] = 'DROP'; + } + + if ($err) { + return FALSE; + } + + oci_close($connection); + return TRUE; +} Index: includes/install.pdo_ibm.inc =================================================================== RCS file: includes/install.pdo_ibm.inc diff -N includes/install.pdo_ibm.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/install.pdo_ibm.inc 31 Mar 2008 17:26:10 -0000 @@ -0,0 +1,149 @@ + PDO::ERRMODE_WARNING, + // Leave column names as returned by the database driver. + PDO::ATTR_CASE => PDO::CASE_NATURAL, + ); + + try { + $connection = new PDO($dsn, $url['db_user'], $url['db_pass'], $driver_options); + } catch (PDOExecption $e) { + drupal_set_message(st('Failed to connect to your DB2 database server. DB2 reports the following message: %error.For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%error' => $e->getMessage())), 'error'); + return FALSE; + } + + $success = array('CONNECT'); + + // Test CREATE. + $query = 'CREATE TABLE "drupal_install_test" ("id" INTEGER NOT NULL)'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to create a test table on your DB2 database server with the command %query. DB2 reports the following message: %error.For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%query' => $query, '%error' => $error[2])), 'error'); + return FALSE; + } + $err = FALSE; + $success[] = 'SELECT'; + $success[] = 'CREATE'; + + // Test INSERT. + $query = 'INSERT INTO "drupal_install_test" ("id") VALUES (1)'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to insert a value into a test table on your DB2 database server. We tried inserting a value with the command %query and DB2 reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'INSERT'; + } + + // Test UPDATE. + $query = 'UPDATE "drupal_install_test" SET "id" = 2'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to update a value in a test table on your DB2 database server. We tried updating a value with the command %query and DB2 reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'UPDATE'; + } + + // Test LOCK. + $query = 'LOCK TABLE "drupal_install_test" IN EXCLUSIVE MODE'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to lock a test table on your DB2 database server. We tried locking a table with the command %query and DB2 reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'LOCK'; + } + + // Test UNLOCK. + $query = 'COMMIT'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to unlock a test table on your DB2 database server. We tried unlocking a table with the command %query and DB2 reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'UNLOCK'; + } + + // Test DELETE. + $query = 'DELETE FROM "drupal_install_test"'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to delete a value from a test table on your DB2 database server. We tried deleting a value with the command %query and DB2 reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'DELETE'; + } + + // Test DROP. + $query = 'DROP TABLE "drupal_install_test"'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to drop a test table from your DB2 database server. We tried dropping a table with the command %query and DB2 reported the following error %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'DROP'; + } + + if ($err) { + return FALSE; + } + + $connection = NULL; + return TRUE; +} Index: includes/install.pdo_mysql.inc =================================================================== RCS file: includes/install.pdo_mysql.inc diff -N includes/install.pdo_mysql.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/install.pdo_mysql.inc 31 Mar 2008 17:26:11 -0000 @@ -0,0 +1,155 @@ + PDO::ERRMODE_WARNING, + // Leave column names as returned by the database driver. + PDO::ATTR_CASE => PDO::CASE_NATURAL, + // Force MySQL driver will use the buffered versions of the MySQL API. + PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => TRUE, + ); + + try { + $connection = new PDO($dsn, $url['db_user'], $url['db_pass'], $driver_options); + } catch (PDOExecption $e) { + drupal_set_message(st('Failed to connect to your MySQL database server. MySQL reports the following message: %error.For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%error' => $e->getMessage())), 'error'); + return FALSE; + } + + // Require ANSI mode to improve SQL portability. + $stmt = $connection->exec("SET SESSION SQL_MODE = 'ANSI'"); + // Force UTF-8 + $stmt = $connection->exec('SET NAMES "UTF8"'); + + $success = array('CONNECT'); + + // Test CREATE. + $query = 'CREATE TABLE `drupal_install_test` (`id` INT NULL)'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to create a test table on your MySQL database server with the command %query. MySQL reports the following message: %error.For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%query' => $query, '%error' => $error[2])), 'error'); + return FALSE; + } + $err = FALSE; + $success[] = 'SELECT'; + $success[] = 'CREATE'; + + // Test INSERT. + $query = 'INSERT INTO `drupal_install_test` (`id`) VALUES (1)'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to insert a value into a test table on your MySQL database server. We tried inserting a value with the command %query and MySQL reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'INSERT'; + } + + // Test UPDATE. + $query = 'UPDATE `drupal_install_test` SET `id` = 2'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to update a value in a test table on your MySQL database server. We tried updating a value with the command %query and MySQL reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'UPDATE'; + } + + // Test LOCK. + $query = 'LOCK TABLES `drupal_install_test` WRITE'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to lock a test table on your MySQL database server. We tried locking a table with the command %query and MySQL reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'LOCK'; + } + + // Test UNLOCK. + $query = 'UNLOCK TABLES'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to unlock a test table on your MySQL database server. We tried unlocking a table with the command %query and MySQL reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'UNLOCK'; + } + + // Test DELETE. + $query = 'DELETE FROM `drupal_install_test`'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to delete a value from a test table on your MySQL database server. We tried deleting a value with the command %query and MySQL reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'DELETE'; + } + + // Test DROP. + $query = 'DROP TABLE `drupal_install_test`'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to drop a test table from your MySQL database server. We tried dropping a table with the command %query and MySQL reported the following error %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'DROP'; + } + + if ($err) { + return FALSE; + } + + $connection = NULL; + return TRUE; +} Index: includes/install.pdo_oci.inc =================================================================== RCS file: includes/install.pdo_oci.inc diff -N includes/install.pdo_oci.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/install.pdo_oci.inc 31 Mar 2008 17:26:11 -0000 @@ -0,0 +1,150 @@ + PDO::ERRMODE_WARNING, + // Leave column names as returned by the database driver. + PDO::ATTR_CASE => PDO::CASE_NATURAL, + // Disable autocommit so that the connection begins a transaction. + PDO::ATTR_AUTOCOMMIT => FALSE, + ); + + try { + $connection = new PDO($dsn, $url['db_user'], $url['db_pass'], $driver_options); + } catch (PDOExecption $e) { + drupal_set_message(st('Failure to connect to your Oracle database server. Oracle reports the following message: %error.For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%error' => $e->getMessage())), 'error'); + return FALSE; + } + + $success = array('CONNECT'); + + // Test CREATE. + $query = 'CREATE TABLE "drupal_install_test" ("id" NUMBER(38) NOT NULL)'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('We were unable to create a test table on your Oracle database server with the command %query. Oracle reports the following message: %error.For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%query' => $query, '%error' => $error[2])), 'error'); + return FALSE; + } + $err = FALSE; + $success[] = 'SELECT'; + $success[] = 'CREATE'; + + // Test INSERT. + $query = 'INSERT INTO "drupal_install_test" ("id") VALUES (1)'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('We were unable to insert a value into a test table on your Oracle database server. We tried inserting a value with the command %query and Oracle reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'INSERT'; + } + + // Test UPDATE. + $query = 'UPDATE "drupal_install_test" SET "id" = 2'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('We were unable to update a value in a test table on your Oracle database server. We tried updating a value with the command %query and Oracle reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'UPDATE'; + } + + // Test LOCK. + $query = 'LOCK TABLE "drupal_install_test" IN EXCLUSIVE MODE'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('We were unable to lock a test table on your Oracle database server. We tried locking a table with the command %query and Oracle reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'LOCK'; + } + + // Test UNLOCK + $query = 'COMMIT'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('We were unable to unlock a test table on your Oracle database server. We tried unlocking a table with the command %query and Oracle reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'UNLOCK'; + } + + // Test DELETE. + $query = 'DELETE FROM "drupal_install_test"'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('We were unable to delete a value from a test table on your Oracle database server. We tried deleting a value with the command %query and Oracle reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'DELETE'; + } + + // Test DROP. + $query = 'DROP TABLE "drupal_install_test"'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('We were unable to drop a test table from your Oracle database server. We tried dropping a table with the command %query and Oracle reported the following error %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'DROP'; + } + + if ($err) { + return FALSE; + } + + $connection = NULL; + return TRUE; +} Index: includes/install.pdo_pgsql.inc =================================================================== RCS file: includes/install.pdo_pgsql.inc diff -N includes/install.pdo_pgsql.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/install.pdo_pgsql.inc 31 Mar 2008 17:26:12 -0000 @@ -0,0 +1,148 @@ + PDO::ERRMODE_WARNING, + // Leave column names as returned by the database driver. + PDO::ATTR_CASE => PDO::CASE_NATURAL, + ); + + try { + $connection = new PDO($dsn, $url['db_user'], $url['db_pass'], $driver_options); + } catch (PDOExecption $e) { + drupal_set_message(st('Failed to connect to your PostgreSQL database server. PostgreSQL reports the following message: %error.For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%error' => $e->getMessage())), 'error'); + return FALSE; + } + + $success = array('CONNECT'); + + // Test CREATE. + $query = 'CREATE TABLE "drupal_install_test" ("id" INT NOT NULL)'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to create a test table on your PostgreSQL database server with the command %query. PostgreSQL reports the following message: %error.For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%query' => $query, '%error' => $error[2])), 'error'); + return FALSE; + } + $err = FALSE; + $success[] = 'SELECT'; + $success[] = 'CREATE'; + + // Test INSERT. + $query = 'INSERT INTO "drupal_install_test" ("id") VALUES (1)'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to insert a value into a test table on your PostgreSQL database server. We tried inserting a value with the command %query and PostgreSQL reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'INSERT'; + } + + // Test UPDATE. + $query = 'UPDATE "drupal_install_test" SET "id" = 2'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to update a value in a test table on your PostgreSQL database server. We tried updating a value with the command %query and PostgreSQL reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'UPDATE'; + } + + // Test LOCK. + $query = 'LOCK "drupal_install_test" IN SHARE ROW EXCLUSIVE MODE'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to lock a test table on your PostgreSQL database server. We tried locking a table with the command %query and PostgreSQL reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'LOCK'; + } + + // Test UNLOCK. + $query = 'COMMIT'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to unlock a test table on your PostgreSQL database server. We tried unlocking a table with the command %query and PostgreSQL reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'UNLOCK'; + } + + // Test DELETE. + $query = 'DELETE FROM "drupal_install_test"'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to delete a value from a test table on your PostgreSQL database server. We tried deleting a value with the command %query and PostgreSQL reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'DELETE'; + } + + // Test DROP. + $query = 'DROP TABLE "drupal_install_test"'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to drop a test table from your PostgreSQL database server. We tried dropping a table with the command %query and PostgreSQL reported the following error %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'DROP'; + } + + if ($err) { + return FALSE; + } + + $connection = NULL; + return TRUE; +} Index: includes/install.pdo_sqlite.inc =================================================================== RCS file: includes/install.pdo_sqlite.inc diff -N includes/install.pdo_sqlite.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/install.pdo_sqlite.inc 31 Mar 2008 17:26:12 -0000 @@ -0,0 +1,153 @@ + PDO::ERRMODE_WARNING, + // Leave column names as returned by the database driver. + PDO::ATTR_CASE => PDO::CASE_NATURAL, + ); + + try { + $connection = new PDO($dsn, $username, $password, $driver_options); + } catch (PDOExecption $e) { + drupal_set_message(st('Failed to connect to your SQLite database server. SQLite reports the following message: %error.For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%error' => $e->getMessage())), 'error'); + return FALSE; + } + + // Modify the operation of the SQLite library + $connection->exec('PRAGMA SYNCHRONOUS = OFF'); + $connection->exec('PRAGMA SHORT_COLUMN_NAMES = 1'); + $connection->exec('PRAGMA TEMP_STORE = MEMORY'); + $connection->exec('PRAGMA CACHE_SIZE = 5120'); + $connection->exec('PRAGMA COUNT_CHANGES = OFF'); + $connection->exec('PRAGMA ENCODING = "UTF-8"'); + + $success = array('CONNECT'); + + // Test CREATE. + $query = 'CREATE TABLE "drupal_install_test" ("id" INTEGER)'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to create a test table on your SQLite database server with the command %query. SQLite reports the following message: %error.For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%query' => $query, '%error' => $error[2])), 'error'); + return FALSE; + } + $err = FALSE; + $success[] = 'SELECT'; + $success[] = 'CREATE'; + + // Test INSERT. + $query = 'INSERT INTO "drupal_install_test" ("id") VALUES (1)'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to insert a value into a test table on your SQLite database server. We tried inserting a value with the command %query and SQLite reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'INSERT'; + } + + // Test UPDATE. + $query = 'UPDATE "drupal_install_test" SET "id" = 2'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to update a value in a test table on your SQLite database server. We tried updating a value with the command %query and SQLite reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'UPDATE'; + } + + // Test LOCK. + $query = 'BEGIN'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to lock a test table on your SQLite database server. We tried locking a table with the command %query and SQLite reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'LOCK'; + } + + // Test UNLOCK. + $query = 'COMMIT'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to unlock a test table on your SQLite database server. We tried unlocking a table with the command %query and SQLite reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'UNLOCK'; + } + + // Test DELETE. + $query = 'DELETE FROM "drupal_install_test"'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to delete a value from a test table on your SQLite database server. We tried deleting a value with the command %query and SQLite reported the following error: %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'DELETE'; + } + + // Test DROP. + $query = 'DROP TABLE "drupal_install_test"'; + $stmt = $connection->prepare($query); + $stmt->execute(); + $error = $stmt->errorInfo(); + if (is_array($error) && $error[0] != 0 && isset($error[2])) { + drupal_set_message(st('Failed to drop a test table from your SQLite database server. We tried dropping a table with the command %query and SQLite reported the following error %error.', array('%query' => $query, '%error' => $error[2])), 'error'); + $err = TRUE; + } + else { + $success[] = 'DROP'; + } + + if ($err) { + return FALSE; + } + + $connection = NULL; + return TRUE; +} Index: includes/install.pgsql.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/install.pgsql.inc,v retrieving revision 1.6 diff -u -p -r1.6 install.pgsql.inc --- includes/install.pgsql.inc 22 Oct 2007 15:22:39 -0000 1.6 +++ includes/install.pgsql.inc 31 Mar 2008 17:26:13 -0000 @@ -1,16 +1,16 @@
  • Are you sure the configured username has the necessary PostgreSQL permissions to create tables in the database?
  • For more help, see the Installation and upgrading handbook. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%query' => $query, '%error' => $error)), 'error'); @@ -66,7 +55,7 @@ function drupal_test_pgsql($url, &$succe $success[] = 'CREATE'; // Test INSERT. - $query = 'INSERT INTO drupal_install_test (id) VALUES (1)'; + $query = 'INSERT INTO "drupal_install_test" ("id") VALUES (1)'; $result = pg_query($connection, $query); if ($error = pg_result_error($result)) { drupal_set_message(st('Failed to insert a value into a test table on your PostgreSQL database server. We tried inserting a value with the command %query and PostgreSQL reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error'); @@ -77,7 +66,7 @@ function drupal_test_pgsql($url, &$succe } // Test UPDATE. - $query = 'UPDATE drupal_install_test SET id = 2'; + $query = 'UPDATE "drupal_install_test" SET "id" = 2'; $result = pg_query($connection, $query); if ($error = pg_result_error($result)) { drupal_set_message(st('Failed to update a value in a test table on your PostgreSQL database server. We tried updating a value with the command %query and PostgreSQL reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error'); @@ -88,7 +77,7 @@ function drupal_test_pgsql($url, &$succe } // Test LOCK. - $query = 'BEGIN; LOCK drupal_install_test IN SHARE ROW EXCLUSIVE MODE'; + $query = 'LOCK "drupal_install_test" IN SHARE ROW EXCLUSIVE MODE'; $result = pg_query($connection, $query); if ($error = pg_result_error($result)) { drupal_set_message(st('Failed to lock a test table on your PostgreSQL database server. We tried locking a table with the command %query and PostgreSQL reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error'); @@ -98,7 +87,7 @@ function drupal_test_pgsql($url, &$succe $success[] = 'LOCK'; } - // Test UNLOCK, which is done automatically upon transaction end in PostgreSQL + // Test UNLOCK. $query = 'COMMIT'; $result = pg_query($connection, $query); if ($error = pg_result_error()) { @@ -110,7 +99,7 @@ function drupal_test_pgsql($url, &$succe } // Test DELETE. - $query = 'DELETE FROM drupal_install_test'; + $query = 'DELETE FROM "drupal_install_test"'; $result = pg_query($connection, $query); if ($error = pg_result_error()) { drupal_set_message(st('Failed to delete a value from a test table on your PostgreSQL database server. We tried deleting a value with the command %query and PostgreSQL reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error'); @@ -121,7 +110,7 @@ function drupal_test_pgsql($url, &$succe } // Test DROP. - $query = 'DROP TABLE drupal_install_test'; + $query = 'DROP TABLE "drupal_install_test"'; $result = pg_query($connection, $query); if ($error = pg_result_error()) { drupal_set_message(st('Failed to drop a test table from your PostgreSQL database server. We tried dropping a table with the command %query and PostgreSQL reported the following error %error.', array('%query' => $query, '%error' => $error)), 'error'); @@ -137,4 +126,4 @@ function drupal_test_pgsql($url, &$succe pg_close($connection); return TRUE; -} \ No newline at end of file +} Index: includes/locale.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/locale.inc,v retrieving revision 1.174 diff -u -p -r1.174 locale.inc --- includes/locale.inc 9 Jan 2008 21:36:13 -0000 1.174 +++ includes/locale.inc 31 Mar 2008 17:26:19 -0000 @@ -116,7 +116,7 @@ function locale_languages_overview_form_ $language->enabled = 0; } $language->weight = $form_state['values']['weight'][$langcode]; - db_query("UPDATE {languages} SET enabled = %d, weight = %d WHERE language = '%s'", $language->enabled, $language->weight, $langcode); + db_query("UPDATE [{languages}] SET [enabled] = %d, [weight] = %d WHERE [language] = %s", $language->enabled, $language->weight, $langcode); $languages[$langcode] = $language; } drupal_set_message(t('Configuration saved.')); @@ -195,7 +195,7 @@ function locale_languages_custom_form() * Language code of the language to edit. */ function locale_languages_edit_form(&$form_state, $langcode) { - if ($language = db_fetch_object(db_query("SELECT * FROM {languages} WHERE language = '%s'", $langcode))) { + if ($language = db_fetch_object(db_query("SELECT * FROM [{languages}] WHERE [language] = %s", $langcode))) { $form = array(); _locale_languages_common_controls($form, $language); $form['submit'] = array( @@ -287,7 +287,7 @@ function _locale_languages_common_contro function locale_languages_predefined_form_validate($form, &$form_state) { $langcode = $form_state['values']['langcode']; - if ($duplicate = db_result(db_query("SELECT COUNT(*) FROM {languages} WHERE language = '%s'", $langcode)) != 0) { + if ($duplicate = db_result(db_query("SELECT COUNT(*) FROM [{languages}] WHERE [language] = %s", $langcode)) != 0) { form_set_error('langcode', t('The language %language (%code) already exists.', array('%language' => $form_state['values']['name'], '%code' => $langcode))); } @@ -338,13 +338,13 @@ function locale_languages_edit_form_vali if (!empty($form_state['values']['domain']) && !empty($form_state['values']['prefix'])) { form_set_error('prefix', t('Domain and path prefix values should not be set at the same time.')); } - if (!empty($form_state['values']['domain']) && $duplicate = db_fetch_object(db_query("SELECT language FROM {languages} WHERE domain = '%s' AND language != '%s'", $form_state['values']['domain'], $form_state['values']['langcode']))) { + if (!empty($form_state['values']['domain']) && $duplicate = db_fetch_object(db_query("SELECT [language] FROM [{languages}] WHERE [domain] = %s AND [language] <> %s", $form_state['values']['domain'], $form_state['values']['langcode']))) { form_set_error('domain', t('The domain (%domain) is already tied to a language (%language).', array('%domain' => $form_state['values']['domain'], '%language' => $duplicate->language))); } if (empty($form_state['values']['prefix']) && language_default('language') != $form_state['values']['langcode'] && empty($form_state['values']['domain'])) { form_set_error('prefix', t('Only the default language can have both the domain and prefix empty.')); } - if (!empty($form_state['values']['prefix']) && $duplicate = db_fetch_object(db_query("SELECT language FROM {languages} WHERE prefix = '%s' AND language != '%s'", $form_state['values']['prefix'], $form_state['values']['langcode']))) { + if (!empty($form_state['values']['prefix']) && $duplicate = db_fetch_object(db_query("SELECT language FROM [{languages}] WHERE [prefix] = %s AND [language] <> %s", $form_state['values']['prefix'], $form_state['values']['langcode']))) { form_set_error('prefix', t('The prefix (%prefix) is already tied to a language (%language).', array('%prefix' => $form_state['values']['prefix'], '%language' => $duplicate->language))); } } @@ -353,7 +353,7 @@ function locale_languages_edit_form_vali * Process the language editing form submission. */ function locale_languages_edit_form_submit($form, &$form_state) { - db_query("UPDATE {languages} SET name = '%s', native = '%s', domain = '%s', prefix = '%s', direction = %d WHERE language = '%s'", $form_state['values']['name'], $form_state['values']['native'], $form_state['values']['domain'], $form_state['values']['prefix'], $form_state['values']['direction'], $form_state['values']['langcode']); + db_query("UPDATE [{languages}] SET [name] = %s, [native] = %s, [domain] = %s, [prefix] = %s, [direction] = %d WHERE [language] = %s", $form_state['values']['name'], $form_state['values']['native'], $form_state['values']['domain'], $form_state['values']['prefix'], $form_state['values']['direction'], $form_state['values']['langcode']); $default = language_default(); if ($default->language == $form_state['values']['langcode']) { $properties = array('name', 'native', 'direction', 'enabled', 'plurals', 'formula', 'domain', 'prefix', 'weight'); @@ -411,13 +411,13 @@ function locale_languages_delete_form_su $languages = language_list(); if (isset($languages[$form_state['values']['langcode']])) { // Remove translations first. - db_query("DELETE FROM {locales_target} WHERE language = '%s'", $form_state['values']['langcode']); + db_query("DELETE FROM [{locales_target}] WHERE [language] = %s", $form_state['values']['langcode']); cache_clear_all('locale:'. $form_state['values']['langcode'], 'cache'); // With no translations, this removes existing JavaScript translations file. _locale_rebuild_js($form_state['values']['langcode']); // Remove the language. - db_query("DELETE FROM {languages} WHERE language = '%s'", $form_state['values']['langcode']); - db_query("UPDATE {node} SET language = '' WHERE language = '%s'", $form_state['values']['langcode']); + db_query("DELETE FROM [{languages}] WHERE [language] = %s", $form_state['values']['langcode']); + db_query("UPDATE [{node}] SET [language] = %s WHERE [language] = %s", '', $form_state['values']['langcode']); $variables = array('%locale' => $languages[$form_state['values']['langcode']]->name); drupal_set_message(t('The language %locale has been removed.', $variables)); watchdog('locale', 'The language %locale has been removed.', $variables); @@ -489,7 +489,7 @@ function locale_translate_overview_scree $headers = array_merge(array(t('Language')), array_values($groups)); // Collect summaries of all source strings in all groups. - $sums = db_query("SELECT COUNT(*) AS strings, textgroup FROM {locales_source} GROUP BY textgroup"); + $sums = db_query("SELECT COUNT(*) AS [strings], [textgroup] FROM [{locales_source}] GROUP BY [textgroup]"); $groupsums = array(); while ($group = db_fetch_object($sums)) { $groupsums[$group->textgroup] = $group->strings; @@ -505,7 +505,7 @@ function locale_translate_overview_scree } // Languages with at least one record in the locale table. - $translations = db_query("SELECT COUNT(*) AS translation, t.language, s.textgroup FROM {locales_source} s INNER JOIN {locales_target} t ON s.lid = t.lid GROUP BY textgroup, language"); + $translations = db_query("SELECT COUNT(*) AS [translation], t.[language], s.[textgroup] FROM [{locales_source}] s INNER JOIN [{locales_target}] t ON s.[lid] = t.[lid] GROUP BY [textgroup], [language]"); while ($data = db_fetch_object($translations)) { $ratio = (!empty($groupsums[$data->textgroup]) && $data->translation > 0) ? round(($data->translation/$groupsums[$data->textgroup])*100., 2) : 0; $rows[$data->language][$data->textgroup] = $data->translation .'/'. $groupsums[$data->textgroup] ." ($ratio%)"; @@ -768,7 +768,7 @@ function locale_translate_export_po_form */ function locale_translate_edit_form(&$form_state, $lid) { // Fetch source string, if possible. - $source = db_fetch_object(db_query('SELECT source, textgroup, location FROM {locales_source} WHERE lid = %d', $lid)); + $source = db_fetch_object(db_query('SELECT [source], [textgroup], [location] FROM [{locales_source}] WHERE [lid] = %d', $lid)); if (!$source) { drupal_set_message(t('String not found.'), 'error'); drupal_goto('admin/build/translate/search'); @@ -815,7 +815,7 @@ function locale_translate_edit_form(&$fo } // Fetch translations and fill in default values in the form. - $result = db_query("SELECT DISTINCT translation, language FROM {locales_target} WHERE lid = %d AND language != '%s'", $lid, $omit); + $result = db_query("SELECT DISTINCT [translation], [language] FROM [{locales_target}] WHERE [lid] = %d AND [language] <> %s", $lid, $omit); while ($translation = db_fetch_object($result)) { $form['translations'][$translation->language]['#default_value'] = $translation->translation; } @@ -831,19 +831,19 @@ function locale_translate_edit_form(&$fo function locale_translate_edit_form_submit($form, &$form_state) { $lid = $form_state['values']['lid']; foreach ($form_state['values']['translations'] as $key => $value) { - $translation = db_result(db_query("SELECT translation FROM {locales_target} WHERE lid = %d AND language = '%s'", $lid, $key)); + $translation = db_result(db_query("SELECT [translation] FROM [{locales_target}] WHERE [lid] = %d AND [language] = %s", $lid, $key)); if (!empty($value)) { // Only update or insert if we have a value to use. if (!empty($translation)) { - db_query("UPDATE {locales_target} SET translation = '%s' WHERE lid = %d AND language = '%s'", $value, $lid, $key); + db_query("UPDATE [{locales_target}] SET [translation] = %s WHERE [lid] = %d AND [language] = %s", $value, $lid, $key); } else { - db_query("INSERT INTO {locales_target} (lid, translation, language) VALUES (%d, '%s', '%s')", $lid, $value, $key); + db_query("INSERT INTO [{locales_target}] ([lid], [translation], [language]) VALUES (%d, %s, %s)", $lid, $value, $key); } } elseif (!empty($translation)) { // Empty translation entered: remove existing entry from database. - db_query("DELETE FROM {locales_target} WHERE lid = %d AND language = '%s'", $lid, $key); + db_query("DELETE FROM [{locales_target}] WHERE [lid] = %d AND [language] = %s", $lid, $key); } // Force JavaScript translation file recreation for this language. @@ -871,8 +871,8 @@ function locale_translate_edit_form_subm * Delete a language string. */ function locale_translate_delete($lid) { - db_query('DELETE FROM {locales_source} WHERE lid = %d', $lid); - db_query('DELETE FROM {locales_target} WHERE lid = %d', $lid); + db_query('DELETE FROM [{locales_source}] WHERE lid = %d', $lid); + db_query('DELETE FROM [{locales_target}] WHERE lid = %d', $lid); // Force JavaScript translation file recreation for all languages. _locale_invalidate_js(); cache_clear_all('locale:', 'cache', TRUE); @@ -924,7 +924,7 @@ function locale_add_language($langcode, $direction = isset($predefined[$langcode][2]) ? $predefined[$langcode][2] : LANGUAGE_LTR; } - db_query("INSERT INTO {languages} (language, name, native, direction, domain, prefix, enabled) VALUES ('%s', '%s', '%s', %d, '%s', '%s', %d)", $langcode, $name, $native, $direction, $domain, $prefix, $enabled); + db_query("INSERT INTO [{languages}] ([language], [name], [native], [direction], [domain], [prefix], [enabled]) VALUES (%s, %s, %s, %d, %s, %s, %d)", $langcode, $name, $native, $direction, $domain, $prefix, $enabled); // Only set it as default if enabled. if ($enabled && $default) { @@ -969,7 +969,7 @@ function _locale_import_po($file, $langc } // Check if we have the language already in the database. - if (!db_fetch_object(db_query("SELECT language FROM {languages} WHERE language = '%s'", $langcode))) { + if (!db_fetch_object(db_query("SELECT [language] FROM [{languages}] WHERE [language] = %s", $langcode))) { drupal_set_message(t('The language selected for import is not supported.'), 'error'); return FALSE; } @@ -1213,10 +1213,10 @@ function _locale_import_one_string($op, // Get the plural formula and update in database. if (isset($header["Plural-Forms"]) && $p = _locale_import_parse_plural_forms($header["Plural-Forms"], $file->filename)) { list($nplurals, $plural) = $p; - db_query("UPDATE {languages} SET plurals = %d, formula = '%s' WHERE language = '%s'", $nplurals, $plural, $lang); + db_query("UPDATE [{languages}] SET [plurals] = %d, [formula] = %s WHERE [language] = %s", $nplurals, $plural, $lang); } else { - db_query("UPDATE {languages} SET plurals = %d, formula = '%s' WHERE language = '%s'", 0, '', $lang); + db_query("UPDATE [{languages}] SET [plurals] = %d, [formula] = %s WHERE [language] = %s", 0, '', $lang); } $headerdone = TRUE; } @@ -1278,35 +1278,35 @@ function _locale_import_one_string($op, * The string ID of the existing string modified or the new string added. */ function _locale_import_one_string_db(&$report, $langcode, $source, $translation, $textgroup, $location, $mode, $plid = NULL, $plural = NULL) { - $lid = db_result(db_query("SELECT lid FROM {locales_source} WHERE source = '%s' AND textgroup = '%s'", $source, $textgroup)); + $lid = db_result(db_query("SELECT [lid] FROM [{locales_source}] WHERE [source] = %s AND [textgroup] = %s", $source, $textgroup)); if (!empty($translation)) { if ($lid) { // We have this source string saved already. - db_query("UPDATE {locales_source} SET location = '%s' WHERE lid = %d", $location, $lid); - $exists = (bool) db_result(db_query("SELECT lid FROM {locales_target} WHERE lid = %d AND language = '%s'", $lid, $langcode)); + db_query("UPDATE [{locales_source}] SET [location] = %s WHERE [lid] = %d", $location, $lid); + $exists = (bool) db_result(db_query("SELECT [lid] FROM [{locales_target}] WHERE [lid] = %d AND [language] = %s", $lid, $langcode)); if (!$exists) { // No translation in this language. - db_query("INSERT INTO {locales_target} (lid, language, translation, plid, plural) VALUES (%d, '%s', '%s', %d, %d)", $lid, $langcode, $translation, $plid, $plural); + db_query("INSERT INTO [{locales_target}] ([lid], [language], [translation], [plid], [plural]) VALUES (%d, %s, %s, %d, %d)", $lid, $langcode, $translation, $plid, $plural); $report[0]++; } else if ($mode == LOCALE_IMPORT_OVERWRITE) { // Translation exists, only overwrite if instructed. - db_query("UPDATE {locales_target} SET translation = '%s', plid = %d, plural = %d WHERE language = '%s' AND lid = %d", $translation, $plid, $plural, $langcode, $lid); + db_query("UPDATE [{locales_target}] SET [translation] = %s, [plid] = %d, [plural] = %d WHERE [language] = %s AND [lid] = %d", $translation, $plid, $plural, $langcode, $lid); $report[1]++; } } else { // No such source string in the database yet. - db_query("INSERT INTO {locales_source} (location, source, textgroup) VALUES ('%s', '%s', '%s')", $location, $source, $textgroup); - $lid = db_result(db_query("SELECT lid FROM {locales_source} WHERE source = '%s' AND textgroup = '%s'", $source, $textgroup)); - db_query("INSERT INTO {locales_target} (lid, language, translation, plid, plural) VALUES (%d, '%s', '%s', %d, %d)", $lid, $langcode, $translation, $plid, $plural); + db_query("INSERT INTO [{locales_source}] ([location], [source], [textgroup]) VALUES (%s, %s, %s)", $location, $source, $textgroup); + $lid = db_result(db_query("SELECT [lid] FROM [{locales_source}] WHERE [source] = %s AND [textgroup] = %s", $source, $textgroup)); + db_query("INSERT INTO [{locales_target}] ([lid], [language], [translation], [plid], [plural]) VALUES (%d, %s, %s, %d, %d)", $lid, $langcode, $translation, $plid, $plural); $report[0]++; } } elseif ($mode == LOCALE_IMPORT_OVERWRITE) { // Empty translation, remove existing if instructed. - db_query("DELETE FROM {locales_target} WHERE language = '%s' AND lid = %d AND plid = %d AND plural = %d", $translation, $langcode, $lid, $plid, $plural); + db_query("DELETE FROM [{locales_target}] WHERE [language] = %s AND [lid] = %d AND [plid] = %d AND [plural] = %d", $translation, $langcode, $lid, $plid, $plural); $report[2]++; } @@ -1642,7 +1642,7 @@ function _locale_parse_js_file($filepath // Remove the quotes and string concatenations from the string. $string = implode('', preg_split('~(?lid); + db_query("UPDATE [{locales_source}] SET [location] = %s WHERE [lid] = %d", $locations, $source->lid); } } else { // We don't have the source string yet, thus we insert it into the database. - db_query("INSERT INTO {locales_source} (location, source, textgroup) VALUES ('%s', '%s', 'default')", $filepath, $string); + db_query("INSERT INTO [{locales_source}] ([location], [source], [textgroup]) VALUES (%s, %s, 'default')", $filepath, $string); } } } @@ -1682,10 +1682,10 @@ function _locale_parse_js_file($filepath */ function _locale_export_get_strings($language = NULL, $group = 'default') { if (isset($language)) { - $result = db_query("SELECT s.lid, s.source, s.location, t.translation, t.plid, t.plural FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = '%s' WHERE s.textgroup = '%s' ORDER BY t.plid, t.plural", $language->language, $group); + $result = db_query("SELECT s.[lid], s.[source], s.[location], t.[translation], t.[plid], t.[plural] FROM [{locales_source}] s LEFT JOIN [{locales_target}] t ON s.[lid] = t.[lid] AND t.[language] = %s WHERE s.[textgroup] = %s ORDER BY t.[plid], t.[plural]", $language->language, $group); } else { - $result = db_query("SELECT s.lid, s.source, s.location, t.plid, t.plural FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid WHERE s.textgroup = '%s' ORDER BY t.plid, t.plural", $group); + $result = db_query("SELECT s.[lid], s.[source], s.[location], t.[plid], t.[plural] FROM [{locales_source}] s LEFT JOIN [{locales_target}] t ON s.[lid] = t.[lid] WHERE s.[textgroup] = %s ORDER BY t.[plid], t.[plural]", $group); } $strings = array(); while ($child = db_fetch_object($result)) { @@ -1913,41 +1913,41 @@ function _locale_translate_seek() { // We have at least one criterion to match if ($query = _locale_translate_seek_query()) { - $join = "SELECT s.source, s.location, s.lid, s.textgroup, t.translation, t.language FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid "; + $join = "SELECT s.[source], s.[location], s.[lid], s.[textgroup], t.[translation], t.[language] FROM [{locales_source}] s LEFT JOIN [{locales_target}] t ON s.[lid] = t.[lid] "; $arguments = array(); $limit_language = FALSE; // Compute LIKE section switch ($query['translation']) { case 'translated': - $where = "WHERE (t.translation LIKE '%%%s%%')"; - $orderby = "ORDER BY t.translation"; - $arguments[] = $query['string']; + $where = "WHERE (t.[translation] LIKE %s)"; + $orderby = "ORDER BY t.[translation]"; + $arguments[] = "%". $query['string'] ."%"; break; case 'untranslated': - $where = "WHERE (s.source LIKE '%%%s%%' AND t.translation IS NULL)"; - $orderby = "ORDER BY s.source"; - $arguments[] = $query['string']; + $where = "WHERE (s.[source] LIKE %s AND t.[translation] IS NULL)"; + $orderby = "ORDER BY s.[source]"; + $arguments[] = "%". $query['string'] ."%"; break; case 'all' : default: - $where = "WHERE (s.source LIKE '%%%s%%' OR t.translation LIKE '%%%s%%')"; + $where = "WHERE (s.[source] LIKE %s OR t.[translation] LIKE %s)"; $orderby = ''; - $arguments[] = $query['string']; - $arguments[] = $query['string']; + $arguments[] = "%". $query['string'] ."%"; + $arguments[] = "%". $query['string'] ."%"; break; } $grouplimit = ''; if (!empty($query['group']) && $query['group'] != 'all') { - $grouplimit = " AND s.textgroup = '%s'"; + $grouplimit = " AND s.[textgroup] = %s"; $arguments[] = $query['group']; } switch ($query['language']) { // Force search in source strings case "en": - $sql = $join ." WHERE s.source LIKE '%%%s%%' $grouplimit ORDER BY s.source"; - $arguments = array($query['string']); // $where is not used, discard its arguments + $sql = $join ." WHERE s.[source] LIKE %s $grouplimit ORDER BY s.[source]"; + $arguments = array("%". $query['string'] ."%"); // $where is not used, discard its arguments if (!empty($grouplimit)) { $arguments[] = $query['group']; } @@ -1958,7 +1958,7 @@ function _locale_translate_seek() { break; // Some different language default: - $sql = "$join AND t.language = '%s' $where $grouplimit $orderby"; + $sql = "$join AND t.[language] = %s $where $grouplimit $orderby"; array_unshift($arguments, $query['language']); // Don't show translation flags for other languages, we can't see them with this search. $limit_language = $query['language']; @@ -2068,7 +2068,7 @@ function _locale_rebuild_js($langcode = // Construct the array for JavaScript translations. // We sort on plural so that we have all plural forms before singular forms. - $result = db_query("SELECT s.lid, s.source, t.plid, t.plural, t.translation FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = '%s' WHERE s.location LIKE '%%.js%%' AND s.textgroup = 'default' ORDER BY t.plural DESC", $language->language); + $result = db_query("SELECT s.[lid], s.[source], t.[plid], t.[plural], t.[translation] FROM [{locales_source}] s LEFT JOIN [{locales_target}] t ON s.[lid] = t.[lid] AND t.[language] = %s WHERE s.[location] LIKE %s AND s.[textgroup] = 'default' ORDER BY t.[plural] DESC", $language->language, '%.js%'); $translations = $plurals = array(); while ($data = db_fetch_object($result)) { @@ -2143,14 +2143,14 @@ function _locale_rebuild_js($langcode = // Save the new JavaScript hash (or an empty value if the file // just got deleted). Act only if some operation was executed. if ($status) { - db_query("UPDATE {languages} SET javascript = '%s' WHERE language = '%s'", $language->javascript, $language->language); + db_query("UPDATE [{languages}] SET [javascript] = %s WHERE [language] = %s", $language->javascript, $language->language); // Update the default language variable if the default language has been altered. // This is necessary to keep the variable consistent with the database // version of the language and to prevent checking against an outdated hash. $default_langcode = language_default('language'); if ($default_langcode == $language->language) { - $default = db_fetch_object(db_query("SELECT * FROM {languages} WHERE language = '%s'", $default_langcode)); + $default = db_fetch_object(db_query("SELECT * FROM [{languages}] WHERE [language] = %s", $default_langcode)); variable_set('language_default', $default); } } @@ -2440,7 +2440,7 @@ function locale_batch_by_language($langc // Collect all files to import for all enabled modules and themes. $files = array(); $components = array(); - $query = "SELECT name, filename FROM {system} WHERE status = 1"; + $query = "SELECT [name], [filename] FROM [{system}] WHERE [status] = 1"; if (count($skip)) { $query .= " AND name NOT IN (". db_placeholders($skip, 'varchar') .")"; } @@ -2475,7 +2475,7 @@ function locale_batch_by_component($comp if (count($languages[1])) { $language_list = join('|', array_keys($languages[1])); // Collect all files to import for all $components. - $result = db_query("SELECT name, filename FROM {system} WHERE status = 1"); + $result = db_query("SELECT [name], [filename] FROM [{system}] WHERE [status] = 1"); while ($component = db_fetch_object($result)) { if (in_array($component->name, $components)) { // Collect all files for this component in all enabled languages, named @@ -2536,7 +2536,7 @@ function _locale_batch_build($files, $fi * Contains a list of files imported. */ function _locale_batch_import($filepath, &$context) { - // The filename is either {langcode}.po or {prefix}.{langcode}.po, so + // The filename is either [{langcode}].po or [{prefix}].[{langcode}].po, so // we can extract the language code to use for the import from the end. if (preg_match('!(/|\.)([^\./]+)\.po$!', $filepath, $langcode)) { $file = (object) array('filename' => basename($filepath), 'filepath' => $filepath); Index: includes/menu.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/menu.inc,v retrieving revision 1.255.2.7 diff -u -p -r1.255.2.7 menu.inc --- includes/menu.inc 12 Feb 2008 22:33:51 -0000 1.255.2.7 +++ includes/menu.inc 31 Mar 2008 17:26:27 -0000 @@ -197,7 +197,7 @@ define('MENU_MAX_DEPTH', 9); * array('node', '12345', 'edit'). * @return * An array which contains the ancestors and placeholders. Placeholders - * simply contain as many '%s' as the ancestors. + * simply contain as many %s as the ancestors. */ function menu_get_ancestors($parts) { $number_parts = count($parts); @@ -228,7 +228,7 @@ function menu_get_ancestors($parts) { $current .= '/'; } } - $placeholders[] = "'%s'"; + $placeholders[] = "%s"; $ancestors[] = $current; } return array($ancestors, $placeholders); @@ -313,7 +313,7 @@ function menu_get_item($path = NULL, $ro $parts = array_slice($original_map, 0, MENU_MAX_PARTS); list($ancestors, $placeholders) = menu_get_ancestors($parts); - if ($router_item = db_fetch_array(db_query_range('SELECT * FROM {menu_router} WHERE path IN ('. implode (',', $placeholders) .') ORDER BY fit DESC', $ancestors, 0, 1))) { + if ($router_item = db_fetch_array(db_query_range('SELECT * FROM [{menu_router}] WHERE [path] IN ('. implode (',', $placeholders) .') ORDER BY [fit] DESC', $ancestors, 0, 1))) { $map = _menu_translate($router_item, $original_map); if ($map === FALSE) { $router_items[$path] = FALSE; @@ -777,7 +777,7 @@ function menu_tree_all_data($menu_name = $cid = 'links:'. $menu_name .':all:'. $mlid; if (!isset($tree[$cid])) { - // If the static variable doesn't have the data, check {cache_menu}. + // If the static variable doesn't have the data, check [{cache_menu}]. $cache = cache_get($cid, 'cache_menu'); if ($cache && isset($cache->data)) { $data = $cache->data; @@ -793,7 +793,7 @@ function menu_tree_all_data($menu_name = } $args = array_unique($args); $placeholders = implode(', ', array_fill(0, count($args), '%d')); - $where = ' AND ml.plid IN ('. $placeholders .')'; + $where = ' AND ml.[plid] IN ('. $placeholders .')'; $parents = $args; $parents[] = $item['mlid']; } @@ -805,13 +805,13 @@ function menu_tree_all_data($menu_name = } array_unshift($args, $menu_name); // Select the links from the table, and recursively build the tree. We - // LEFT JOIN since there is no match in {menu_router} for an external + // LEFT JOIN since there is no match in [{menu_router}] for an external // link. $data['tree'] = menu_tree_data(db_query(" - SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type, m.description, ml.* - FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path - WHERE ml.menu_name = '%s'". $where ." - ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", $args), $parents); + SELECT m.[load_functions], m.[to_arg_functions], m.[access_callback], m.[access_arguments], m.[page_callback], m.[page_arguments], m.[title], m.[title_callback], m.[title_arguments], m.[type], m.[description], ml.* + FROM [{menu_links}] ml LEFT JOIN [{menu_router}] m ON m.[path] = ml.[router_path] + WHERE ml.[menu_name] = %s". $where ." + ORDER BY [p1] ASC, [p2] ASC, [p3] ASC, [p4] ASC, [p5] ASC, [p6] ASC, [p7] ASC, [p8] ASC, [p9] ASC", $args), $parents); $data['node_links'] = array(); menu_tree_collect_node_links($data['tree'], $data['node_links']); // Cache the data. @@ -849,7 +849,7 @@ function menu_tree_page_data($menu_name $cid = 'links:'. $menu_name .':page:'. $item['href'] .':'. (int)$item['access']; if (!isset($tree[$cid])) { - // If the static variable doesn't have the data, check {cache_menu}. + // If the static variable doesn't have the data, check [{cache_menu}]. $cache = cache_get($cid, 'cache_menu'); if ($cache && isset($cache->data)) { $data = $cache->data; @@ -859,17 +859,17 @@ function menu_tree_page_data($menu_name if ($item['access']) { // Check whether a menu link exists that corresponds to the current path. $args = array($menu_name, $item['href']); - $placeholders = "'%s'"; + $placeholders = "%s"; if (drupal_is_front_page()) { $args[] = ''; - $placeholders .= ", '%s'"; + $placeholders .= ", %s"; } - $parents = db_fetch_array(db_query("SELECT p1, p2, p3, p4, p5, p6, p7, p8 FROM {menu_links} WHERE menu_name = '%s' AND link_path IN (". $placeholders .")", $args)); + $parents = db_fetch_array(db_query("SELECT [p1], [p2], [p3], [p4], [p5], [p6], [p7], [p8] FROM [{menu_links}] WHERE [menu_name] = %s AND [link_path] IN (". $placeholders .")", $args)); if (empty($parents)) { // If no link exists, we may be on a local task that's not in the links. // TODO: Handle the case like a local task on a specific node in the menu. - $parents = db_fetch_array(db_query("SELECT p1, p2, p3, p4, p5, p6, p7, p8 FROM {menu_links} WHERE menu_name = '%s' AND link_path = '%s'", $menu_name, $item['tab_root'])); + $parents = db_fetch_array(db_query("SELECT [p1], [p2], [p3], [p4], [p5], [p6], [p7], [p8] FROM [{menu_links}] WHERE [menu_name] = %s AND [link_path] = %s", $menu_name, $item['tab_root'])); } // We always want all the top-level links with plid == 0. $parents[] = '0'; @@ -883,7 +883,7 @@ function menu_tree_page_data($menu_name // Collect all the links set to be expanded, and then add all of // their children to the list as well. do { - $result = db_query("SELECT mlid FROM {menu_links} WHERE menu_name = '%s' AND expanded = 1 AND has_children = 1 AND plid IN (". $placeholders .') AND mlid NOT IN ('. $placeholders .')', array_merge(array($menu_name), $args, $args)); + $result = db_query("SELECT [mlid] FROM [{menu_links}] WHERE [menu_name] = %s AND [expanded] = 1 AND [has_children] = 1 AND [plid] IN (". $placeholders .') AND [mlid] NOT IN ('. $placeholders .')', array_merge(array($menu_name), $args, $args)); $num_rows = FALSE; while ($item = db_fetch_array($result)) { $args[] = $item['mlid']; @@ -901,13 +901,13 @@ function menu_tree_page_data($menu_name $parents = array(); } // Select the links from the table, and recursively build the tree. We - // LEFT JOIN since there is no match in {menu_router} for an external + // LEFT JOIN since there is no match in [{menu_router}] for an external // link. $data['tree'] = menu_tree_data(db_query(" - SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type, m.description, ml.* - FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path - WHERE ml.menu_name = '%s' AND ml.plid IN (". $placeholders .") - ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", $args), $parents); + SELECT m.[load_functions], m.[to_arg_functions], m.[access_callback], m.[access_arguments], m.[page_callback], m.[page_arguments], m.[title], m.[title_callback], m.[title_arguments], m.[type], m.[description], ml.* + FROM [{menu_links}] ml LEFT JOIN [{menu_router}] m ON m.[path] = ml.[router_path] + WHERE ml.[menu_name] = %s AND ml.[plid] IN (". $placeholders .") + ORDER BY [p1] ASC, [p2] ASC, [p3] ASC, [p4] ASC, [p5] ASC, [p6] ASC, [p7] ASC, [p8] ASC, [p9] ASC", $args), $parents); $data['node_links'] = array(); menu_tree_collect_node_links($data['tree'], $data['node_links']); // Cache the data. @@ -950,7 +950,7 @@ function menu_tree_check_access(&$tree, // Use db_rewrite_sql to evaluate view access without loading each full node. $nids = array_keys($node_links); $placeholders = '%d'. str_repeat(', %d', count($nids) - 1); - $result = db_query(db_rewrite_sql("SELECT n.nid FROM {node} n WHERE n.status = 1 AND n.nid IN (". $placeholders .")"), $nids); + $result = db_query(db_rewrite_sql("SELECT n.[nid] FROM [{node}] n WHERE n.[status] = 1 AND n.[nid] IN (". $placeholders .")"), $nids); while ($node = db_fetch_array($result)) { $nid = $node['nid']; foreach ($node_links[$nid] as $mlid => $link) { @@ -1154,7 +1154,7 @@ function menu_get_names($reset = FALSE) if ($reset || empty($names)) { $names = array(); - $result = db_query("SELECT DISTINCT(menu_name) FROM {menu_links} ORDER BY menu_name"); + $result = db_query("SELECT DISTINCT([menu_name]) FROM [{menu_links}] ORDER BY [menu_name]"); while ($name = db_fetch_array($result)) { $names[] = $name['menu_name']; } @@ -1260,7 +1260,7 @@ function menu_local_tasks($level = 0, $r return ''; } // Get all tabs and the root page. - $result = db_query("SELECT * FROM {menu_router} WHERE tab_root = '%s' ORDER BY weight, title", $router_item['tab_root']); + $result = db_query("SELECT * FROM [{menu_router}] WHERE [tab_root] = %s ORDER BY [weight], [title]", $router_item['tab_root']); $map = arg(); $children = array(); $tasks = array(); @@ -1566,7 +1566,7 @@ function menu_get_active_title() { * rendering. */ function menu_link_load($mlid) { - if (is_numeric($mlid) && $item = db_fetch_array(db_query("SELECT m.*, ml.* FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path WHERE ml.mlid = %d", $mlid))) { + if (is_numeric($mlid) && $item = db_fetch_array(db_query("SELECT m.*, ml.* FROM [{menu_links}] ml LEFT JOIN [{menu_router}] m ON m.[path] = ml.[router_path] WHERE ml.[mlid] = %d", $mlid))) { _menu_link_translate($item); return $item; } @@ -1630,7 +1630,7 @@ function menu_router_build($reset = FALS $menu = $cache->data; } else { - db_query('DELETE FROM {menu_router}'); + db_query('DELETE FROM [{menu_router}]'); // We need to manually call each module so that we can know which module // a given item came from. $callbacks = array(); @@ -1663,7 +1663,7 @@ function _menu_link_build($item) { $item['hidden'] = 1; } // Note, we set this as 'system', so that we can be sure to distinguish all - // the menu links generated automatically from entries in {menu_router}. + // the menu links generated automatically from entries in [{menu_router}]. $item['module'] = 'system'; $item += array( 'menu_name' => 'navigation', @@ -1693,7 +1693,7 @@ function _menu_navigation_links_rebuild( array_multisort($sort, SORT_NUMERIC, $menu_links); foreach ($menu_links as $item) { - $existing_item = db_fetch_array(db_query("SELECT mlid, menu_name, plid, customized, has_children, updated FROM {menu_links} WHERE link_path = '%s' AND module = '%s'", $item['link_path'], 'system')); + $existing_item = db_fetch_array(db_query("SELECT [mlid], [menu_name], [plid], [customized], [has_children], [updated] FROM [{menu_links}] WHERE [link_path] = %s AND [module] = %s", $item['link_path'], 'system')); if ($existing_item) { $item['mlid'] = $existing_item['mlid']; $item['menu_name'] = $existing_item['menu_name']; @@ -1710,18 +1710,18 @@ function _menu_navigation_links_rebuild( $paths = array_keys($menu); // Updated items and customized items which router paths are gone need new // router paths. - $result = db_query("SELECT ml.link_path, ml.mlid, ml.router_path, ml.updated FROM {menu_links} ml WHERE ml.updated = 1 OR (router_path NOT IN ($placeholders) AND external = 0 AND customized = 1)", $paths); + $result = db_query("SELECT ml.[link_path], ml.[mlid], ml.[router_path], ml.[updated] FROM [{menu_links}] ml WHERE ml.[updated] = 1 OR ([router_path] NOT IN ($placeholders) AND [external] = 0 AND [customized] = 1)", $paths); while ($item = db_fetch_array($result)) { $router_path = _menu_find_router_path($menu, $item['link_path']); if (!empty($router_path) && ($router_path != $item['router_path'] || $item['updated'])) { // If the router path and the link path matches, it's surely a working // item, so we clear the updated flag. $updated = $item['updated'] && $router_path != $item['link_path']; - db_query("UPDATE {menu_links} SET router_path = '%s', updated = %d WHERE mlid = %d", $router_path, $updated, $item['mlid']); + db_query("UPDATE [{menu_links}] SET [router_path] = %s, [updated] = %d WHERE [mlid] = %d", $router_path, $updated, $item['mlid']); } } // Find any items where their router path does not exist any more. - $result = db_query("SELECT * FROM {menu_links} WHERE router_path NOT IN ($placeholders) AND external = 0 AND updated = 0 AND customized = 0 ORDER BY depth DESC", $paths); + $result = db_query("SELECT * FROM [{menu_links}] WHERE [router_path] NOT IN ($placeholders) AND [external] = 0 AND [updated] = 0 AND [customized] = 0 ORDER BY [depth] DESC", $paths); // Remove all such items. Starting from those with the greatest depth will // minimize the amount of re-parenting done by menu_link_delete(). while ($item = db_fetch_array($result)) { @@ -1739,10 +1739,10 @@ function _menu_navigation_links_rebuild( */ function menu_link_delete($mlid, $path = NULL) { if (isset($mlid)) { - _menu_delete_item(db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE mlid = %d", $mlid))); + _menu_delete_item(db_fetch_array(db_query("SELECT * FROM [{menu_links}] WHERE [mlid] = %d", $mlid))); } else { - $result = db_query("SELECT * FROM {menu_links} WHERE link_path = '%s'", $path); + $result = db_query("SELECT * FROM [{menu_links}] WHERE [link_path] = %s", $path); while ($link = db_fetch_array($result)) { _menu_delete_item($link); } @@ -1761,14 +1761,14 @@ function _menu_delete_item($item, $force if ($item && ($item['module'] != 'system' || $item['updated'] || $force)) { // Children get re-attached to the item's parent. if ($item['has_children']) { - $result = db_query("SELECT mlid FROM {menu_links} WHERE plid = %d", $item['mlid']); + $result = db_query("SELECT [mlid] FROM [{menu_links}] WHERE [plid] = %d", $item['mlid']); while ($m = db_fetch_array($result)) { $child = menu_link_load($m['mlid']); $child['plid'] = $item['plid']; menu_link_save($child); } } - db_query('DELETE FROM {menu_links} WHERE mlid = %d', $item['mlid']); + db_query('DELETE FROM [{menu_links}] WHERE [mlid] = %d', $item['mlid']); // Update the has_children status of the parent. _menu_update_parental_status($item); @@ -1814,34 +1814,34 @@ function menu_link_save(&$item) { ); $existing_item = FALSE; if (isset($item['mlid'])) { - $existing_item = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE mlid = %d", $item['mlid'])); + $existing_item = db_fetch_array(db_query("SELECT * FROM [{menu_links}] WHERE [mlid] = %d", $item['mlid'])); } if (isset($item['plid'])) { - $parent = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE mlid = %d", $item['plid'])); + $parent = db_fetch_array(db_query("SELECT * FROM [{menu_links}] WHERE [mlid] = %d", $item['plid'])); } else { // Find the parent - it must be unique. $parent_path = $item['link_path']; - $where = "WHERE link_path = '%s'"; + $where = "WHERE [link_path] = %s"; // Only links derived from router items should have module == 'system', and // we want to find the parent even if it's in a different menu. if ($item['module'] == 'system') { - $where .= " AND module = '%s'"; + $where .= " AND [module] = %s"; $arg2 = 'system'; } else { // If not derived from a router item, we respect the specified menu name. - $where .= " AND menu_name = '%s'"; + $where .= " AND [menu_name] = %s"; $arg2 = $item['menu_name']; } do { $parent = FALSE; $parent_path = substr($parent_path, 0, strrpos($parent_path, '/')); - $result = db_query("SELECT COUNT(*) FROM {menu_links} ". $where, $parent_path, $arg2); + $result = db_query("SELECT COUNT(*) FROM [{menu_links}] ". $where, $parent_path, $arg2); // Only valid if we get a unique result. if (db_result($result) == 1) { - $parent = db_fetch_array(db_query("SELECT * FROM {menu_links} ". $where, $parent_path, $arg2)); + $parent = db_fetch_array(db_query("SELECT * FROM [{menu_links}] ". $where, $parent_path, $arg2)); } } while ($parent === FALSE && $parent_path); } @@ -1859,21 +1859,10 @@ function menu_link_save(&$item) { } if (!$existing_item) { - db_query("INSERT INTO {menu_links} ( - menu_name, plid, link_path, - hidden, external, has_children, - expanded, weight, - module, link_title, options, - customized, updated) VALUES ( - '%s', %d, '%s', - %d, %d, %d, - %d, %d, - '%s', '%s', '%s', %d, %d)", - $item['menu_name'], $item['plid'], $item['link_path'], - $item['hidden'], $item['_external'], $item['has_children'], - $item['expanded'], $item['weight'], - $item['module'], $item['link_title'], serialize($item['options']), - $item['customized'], $item['updated']); + $values = $item; + $values['external'] = $item['_external']; + $values['options'] = serialize($item['options']); + drupal_write_record('menu_links', $values); $item['mlid'] = db_last_insert_id('menu_links', 'mlid'); } @@ -1914,16 +1903,10 @@ function menu_link_save(&$item) { $item['router_path'] = _menu_find_router_path($menu, $item['link_path']); } } - db_query("UPDATE {menu_links} SET menu_name = '%s', plid = %d, link_path = '%s', - router_path = '%s', hidden = %d, external = %d, has_children = %d, - expanded = %d, weight = %d, depth = %d, - p1 = %d, p2 = %d, p3 = %d, p4 = %d, p5 = %d, p6 = %d, p7 = %d, p8 = %d, p9 = %d, - module = '%s', link_title = '%s', options = '%s', customized = %d WHERE mlid = %d", - $item['menu_name'], $item['plid'], $item['link_path'], - $item['router_path'], $item['hidden'], $item['_external'], $item['has_children'], - $item['expanded'], $item['weight'], $item['depth'], - $item['p1'], $item['p2'], $item['p3'], $item['p4'], $item['p5'], $item['p6'], $item['p7'], $item['p8'], $item['p9'], - $item['module'], $item['link_title'], serialize($item['options']), $item['customized'], $item['mlid']); + $values = $item; + $values['external'] = $item['_external']; + $values['options'] = serialize($item['options']); + drupal_write_record('menu_links', $values, 'mlid'); // Check the has_children status of the parent. _menu_update_parental_status($item); menu_cache_clear($menu_name); @@ -1962,7 +1945,7 @@ function _menu_clear_page_cache() { */ function _menu_set_expanded_menus() { $names = array(); - $result = db_query("SELECT menu_name FROM {menu_links} WHERE expanded != 0 GROUP BY menu_name"); + $result = db_query("SELECT [menu_name] FROM [{menu_links}] WHERE [expanded] <> 0 GROUP BY [menu_name]"); while ($n = db_fetch_array($result)) { $names[] = $n['menu_name']; } @@ -2021,7 +2004,7 @@ function menu_link_maintain($module, $op return menu_link_save($menu_link); break; case 'update': - db_query("UPDATE {menu_links} SET link_title = '%s' WHERE link_path = '%s' AND customized = 0 AND module = '%s'", $link_title, $link_path, $module); + db_query("UPDATE [{menu_links}] SET [link_title] = %s WHERE [link_path] = %s AND [customized] = 0 AND [module] = %s", $link_title, $link_path, $module); menu_cache_clear(); break; case 'delete': @@ -2048,12 +2031,12 @@ function menu_link_children_relative_dep $args[] = $item['menu_name']; $p = 'p1'; while ($i <= MENU_MAX_DEPTH && $item[$p]) { - $match .= " AND $p = %d"; + $match .= " AND [$p] = %d"; $args[] = $item[$p]; $p = 'p'. ++$i; } - $max_depth = db_result(db_query_range("SELECT depth FROM {menu_links} WHERE menu_name = '%s'". $match ." ORDER BY depth DESC", $args, 0, 1)); + $max_depth = db_result(db_query_range("SELECT [depth] FROM [{menu_links}] WHERE [menu_name] = %s". $match ." ORDER BY [depth] DESC", $args, 0, 1)); return ($max_depth > $item['depth']) ? $max_depth - $item['depth'] : 0; } @@ -2067,26 +2050,26 @@ function menu_link_children_relative_dep function _menu_link_move_children($item, $existing_item) { $args[] = $item['menu_name']; - $set[] = "menu_name = '%s'"; + $set[] = "[menu_name] = %s"; $i = 1; while ($i <= $item['depth']) { $p = 'p'. $i++; - $set[] = "$p = %d"; + $set[] = "[$p] = %d"; $args[] = $item[$p]; } $j = $existing_item['depth'] + 1; while ($i <= MENU_MAX_DEPTH && $j <= MENU_MAX_DEPTH) { - $set[] = 'p'. $i++ .' = p'. $j++; + $set[] = '[p'. $i++ .'] = [p'. $j++ .']'; } while ($i <= MENU_MAX_DEPTH) { - $set[] = 'p'. $i++ .' = 0'; + $set[] = '[p'. $i++ .'] = 0'; } $shift = $item['depth'] - $existing_item['depth']; if ($shift < 0) { $args[] = -$shift; - $set[] = 'depth = depth - %d'; + $set[] = '[depth] = [depth] - %d'; } elseif ($shift > 0) { // The order of $set must be reversed so the new values don't overwrite the @@ -2097,17 +2080,17 @@ function _menu_link_move_children($item, $args = array_reverse($args); $args[] = $shift; - $set[] = 'depth = depth + %d'; + $set[] = '[depth] = [depth] + %d'; } - $where[] = "menu_name = '%s'"; + $where[] = "[menu_name] = %s"; $args[] = $existing_item['menu_name']; $p = 'p1'; for ($i = 1; $i <= MENU_MAX_DEPTH && $existing_item[$p]; $p = 'p'. ++$i) { - $where[] = "$p = %d"; + $where[] = "[$p] = %d"; $args[] = $existing_item[$p]; } - db_query("UPDATE {menu_links} SET ". implode(', ', $set) ." WHERE ". implode(' AND ', $where), $args); + db_query("UPDATE [{menu_links}] SET ". implode(', ', $set) ." WHERE ". implode(' AND ', $where), $args); // Check the has_children status of the parent, while excluding this item. _menu_update_parental_status($existing_item, TRUE); } @@ -2119,10 +2102,10 @@ function _menu_update_parental_status($i // If plid == 0, there is nothing to update. if ($item['plid']) { // We may want to exclude the passed link as a possible child. - $where = $exclude ? " AND mlid != %d" : ''; + $where = $exclude ? " AND [mlid] != %d" : ''; // Check if at least one visible child exists in the table. - $parent_has_children = (bool)db_result(db_query_range("SELECT mlid FROM {menu_links} WHERE menu_name = '%s' AND plid = %d AND hidden = 0". $where, $item['menu_name'], $item['plid'], $item['mlid'], 0, 1)); - db_query("UPDATE {menu_links} SET has_children = %d WHERE mlid = %d", $parent_has_children, $item['plid']); + $parent_has_children = (bool)db_result(db_query_range("SELECT [mlid] FROM [{menu_links}] WHERE [menu_name] = %s AND [plid] = %d AND [hidden] = 0". $where, $item['menu_name'], $item['plid'], $item['mlid'], 0, 1)); + db_query("UPDATE [{menu_links}] SET [has_children] = %d WHERE [mlid] = %d", $parent_has_children, $item['plid']); } } @@ -2306,23 +2289,19 @@ function _menu_router_build($callbacks) $item['include file'] = $file_path .'/'. $item['file']; } - $title_arguments = $item['title arguments'] ? serialize($item['title arguments']) : ''; - db_query("INSERT INTO {menu_router} - (path, load_functions, to_arg_functions, access_callback, - access_arguments, page_callback, page_arguments, fit, - number_parts, tab_parent, tab_root, - title, title_callback, title_arguments, - type, block_callback, description, position, weight, file) - VALUES ('%s', '%s', '%s', '%s', - '%s', '%s', '%s', %d, - %d, '%s', '%s', - '%s', '%s', '%s', - %d, '%s', '%s', '%s', %d, '%s')", - $path, $item['load_functions'], $item['to_arg_functions'], $item['access callback'], - serialize($item['access arguments']), $item['page callback'], serialize($item['page arguments']), $item['_fit'], - $item['_number_parts'], $item['tab_parent'], $item['tab_root'], - $item['title'], $item['title callback'], $title_arguments, - $item['type'], $item['block callback'], $item['description'], $item['position'], $item['weight'], $item['include file']); + $values = $item; + $values['path'] = $path; + $values['access_callback'] = $item['access callback']; + $values['access_arguments'] = serialize($item['access arguments']); + $values['page_callback'] = $item['page callback']; + $values['page_arguments'] = serialize($item['page arguments']); + $values['fit'] = $item['_fit']; + $values['number_parts'] = $item['_number_parts']; + $values['title_callback'] = $item['title callback']; + $values['title_arguments'] = $item['title arguments'] ? serialize($item['title arguments']) : ''; + $values['block_callback'] = $item['block callback']; + $values['file'] = $item['include file']; + drupal_write_record('menu_router', $values); } // Sort the masks so they are in order of descending fit, and store them. $masks = array_keys($masks); @@ -2393,7 +2372,7 @@ function menu_valid_path($form_item) { } elseif (preg_match('/\/\%/', $path)) { // Path is dynamic (ie 'user/%'), so check directly against menu_router table. - if ($item = db_fetch_array(db_query("SELECT * FROM {menu_router} where path = '%s' ", $path))) { + if ($item = db_fetch_array(db_query("SELECT * FROM [{menu_router}] WHERE [path] = %s ", $path))) { $item['link_path'] = $form_item['link_path']; $item['link_title'] = $form_item['link_title']; $item['external'] = FALSE; Index: includes/module.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/module.inc,v retrieving revision 1.115 diff -u -p -r1.115 module.inc --- includes/module.inc 27 Dec 2007 12:31:05 -0000 1.115 +++ includes/module.inc 31 Mar 2008 17:26:29 -0000 @@ -58,10 +58,10 @@ function module_list($refresh = FALSE, $ } else { if ($bootstrap) { - $result = db_query("SELECT name, filename, throttle FROM {system} WHERE type = 'module' AND status = 1 AND bootstrap = 1 ORDER BY weight ASC, filename ASC"); + $result = db_query("SELECT [name], [filename], [throttle] FROM [{system}] WHERE [type] = 'module' AND [status] = 1 AND [bootstrap] = 1 ORDER BY [weight] ASC, [filename] ASC"); } else { - $result = db_query("SELECT name, filename, throttle FROM {system} WHERE type = 'module' AND status = 1 ORDER BY weight ASC, filename ASC"); + $result = db_query("SELECT [name], [filename], [throttle] FROM [{system}] WHERE [type] = 'module' AND [status] = 1 ORDER BY [weight] ASC, [filename] ASC"); } while ($module = db_fetch_object($result)) { if (file_exists($module->filename)) { @@ -138,13 +138,13 @@ function module_rebuild_cache() { // Update the contents of the system table: if (isset($file->status) || (isset($file->old_filename) && $file->old_filename != $file->filename)) { - db_query("UPDATE {system} SET info = '%s', name = '%s', filename = '%s', bootstrap = %d WHERE filename = '%s'", serialize($files[$filename]->info), $file->name, $file->filename, $bootstrap, $file->old_filename); + db_query("UPDATE [{system}] SET [info] = %s, [name] = %s, [filename] = %s, [bootstrap] = %d WHERE [filename] = %s", serialize($files[$filename]->info), $file->name, $file->filename, $bootstrap, $file->old_filename); } else { // This is a new module. $files[$filename]->status = 0; $files[$filename]->throttle = 0; - db_query("INSERT INTO {system} (name, info, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)", $file->name, serialize($files[$filename]->info), 'module', $file->filename, 0, 0, $bootstrap); + db_query("INSERT INTO [{system}] ([name], [info], [type], [filename], [status], [throttle], [bootstrap]) VALUES (%s, %s, %s, %s, %d, %d, %d)", $file->name, serialize($files[$filename]->info), 'module', $file->filename, 0, 0, $bootstrap); } } $files = _module_build_dependencies($files); @@ -286,10 +286,10 @@ function module_load_all_includes($type, function module_enable($module_list) { $invoke_modules = array(); foreach ($module_list as $module) { - $existing = db_fetch_object(db_query("SELECT status FROM {system} WHERE type = '%s' AND name = '%s'", 'module', $module)); + $existing = db_fetch_object(db_query("SELECT [status] FROM [{system}] WHERE [type] = %s AND [name] = %s", 'module', $module)); if ($existing->status == 0) { module_load_install($module); - db_query("UPDATE {system} SET status = %d, throttle = %d WHERE type = '%s' AND name = '%s'", 1, 0, 'module', $module); + db_query("UPDATE [{system}] SET [status] = %d, [throttle] = %d WHERE [type] = %s AND [name] = %s", 1, 0, 'module', $module); drupal_load('module', $module); $invoke_modules[] = $module; } @@ -331,7 +331,7 @@ function module_disable($module_list) { module_load_install($module); module_invoke($module, 'disable'); - db_query("UPDATE {system} SET status = %d, throttle = %d WHERE type = '%s' AND name = '%s'", 0, 0, 'module', $module); + db_query("UPDATE [{system}] SET [status] = %d, [throttle] = %d WHERE [type] = %s AND [name] = %s", 0, 0, 'module', $module); $invoke_modules[] = $module; } } Index: includes/path.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/path.inc,v retrieving revision 1.19 diff -u -p -r1.19 path.inc --- includes/path.inc 4 Nov 2007 16:42:45 -0000 1.19 +++ includes/path.inc 31 Mar 2008 17:26:30 -0000 @@ -52,7 +52,7 @@ function drupal_lookup_path($action, $pa // Use $count to avoid looking up paths in subsequent calls if there simply are no aliases if (!isset($count)) { - $count = db_result(db_query('SELECT COUNT(pid) FROM {url_alias}')); + $count = db_result(db_query('SELECT COUNT([pid]) FROM [{url_alias}]')); } if ($action == 'wipe') { @@ -65,7 +65,7 @@ function drupal_lookup_path($action, $pa return $map[$path_language][$path]; } // Get the most fitting result falling back with alias without language - $alias = db_result(db_query("SELECT dst FROM {url_alias} WHERE src = '%s' AND language IN('%s', '') ORDER BY language DESC", $path, $path_language)); + $alias = db_result(db_query("SELECT [dst] FROM [{url_alias}] WHERE [src] = %s AND [language] IN (%s, %s) ORDER BY [language] DESC", $path, $path_language, '')); $map[$path_language][$path] = $alias; return $alias; } @@ -76,7 +76,7 @@ function drupal_lookup_path($action, $pa $src = ''; if (!isset($map[$path_language]) || !($src = array_search($path, $map[$path_language]))) { // Get the most fitting result falling back with alias without language - if ($src = db_result(db_query("SELECT src FROM {url_alias} WHERE dst = '%s' AND language IN('%s', '') ORDER BY language DESC", $path, $path_language))) { + if ($src = db_result(db_query("SELECT [src] FROM [{url_alias}] WHERE [dst] = %s AND [language] IN (%s, %s) ORDER BY [language] DESC", $path, $path_language, ''))) { $map[$path_language][$src] = $path; } else { Index: includes/schema.db2.inc =================================================================== RCS file: includes/schema.db2.inc diff -N includes/schema.db2.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/schema.db2.inc 31 Mar 2008 17:26:30 -0000 @@ -0,0 +1,413 @@ + 'VARCHAR', + 'char:normal' => 'CHAR', + + 'text:tiny' => 'VARCHAR(4000)', + 'text:small' => 'VARCHAR(4000)', + 'text:medium' => 'VARCHAR(4000)', + 'text:big' => 'VARCHAR(4000)', + 'text:normal' => 'VARCHAR(4000)', + + 'serial:tiny' => 'INTEGER', + 'serial:small' => 'INTEGER', + 'serial:medium' => 'INTEGER', + 'serial:big' => 'BIGINT', + 'serial:normal' => 'INTEGER', + + 'int:tiny' => 'SMALLINT', + 'int:small' => 'SMALLINT', + 'int:medium' => 'INTEGER', + 'int:big' => 'BIGINT', + 'int:normal' => 'INTEGER', + + 'float:tiny' => 'REAL', + 'float:small' => 'REAL', + 'float:medium' => 'REAL', + 'float:big' => 'DOUBLE', + 'float:normal' => 'REAL', + + 'numeric:normal' => 'NUMERIC', + + 'blob:big' => 'BLOB(2G)', + 'blob:normal' => 'BLOB(2G)', + + 'datetime:normal' => 'TIMESTAMP', + ); + return $map; +} + +/** + * Generate SQL to create a new table from a Drupal schema definition. + * + * @param $name + * The name of the table to create. + * @param $table + * A Schema API table definition array. + * @return + * An array of SQL statements to create the table. + */ +function db_create_table_sql($name, $table) { + $sql_keys = array(); + if (isset($table['primary key']) && is_array($table['primary key'])) { + $sql_keys[] = 'CONSTRAINT [pk_{' . $name . '}] PRIMARY KEY (['. implode('], [', $table['primary key']) .'])'; + } + if (isset($table['unique keys']) && is_array($table['unique keys'])) { + foreach ($table['unique keys'] as $key => $value) { + $sql_keys[] = 'CONSTRAINT [ix_{'. $name .'}_'. $key .'] UNIQUE (['. implode('], [', $value) .'])'; + } + } + + $sql_fields = array(); + foreach ($table['fields'] as $field_name => $field) { + $sql_fields[] = _db_create_field_sql($field_name, _db_process_field($field)); + } + + $sql = 'CREATE TABLE [{'. $name .'}] (' . "\n\t"; + $sql .= implode(",\n\t", $sql_fields); + if (count($sql_keys) > 0) { + $sql .= ",\n\t"; + } + $sql .= implode(",\n\t", $sql_keys); + $sql .= "\n)"; + $statements[] = $sql; + + if (isset($table['indexes']) && is_array($table['indexes'])) { + foreach ($table['indexes'] as $key => $value) { + $statements[] = _db_create_index_sql($name, $key, $value); + } + } + + return $statements; +} + +function _db_create_index_sql($table, $name, $fields) { + $ix = 'ix_{'. $table .'}_'. $name; + return 'CREATE INDEX ['. $ix .'] ON [{'. $table .'}] ('. _db_create_key_sql($fields) .')'; +} + +function _db_create_key_sql($fields) { + $ret = array(); + foreach ($fields as $field) { + $ret[] = is_array($field) ? '['. $field[0] .']' : '['. $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['db2_type'])) { + $map = db_type_map(); + $field['db2_type'] = $map[$field['type'] .':'. $field['size']]; + } + if ($field['type'] == 'serial') { + unset($field['not null']); + } + 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['db2_type']; + + if ($spec['type'] == 'blob') { + $sql .= " NOT LOGGED NOT COMPACT"; + unset($spec['not null']); + } + + if (!empty($spec['length'])) { + $sql .= '('. $spec['length'] .')'; + } + elseif (isset($spec['precision']) && isset($spec['scale'])) { + $sql .= '('. $spec['precision'] .', '. $spec['scale'] .')'; + } + + if (isset($spec['not null']) && $spec['not null']) { + $sql .= ' NOT NULL'; + } + + if (isset($spec['default'])) { + if (($spec['type'] == 'blob') && ($spec['default'] == '')) { + $sql .= " DEFAULT EMPTY_BLOB()"; + } + else { + $default = is_string($spec['default']) ? "'". $spec['default'] ."'" : $spec['default']; + $sql .= " DEFAULT $default"; + } + } + + if (!empty($spec['unsigned'])) { + $sql .= ' CHECK ([' . $name . '] >= 0)'; + } + + if ($spec['type'] == 'serial') { + $sql .= ' GENERATED BY DEFAULT AS IDENTITY (START WITH +1 INCREMENT BY +1 NO CYCLE NO CACHE ORDER)'; + } + + return $sql; +} + +/** + * Rename a table. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be renamed. + * @param $new_name + * The new name for the table. + */ +function db_rename_table(&$ret, $table, $new_name) { + $ret[] = update_sql('RENAME TABLE [{'. $table .'}] TO [{'. $new_name .'}]'); +} + +/** + * 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 '; + $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 ['. $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 ['. $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) { + $pk = 'pk_{' . $table . '}'; + $ret[] = update_sql('ALTER TABLE [{'. $table .'}] ADD CONSTRAINT ['. $pk .'] PRIMARY KEY ([' . implode('], [', $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) { + $pk = 'pk_{' . $table . '}'; + $ret[] = update_sql('ALTER TABLE [{'. $table .'}] DROP CONSTRAINT ['. $pk .']'); +} + +/** + * Add a unique key. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the key. + * @param $fields + * An array of field names. + */ +function db_add_unique_key(&$ret, $table, $name, $fields) { + $ix = 'ix_{'. $table .'}_'. $name; + $ret[] = update_sql('ALTER TABLE [{' . $table . '}] ADD CONSTRAINT ['. $ix .'] UNIQUE ([' . implode('], [', $fields) . '])'); +} + +/** + * Drop a unique key. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the key. + */ +function db_drop_unique_key(&$ret, $table, $name) { + $ix = 'ix_{'. $table .'}_'. $name; + $ret[] = update_sql('ALTER TABLE [{'. $table .'}] DROP CONSTRAINT ['. $ix .']'); +} + +/** + * Add an index. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the index. + * @param $fields + * An array of field names. + */ +function db_add_index(&$ret, $table, $name, $fields) { + $ret[] = update_sql(_db_create_index_sql($table, $name, $fields)); +} + +/** + * Drop an index. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the index. + */ +function db_drop_index(&$ret, $table, $name) { + $name = 'ix_{'. $table .'}_'. $name; + $ret[] = update_sql('DROP INDEX ['. $name .']'); +} + +/** + * Change a field definition. + * + * Remember that changing a field definition involves adding a new field + * and dropping an old one. This means that any indices, primary keys and + * sequences from serial-type fields are dropped and might need to be + * recreated. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * Name of the table. + * @param $field + * Name of the field to change. + * @param $field_new + * New name for the field (set to the same as $field if you don't want to change the name). + * @param $spec + * The field specification for the new field. + */ +function db_change_field(&$ret, $table, $field, $field_new, $spec) { + // NOTE: DB2 don't support column rename query (known issue), so first of + // all we need to copy old column data to temp column, drop old column, and + // copy it back to new column. + db_add_field($ret, $table, "new_" . $field_new, $spec); + $ret[] = update_sql('UPDATE [{'. $table .'}] SET [new_'. $field_new ."] = [". $field .']'); + db_drop_field($ret, $table, $field); + db_add_field($ret, $table, "$field_new", $spec); + $ret[] = update_sql('UPDATE [{'. $table .'}] SET ['. $field_new ."] = [new_". $field .']'); + $not_null = isset($spec['not null']) ? $spec['not null'] : FALSE; + unset($spec['not null']); + if ($not_null) { + $ret[] = update_sql('ALTER TABLE [{'. $table .'}] ALTER ['. $field_new ."] SET NOT NULL"); + } + db_drop_field($ret, $table, "new_" . $field); +} + +/** + * @} End of "ingroup schemaapi". + */ Index: includes/schema.mysql.inc =================================================================== RCS file: includes/schema.mysql.inc diff -N includes/schema.mysql.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/schema.mysql.inc 31 Mar 2008 17:26:31 -0000 @@ -0,0 +1,491 @@ + 'VARCHAR', + 'char:normal' => 'CHAR', + + 'text:tiny' => 'TINYTEXT', + 'text:small' => 'TINYTEXT', + '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' => 'DECIMAL', + + 'blob:big' => 'LONGBLOB', + 'blob:normal' => 'BLOB', + + 'datetime:normal' => 'DATETIME', + ); + return $map; +} + +/** + * Generate SQL to create a new table from a Drupal schema definition. + * + * @param $name + * The name of the table to create. + * @param $table + * A Schema API table definition array. + * @return + * An array of SQL statements to create the table. + */ +function db_create_table_sql($name, $table) { + + if (empty($table['mysql_suffix'])) { + $table['mysql_suffix'] = "/*!40100 DEFAULT CHARACTER SET UTF8 */"; + } + + $sql = "CREATE TABLE [{". $name ."}] (\n"; + + // Add the SQL statement for each field. + foreach ($table['fields'] as $field_name => $field) { + $sql .= _db_create_field_sql($field_name, _db_process_field($field)) .", \n"; + } + + // Process keys & indexes. + $keys = _db_create_keys($table); + if (count($keys)) { + $sql .= implode(", \n", $keys) .", \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); +} + +function _db_create_keys($spec) { + $keys = array(); + + if (!empty($spec['primary key'])) { + $keys[] = 'PRIMARY KEY ('. _db_create_key_sql($spec['primary key']) .')'; + } + if (!empty($spec['unique keys'])) { + foreach ($spec['unique keys'] as $key => $fields) { + $keys[] = 'UNIQUE KEY ['. $key .'] ('. _db_create_key_sql($fields) .')'; + } + } + if (!empty($spec['indexes'])) { + foreach ($spec['indexes'] as $index => $fields) { + $keys[] = 'INDEX ['. $index .'] ('. _db_create_key_sql($fields) .')'; + } + } + + return $keys; +} + +/** + * 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 (($spec['type'] == 'text') || ($spec['type'] == 'blob')) { + unset($spec['default']); + } + + if (isset($spec['length'])) { + $sql .= '('. $spec['length'] .')'; + } + elseif (isset($spec['precision']) && isset($spec['scale'])) { + $sql .= '('. $spec['precision'] .', '. $spec['scale'] .')'; + } + + 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; +} + +/** + * Rename a table. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be renamed. + * @param $new_name + * The new name for the table. + */ +function db_rename_table(&$ret, $table, $new_name) { + $ret[] = update_sql('ALTER TABLE [{'. $table .'}] RENAME TO [{'. $new_name .'}]'); +} + +/** + * 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. + * The specification may also contain the key 'initial', the newly + * created field will be set to the value of the key in all rows. + * This is most useful for creating NOT NULL columns with no default + * value in existing tables. + * @param $keys_new + * Optional keys and indexes specification to be created on the + * table along with adding the field. The format is the same as a + * table specification but without the 'fields' element. If you are + * adding a type 'serial' field, you MUST specify at least one key + * or index including it in this array. @see db_change_field for more + * explanation why. + */ +function db_add_field(&$ret, $table, $field, $spec, $keys_new = array()) { + $fixnull = FALSE; + if (!empty($spec['not null']) && !isset($spec['default'])) { + $fixnull = TRUE; + $spec['not null'] = FALSE; + } + $query = 'ALTER TABLE [{'. $table .'}] ADD '; + $query .= _db_create_field_sql($field, _db_process_field($spec)); + if (count($keys_new)) { + $query .= ', ADD '. implode(', ADD ', _db_create_keys($keys_new)); + } + $ret[] = update_sql($query); + if (isset($spec['initial'])) { + // All this because update_sql does not support %-placeholders. + $sql = 'UPDATE [{'. $table .'}] SET ['. $field .'] = '. db_type_placeholder($spec['type']); + $result = db_query($sql, $spec['initial']); + $ret[] = array('success' => $result !== FALSE, 'query' => check_plain($sql .' ('. $spec['initial'] .')')); + } + if ($fixnull) { + $spec['not null'] = TRUE; + db_change_field($ret, $table, $field, $field, $spec); + } +} + +/** + * 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 + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the key. + * @param $fields + * An array of field names. + */ +function db_add_unique_key(&$ret, $table, $name, $fields) { + $ret[] = update_sql('ALTER TABLE [{'. $table .'}] ADD UNIQUE KEY '. $name .' ('. _db_create_key_sql($fields) .')'); +} + +/** + * Drop a unique key. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the key. + */ +function db_drop_unique_key(&$ret, $table, $name) { + $ret[] = update_sql('ALTER TABLE [{'. $table .'}] DROP KEY '. $name); +} + +/** + * Add an index. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the index. + * @param $fields + * An array of field names. + */ +function db_add_index(&$ret, $table, $name, $fields) { + $query = 'ALTER TABLE [{'. $table .'}] ADD INDEX ['. $name .'] ('. _db_create_key_sql($fields) .')'; + $ret[] = update_sql($query); +} + +/** + * Drop an index. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the index. + */ +function db_drop_index(&$ret, $table, $name) { + $ret[] = update_sql('ALTER TABLE [{'. $table .'}] DROP INDEX '. $name); +} + +/** + * Change a field definition. + * + * IMPORTANT NOTE: To maintain database portability, you have to explicitly + * recreate all indices and primary keys that are using the changed field. + * + * That means that you have to drop all affected keys and indexes with + * db_drop_{primary_key,unique_key,index}() before calling db_change_field(). + * To recreate the keys and indices, pass the key definitions as the + * optional $keys_new argument directly to db_change_field(). + * + * For example, suppose you have: + * @code + * $schema['foo'] = array( + * 'fields' => array( + * 'bar' => array('type' => 'int', 'not null' => TRUE) + * ), + * 'primary key' => array('bar') + * ); + * @endcode + * and you want to change foo.bar to be type serial, leaving it as the + * primary key. The correct sequence is: + * @code + * db_drop_primary_key($ret, 'foo'); + * db_change_field($ret, 'foo', 'bar', 'bar', + * array('type' => 'serial', 'not null' => TRUE), + * array('primary key' => array('bar'))); + * @endcode + * + * The reasons for this are due to the different database engines: + * + * On PostgreSQL, changing a field definition involves adding a new field + * and dropping an old one which* causes any indices, primary keys and + * sequences (from serial-type fields) that use the changed field to be dropped. + * + * On MySQL, all type 'serial' fields must be part of at least one key + * or index as soon as they are created. You cannot use + * db_add_{primary_key,unique_key,index}() for this purpose because + * the ALTER TABLE command will fail to add the column without a key + * or index specification. The solution is to use the optional + * $keys_new argument to create the key or index at the same time as + * field. + * + * You could use db_add_{primary_key,unique_key,index}() in all cases + * unless you are converting a field to be type serial. You can use + * the $keys_new argument in all cases. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * Name of the table. + * @param $field + * Name of the field to change. + * @param $field_new + * New name for the field (set to the same as $field if you don't want to change the name). + * @param $spec + * The field specification for the new field. + * @param $keys_new + * Optional keys and indexes specification to be created on the + * table along with changing the field. The format is the same as a + * table specification but without the 'fields' element. + */ + +function db_change_field(&$ret, $table, $field, $field_new, $spec, $keys_new = array()) { + $sql = 'ALTER TABLE [{'. $table .'}] CHANGE '. $field .' '. + _db_create_field_sql($field_new, _db_process_field($spec)); + if (count($keys_new)) { + $sql .= ', ADD '. implode(', ADD ', _db_create_keys($keys_new)); + } + $ret[] = update_sql($sql); +} + +/** + * @} End of "ingroup schemaapi". + */ Index: includes/schema.oracle.inc =================================================================== RCS file: includes/schema.oracle.inc diff -N includes/schema.oracle.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/schema.oracle.inc 31 Mar 2008 17:26:32 -0000 @@ -0,0 +1,545 @@ + 'VARCHAR2', + 'char:normal' => 'CHAR', + + 'text:tiny' => 'VARCHAR2(4000)', + 'text:small' => 'VARCHAR2(4000)', + 'text:medium' => 'VARCHAR2(4000)', + 'text:big' => 'VARCHAR2(4000)', + 'text:normal' => 'VARCHAR2(4000)', + + 'serial:tiny' => 'NUMBER(38)', + 'serial:small' => 'NUMBER(38)', + 'serial:medium' => 'NUMBER(38)', + 'serial:big' => 'NUMBER(38)', + 'serial:normal' => 'NUMBER(38)', + + 'int:tiny' => 'NUMBER(38)', + 'int:small' => 'NUMBER(38)', + 'int:medium' => 'NUMBER(38)', + 'int:big' => 'NUMBER(38)', + 'int:normal' => 'NUMBER(38)', + + 'float:tiny' => 'FLOAT(126)', + 'float:small' => 'FLOAT(126)', + 'float:medium' => 'FLOAT(126)', + 'float:big' => 'FLOAT(126)', + 'float:normal' => 'FLOAT(126)', + + 'numeric:normal' => 'NUMBER', + + 'blob:big' => 'BLOB', + 'blob:normal' => 'BLOB', + + 'datetime:normal' => 'TIMESTAMP', + ); + return $map; +} + +/** + * Generate SQL to create a new table from a Drupal schema definition. + * + * @param $name + * The name of the table to create. + * @param $table + * A Schema API table definition array. + * @return + * An array of SQL statements to create the table. + */ +function db_create_table_sql($name, $table) { + $sql_fields = array(); + foreach ($table['fields'] as $field_name => $field) { + $spec = _db_process_field($field); + $sql_fields[] = _db_create_field_sql($field_name, $spec); + if ($spec['type'] == 'serial') { + $table['serials'][] = $field_name; + } + } + + $sql_keys = array(); + if (isset($table['primary key']) && is_array($table['primary key'])) { + $sql_keys[] = 'CONSTRAINT [pk_{'. $name .'}] PRIMARY KEY (['. implode('], [', $table['primary key']) .'])'; + } + if (isset($table['unique keys']) && is_array($table['unique keys'])) { + foreach ($table['unique keys'] as $key => $value) { + $sql_keys[] = 'CONSTRAINT [ix_{'. $name .'}_'. $key .'] UNIQUE (['. implode('], [', $value) .'])'; + } + } + + $sql = "CREATE TABLE [{". $name ."}] (\n\t"; + $sql .= implode(",\n\t", $sql_fields); + if (count($sql_keys) > 0) { + $sql .= ",\n\t"; + } + $sql .= implode(",\n\t", $sql_keys); + $sql .= "\n)"; + $statements[] = $sql; + + if (isset($table['indexes']) && is_array($table['indexes'])) { + foreach ($table['indexes'] as $key => $value) { + $statements[] = _db_create_index_sql($name, $key, $value); + } + } + + if (isset($table['serials']) && is_array($table['serials'])) { + foreach ($table['serials'] as $key => $value) { + $statements[] = _db_create_sequence_sql($name, $value); + $statements[] = _db_create_trigger_sql($name, $value); + } + } + + return $statements; +} + +function _db_create_sequence_sql($table, $field) { + $seq = 'seq_{'. $table .'}_'. $field; + return "CREATE SEQUENCE [". $seq ."] MINVALUE 1 INCREMENT BY 1 START WITH 1 NOCACHE NOORDER NOCYCLE"; +} + +function _db_create_trigger_sql($table, $field) { + $tgr = 'tgr_{'. $table .'}_'. $field; + $seq = 'seq_{'. $table .'}_'. $field; + $query = "CREATE OR REPLACE TRIGGER [". $tgr ."]\n"; + $query .= "BEFORE INSERT ON [{". $table ."}]\n"; + $query .= "FOR EACH ROW\n"; + $query .= "BEGIN\n"; + $query .= "\tIF :NEW.[". $field ."] IS NULL THEN\n"; + $query .= "\t\tSELECT [". $seq ."].NEXTVAL\n"; + $query .= "\t\tINTO :NEW.[". $field ."]\n"; + $query .= "\t\tFROM DUAL;\n"; + $query .= "\tEND IF;\n"; + $query .= "END;"; + return $query; +} + +function _db_create_index_sql($table, $name, $fields) { + $ix = 'ix_{'. $table .'}_'. $name; + return 'CREATE INDEX ['. $ix .'] ON [{'. $table .'}] ('. _db_create_key_sql($fields) .')'; +} + +function _db_create_key_sql($fields) { + $ret = array(); + foreach ($fields as $field) { + if (is_array($field)) { + $ret[] = DB_SUBSTR .'(['. $field[0] .'], 1, '. $field[1] .')'; + } + else { + $ret[] = '['. $field .']'; + } + } + return implode(', ', $ret); +} + +function _db_create_keys(&$ret, $table, $key_news) { + if (isset($key_news['primary key'])) { + db_add_primary_key($ret, $table, $key_news['primary key']); + } + if (isset($key_news['unique keys'])) { + foreach ($key_news['unique keys'] as $name => $fields) { + db_add_unique_key($ret, $table, $name, $fields); + } + } + if (isset($key_news['indexes'])) { + foreach ($key_news['indexes'] as $name => $fields) { + db_add_index($ret, $table, $name, $fields); + } + } +} + +/** + * 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['oracle_type'])) { + $map = db_type_map(); + $field['oracle_type'] = $map[$field['type'] .':'. $field['size']]; + } + + if ($field['type'] == 'serial') { + unset($field['not null']); + } + + 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. + * @param $table + * Name of the table. Useful if required to create sequence and trigger. + * @param $extra_sql + * Array of extra queries. Useful if required to create sequence and trigger. + */ +function _db_create_field_sql($name, $spec) { + $sql = '['. $name .'] '. $spec['oracle_type']; + + if (!empty($spec['length'])) { + $sql .= '('. $spec['length'] .')'; + } + elseif (isset($spec['precision']) && isset($spec['scale'])) { + $sql .= '('. $spec['precision'] .', '. $spec['scale'] .')'; + } + + if (($spec['type'] == 'text') || ($spec['type'] == 'varchar')) { + if (isset($spec['not null']) && (!isset($spec['default']) || $spec['default'] == '')) { + $spec['default'] = ORACLE_EMPTY_STRING_PLACEHOLDER; + } + } + if (isset($spec['default'])) { + switch ($spec['type']) { + case 'blob': + $default = 'EMPTY_BLOB()'; + break; + case 'text': + case 'varchar': + $default = "'". $spec['default'] ."'"; + break; + default: + $default = is_string($spec['default']) ? "'". $spec['default'] ."'" : $spec['default']; + } + $sql .= " DEFAULT $default"; + } + + if (isset($spec['not null']) && $spec['not null']) { + $sql .= ' NOT NULL'; + } + + if (!empty($spec['unsigned'])) { + $sql .= ' CHECK (['. $name .'] >= 0)'; + } + + return $sql; +} + +/** + * Rename a table. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be renamed. + * @param $new_name + * The new name for the table. + */ +function db_rename_table(&$ret, $table, $new_name) { + $ret[] = update_sql('ALTER TABLE [{'. $table .'}] RENAME TO [{'. $new_name .'}]'); +} + +/** + * 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 .'}] CASCADE CONSTRAINTS'); +} + +/** + * 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. + * The specification may also contain the key 'initial', the newly + * created field will be set to the value of the key in all rows. + * This is most useful for creating NOT NULL columns with no default + * value in existing tables. + * @param $keys_new + * Optional keys and indexes specification to be created on the + * table along with adding the field. The format is the same as a + * table specification but without the 'fields' element. If you are + * adding a type 'serial' field, you MUST specify at least one key + * or index including it in this array. @see db_change_field for more + * explanation why. + */ +function db_add_field(&$ret, $table, $field, $spec, $keys_new = array()) { + $spec = _db_process_field($field); + $queries[] = 'ALTER TABLE [{'. $table .'}] ADD '. _db_create_field_sql($field, $spec); + if ($spec['type'] == 'serial') { + $queries[] = _db_create_sequence_sql($table, $field); + $queries[] = _db_create_trigger_sql($table, $field); + } + foreach ($queries as $query) { + $ret[] = update_sql($query); + } + if (isset($keys_new)) { + _db_create_keys($ret, $table, $keys_new); + } +} + +/** + * 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 COLUMN ['. $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 .'}] MODIFY (['. $field .'] 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 .'}] MODIFY (['. $field .'] DEFAULT NULL)'); +} + +/** + * 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) { + $pk = 'pk_{'. $table .'}'; + $ret[] = update_sql('ALTER TABLE [{'. $table .'}] ADD CONSTRAINT ['. $pk .'] PRIMARY KEY (['. implode('], [', $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) { + $pk = 'pk_{'. $table .'}'; + $ret[] = update_sql('ALTER TABLE [{'. $table .'}] DROP CONSTRAINT ['. $pk .']'); +} + +/** + * Add a unique key. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the key. + * @param $fields + * An array of field names. + */ +function db_add_unique_key(&$ret, $table, $name, $fields) { + $ix = 'ix_{'. $table .'}_'. $name; + $ret[] = update_sql('ALTER TABLE [{'. $table .'}] ADD CONSTRAINT ['. $ix .'] UNIQUE (['. implode('], [', $fields) .'])'); +} + +/** + * Drop a unique key. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the key. + */ +function db_drop_unique_key(&$ret, $table, $name) { + $ix = 'ix_{'. $table .'}_'. $name; + $ret[] = update_sql('ALTER TABLE [{'. $table .'}] DROP CONSTRAINT ['. $ix .']'); +} + +/** + * Add an index. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the index. + * @param $fields + * An array of field names. + * + * NOTE: Need to do some checking before add index, since + * Oracle don't allow create index on promary key. + */ +function db_add_index(&$ret, $table, $name, $fields) { + if (db_constraint_exists($table, $fields)) { + $ret[] = update_sql(_db_create_index_sql($table, $name, $fields)); + } +} + +/** + * Drop an index. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the index. + */ +function db_drop_index(&$ret, $table, $name) { + $ix = 'ix_{'. $table .'}_'. $name; + $ret[] = update_sql('DROP INDEX ['. $ix .']'); +} + +/** + * Change a field definition. + * + * IMPORTANT NOTE: To maintain database portability, you have to explicitly + * recreate all indices and primary keys that are using the changed field. + * + * That means that you have to drop all affected keys and indexes with + * db_drop_{primary_key,unique_key,index}() before calling db_change_field(). + * To recreate the keys and indices, pass the key definitions as the + * optional $keys_new argument directly to db_change_field(). + * + * For example, suppose you have: + * @code + * $schema['foo'] = array( + * 'fields' => array( + * 'bar' => array('type' => 'int', 'not null' => TRUE) + * ), + * 'primary key' => array('bar') + * ); + * @endcode + * and you want to change foo.bar to be type serial, leaving it as the + * primary key. The correct sequence is: + * @code + * db_drop_primary_key($ret, 'foo'); + * db_change_field($ret, 'foo', 'bar', 'bar', + * array('type' => 'serial', 'not null' => TRUE), + * array('primary key' => array('bar'))); + * @endcode + * + * The reasons for this are due to the different database engines: + * + * On PostgreSQL, changing a field definition involves adding a new field + * and dropping an old one which* causes any indices, primary keys and + * sequences (from serial-type fields) that use the changed field to be dropped. + * + * On MySQL, all type 'serial' fields must be part of at least one key + * or index as soon as they are created. You cannot use + * db_add_{primary_key,unique_key,index}() for this purpose because + * the ALTER TABLE command will fail to add the column without a key + * or index specification. The solution is to use the optional + * $keys_new argument to create the key or index at the same time as + * field. + * + * You could use db_add_{primary_key,unique_key,index}() in all cases + * unless you are converting a field to be type serial. You can use + * the $keys_new argument in all cases. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * Name of the table. + * @param $field + * Name of the field to change. + * @param $field_new + * New name for the field (set to the same as $field if you don't want to change the name). + * @param $spec + * The field specification for the new field. + * @param $key_news + * Optional keys and indexes specification to be created on the + * table along with changing the field. The format is the same as a + * table specification but without the 'fields' element. + */ +function db_change_field(&$ret, $table, $field, $field_new, $spec, $key_news = array()) { + $ret[] = update_sql("ALTER TABLE [{". $table ."}] RENAME $field TO [old_". $field .']'); + $not_null = isset($spec['not null']) ? $spec['not null'] : FALSE; + unset($spec['not null']); + + db_add_field($ret, $table, "$field_new", $spec); + + $ret[] = update_sql("UPDATE [{". $table ."}] SET [$field_new] = [old_". $field .']'); + + if ($not_null) { + $ret[] = update_sql("ALTER TABLE [{". $table ."}] ALTER [$field_new] SET NOT NULL"); + } + + db_drop_field($ret, $table, 'old_'. $field); + + if (isset($key_news)) { + _db_create_keys($ret, $table, $key_news); + } +} + +/** + * @} End of "ingroup schemaapi". + */ Index: includes/schema.postgresql.inc =================================================================== RCS file: includes/schema.postgresql.inc diff -N includes/schema.postgresql.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/schema.postgresql.inc 31 Mar 2008 17:26:33 -0000 @@ -0,0 +1,495 @@ + 'VARCHAR', + 'char:normal' => 'CHARACTER', + + 'text:tiny' => 'TEXT', + 'text:small' => 'TEXT', + 'text:medium' => 'TEXT', + 'text:big' => 'TEXT', + 'text:normal' => 'TEXT', + + 'serial:tiny' => 'SERIAL', + 'serial:small' => 'SERIAL', + 'serial:medium' => 'SERIAL', + 'serial:big' => 'BIGSERIAL', + 'serial:normal' => 'SERIAL', + + 'int:tiny' => 'SMALLINT', + 'int:small' => 'SMALLINT', + 'int:medium' => 'INT', + 'int:big' => 'BIGINT', + 'int:normal' => 'INT', + + 'float:tiny' => 'REAL', + 'float:small' => 'REAL', + 'float:medium' => 'REAL', + 'float:big' => 'DOUBLE PRECISION', + 'float:normal' => 'REAL', + + 'numeric:normal' => 'NUMERIC', + + 'blob:big' => 'BYTEA', + 'blob:normal' => 'BYTEA', + + 'datetime:normal' => 'TIMESTAMP', + ); + return $map; +} + +/** + * Generate SQL to create a new table from a Drupal schema definition. + * + * @param $name + * The name of the table to create. + * @param $table + * A Schema API table definition array. + * @return + * An array of SQL statements to create the table. + */ +function db_create_table_sql($name, $table) { + $sql_fields = array(); + foreach ($table['fields'] as $field_name => $field) { + $sql_fields[] = _db_create_field_sql($field_name, _db_process_field($field)); + } + + $sql_keys = array(); + if (isset($table['primary key']) && is_array($table['primary key'])) { + $sql_keys[] = 'PRIMARY KEY (['. implode('], [', $table['primary key']) .'])'; + } + if (isset($table['unique keys']) && is_array($table['unique keys'])) { + foreach ($table['unique keys'] as $key_name => $key) { + $sql_keys[] = 'CONSTRAINT [{'. $name .'}_'. $key_name .'_key] UNIQUE (['. implode('], [', $key) .'])'; + } + } + + $sql = "CREATE TABLE [{". $name ."}] (\n\t"; + $sql .= implode(",\n\t", $sql_fields); + if (count($sql_keys) > 0) { + $sql .= ",\n\t"; + } + $sql .= implode(",\n\t", $sql_keys); + $sql .= "\n)"; + $statements[] = $sql; + + if (isset($table['indexes']) && is_array($table['indexes'])) { + foreach ($table['indexes'] as $key_name => $key) { + $statements[] = _db_create_index_sql($name, $key_name, $key); + } + } + + return $statements; +} + +function _db_create_index_sql($table, $name, $fields) { + return 'CREATE INDEX [{'. $table .'}_'. $name .'_idx] ON [{'. $table .'}] ('. _db_create_key_sql($fields) .')'; +} + +function _db_create_key_sql($fields) { + $ret = array(); + foreach ($fields as $field) { + if (is_array($field)) { + $ret[] = DB_SUBSTR .'(['. $field[0] .'], 1, '. $field[1] .')'; + } + else { + $ret[] = '['. $field .']'; + } + } + return implode(', ', $ret); +} + +function _db_create_keys(&$ret, $table, $keys_new) { + if (isset($keys_new['primary key'])) { + db_add_primary_key($ret, $table, $keys_new['primary key']); + } + if (isset($keys_new['unique keys'])) { + foreach ($keys_new['unique keys'] as $name => $fields) { + db_add_unique_key($ret, $table, $name, $fields); + } + } + if (isset($keys_new['indexes'])) { + foreach ($keys_new['indexes'] as $name => $fields) { + db_add_index($ret, $table, $name, $fields); + } + } +} + +/** + * 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['postgresql_type'])) { + $map = db_type_map(); + $field['postgresql_type'] = $map[$field['type'] .':'. $field['size']]; + } + if ($field['type'] == 'serial') { + unset($field['not null']); + } + 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['postgresql_type']; + + if ($spec['type'] == 'serial') { + unset($spec['not null']); + } + + if (!empty($spec['unsigned'])) { + $sql .= " CHECK ([$name] >= 0)"; + } + + if (!empty($spec['length'])) { + $sql .= '('. $spec['length'] .')'; + } + elseif (isset($spec['precision']) && isset($spec['scale'])) { + $sql .= '('. $spec['precision'] .', '. $spec['scale'] .')'; + } + + if (isset($spec['not null']) && $spec['not null']) { + $sql .= ' NOT NULL'; + } + + if (isset($spec['default'])) { + $default = is_string($spec['default']) ? "'". $spec['default'] ."'" : $spec['default']; + $sql .= " DEFAULT $default"; + } + + return $sql; +} + +/** + * Rename a table. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be renamed. + * @param $new_name + * The new name for the table. + */ +function db_rename_table(&$ret, $table, $new_name) { + $ret[] = update_sql('ALTER TABLE [{'. $table .'}] RENAME TO [{'. $new_name .'}]'); +} + +/** + * 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. + * The specification may also contain the key 'initial', the newly + * created field will be set to the value of the key in all rows. + * This is most useful for creating NOT NULL columns with no default + * value in existing tables. + * @param $keys_new + * Optional keys and indexes specification to be created on the + * table along with adding the field. The format is the same as a + * table specification but without the 'fields' element. If you are + * adding a type 'serial' field, you MUST specify at least one key + * or index including it in this array. @see db_change_field for more + * explanation why. + */ +function db_add_field(&$ret, $table, $field, $spec, $keys_new = array()) { + $fixnull = FALSE; + if (!empty($spec['not null']) && !isset($spec['default'])) { + $fixnull = TRUE; + $spec['not null'] = FALSE; + } + $query = 'ALTER TABLE [{'. $table .'}] ADD COLUMN '; + $query .= _db_create_field_sql($field, _db_process_field($spec)); + $ret[] = update_sql($query); + if (isset($spec['initial'])) { + // All this because update_sql does not support %-placeholders. + $sql = 'UPDATE [{'. $table .'}] SET '. $field .' = '. db_type_placeholder($spec['type']); + $result = db_query($sql, $spec['initial']); + $ret[] = array('success' => $result !== FALSE, 'query' => check_plain($sql .' ('. $spec['initial'] .')')); + } + if ($fixnull) { + $ret[] = update_sql("ALTER TABLE [{". $table ."}] ALTER $field SET NOT NULL"); + } + if (isset($keys_new)) { + _db_create_keys($ret, $table, $keys_new); + } +} + +/** + * 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 COLUMN ['. $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 (['. implode('], [', $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 CONSTRAINT [{'. $table .'}_pkey]'); +} + +/** + * Add a unique key. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the key. + * @param $fields + * An array of field names. + */ +function db_add_unique_key(&$ret, $table, $name, $fields) { + $name = '{'. $table .'}_'. $name .'_key'; + $ret[] = update_sql('ALTER TABLE [{'. $table .'}] ADD CONSTRAINT ['. $name .'] UNIQUE (['. implode('], [', $fields) .'])'); +} + +/** + * Drop a unique key. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the key. + */ +function db_drop_unique_key(&$ret, $table, $name) { + $name = '{'. $table .'}_'. $name .'_key'; + $ret[] = update_sql('ALTER TABLE [{'. $table .'}] DROP CONSTRAINT ['. $name .']'); +} + +/** + * Add an index. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the index. + * @param $fields + * An array of field names. + */ +function db_add_index(&$ret, $table, $name, $fields) { + $ret[] = update_sql(_db_create_index_sql($table, $name, $fields)); +} + +/** + * Drop an index. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the index. + */ +function db_drop_index(&$ret, $table, $name) { + $name = '{'. $table .'}_'. $name .'_idx'; + $ret[] = update_sql('DROP INDEX ['. $name .']'); +} + +/** + * Change a field definition. + * + * IMPORTANT NOTE: To maintain database portability, you have to explicitly + * recreate all indices and primary keys that are using the changed field. + * + * That means that you have to drop all affected keys and indexes with + * db_drop_{primary_key,unique_key,index}() before calling db_change_field(). + * To recreate the keys and indices, pass the key definitions as the + * optional $keys_new argument directly to db_change_field(). + * + * For example, suppose you have: + * @code + * $schema['foo'] = array( + * 'fields' => array( + * 'bar' => array('type' => 'int', 'not null' => TRUE) + * ), + * 'primary key' => array('bar') + * ); + * @endcode + * and you want to change foo.bar to be type serial, leaving it as the + * primary key. The correct sequence is: + * @code + * db_drop_primary_key($ret, 'foo'); + * db_change_field($ret, 'foo', 'bar', 'bar', + * array('type' => 'serial', 'not null' => TRUE), + * array('primary key' => array('bar'))); + * @endcode + * + * The reasons for this are due to the different database engines: + * + * On PostgreSQL, changing a field definition involves adding a new field + * and dropping an old one which* causes any indices, primary keys and + * sequences (from serial-type fields) that use the changed field to be dropped. + * + * On MySQL, all type 'serial' fields must be part of at least one key + * or index as soon as they are created. You cannot use + * db_add_{primary_key,unique_key,index}() for this purpose because + * the ALTER TABLE command will fail to add the column without a key + * or index specification. The solution is to use the optional + * $keys_new argument to create the key or index at the same time as + * field. + * + * You could use db_add_{primary_key,unique_key,index}() in all cases + * unless you are converting a field to be type serial. You can use + * the $keys_new argument in all cases. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * Name of the table. + * @param $field + * Name of the field to change. + * @param $field_new + * New name for the field (set to the same as $field if you don't want to change the name). + * @param $spec + * The field specification for the new field. + * @param $keys_new + * Optional keys and indexes specification to be created on the + * table along with changing the field. The format is the same as a + * table specification but without the 'fields' element. + */ +function db_change_field(&$ret, $table, $field, $field_new, $spec, $keys_new = array()) { + $ret[] = update_sql("ALTER TABLE [{". $table ."}] RENAME [$field] TO [". $field ."_old]"); + $not_null = isset($spec['not null']) ? $spec['not null'] : FALSE; + unset($spec['not null']); + + db_add_field($ret, $table, "$field_new", $spec); + + $ret[] = update_sql("UPDATE [{". $table ."}] SET [$field_new] = [". $field ."_old]"); + + if ($not_null) { + $ret[] = update_sql("ALTER TABLE [{". $table ."}] ALTER [$field_new] SET NOT NULL"); + } + + db_drop_field($ret, $table, $field .'_old'); + + if (isset($keys_new)) { + _db_create_keys($ret, $table, $keys_new); + } +} + +/** + * @} End of "ingroup schemaapi". + */ Index: includes/schema.sqlite.inc =================================================================== RCS file: includes/schema.sqlite.inc diff -N includes/schema.sqlite.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/schema.sqlite.inc 31 Mar 2008 17:26:34 -0000 @@ -0,0 +1,511 @@ + 'TEXT', + 'char:normal' => 'TEXT', + + 'text:tiny' => 'TEXT', + 'text:small' => 'TEXT', + 'text:medium' => 'TEXT', + 'text:big' => 'TEXT', + 'text:normal' => 'TEXT', + + 'serial:tiny' => 'INTEGER', + 'serial:small' => 'INTEGER', + 'serial:medium' => 'INTEGER', + 'serial:big' => 'INTEGER', + 'serial:normal' => 'INTEGER', + + 'int:tiny' => 'INTEGER', + 'int:small' => 'INTEGER', + 'int:medium' => 'INTEGER', + 'int:big' => 'INTEGER', + 'int:normal' => 'INTEGER', + + 'float:tiny' => 'REAL', + 'float:small' => 'REAL', + 'float:medium' => 'REAL', + 'float:big' => 'REAL', + 'float:normal' => 'REAL', + + 'numeric:normal' => 'NUMERIC', + + 'blob:big' => 'BLOB', + 'blob:normal' => 'BLOB', + + 'datetime:normal' => 'TEXT', + ); + return $map; +} + +/** + * Generate SQL to create a new table from a Drupal schema definition. + * + * @param $name + * The name of the table to create. + * @param $table + * A Schema API table definition array. + * @return + * An array of SQL statements to create the table. + */ +function db_create_table_sql($name, $table) { + $sql_fields = array(); + foreach ($table['fields'] as $field_name => $field) { + if ($field['type'] == 'serial' && isset($table['primary key']) && in_array($field_name, $table['primary key'])) { + unset($table['primary key']); + } + $sql_fields[] = _db_create_field_sql($field_name, _db_process_field($field)); + } + + $sql_keys = array(); + if (isset($table['primary key']) && is_array($table['primary key'])) { + $sql_keys[] = 'PRIMARY KEY (['. implode('], [', $table['primary key']) .'])'; + } + if (isset($table['unique keys']) && is_array($table['unique keys'])) { + foreach ($table['unique keys'] as $key_name => $key) { + $sql_keys[] = 'UNIQUE (['. implode('], [', $key) .'])'; + } + } + + $sql = "CREATE TABLE [{". $name ."}] (\n\t"; + $sql .= implode(",\n\t", $sql_fields); + if (count($sql_keys) > 0) { + $sql .= ",\n\t"; + } + $sql .= implode(",\n\t", $sql_keys); + $sql .= "\n)"; + $statements[] = $sql; + + if (isset($table['indexes']) && is_array($table['indexes'])) { + foreach ($table['indexes'] as $key_name => $key) { + $statements[] = _db_create_index_sql($name, $key_name, $key); + } + } + + // In case of SQLite, use transection to ensure atomic CREATE TABLE. + return array_merge( + array('BEGIN'), + $statements, + array('COMMIT') + ); +} + +function _db_create_index_sql($table, $name, $fields) { + return 'CREATE INDEX [ix_{'. $table .'}_'. $name .'] ON [{'. $table .'}] ('. _db_create_key_sql($fields) .')'; +} + +function _db_create_key_sql($fields) { + $ret = array(); + foreach ($fields as $field) { + if (is_array($field)) { + $ret[] = '['. $field[0] .']'; + } + else { + $ret[] = '['. $field .']'; + } + } + return implode(', ', $ret); +} + +//function _db_create_keys(&$ret, $table, $keys_new) { +// if (isset($keys_new['primary key'])) { +// db_add_primary_key($ret, $table, $keys_new['primary key']); +// } +// if (isset($keys_new['unique keys'])) { +// foreach ($keys_new['unique keys'] as $name => $fields) { +// db_add_unique_key($ret, $table, $name, $fields); +// } +// } +// if (isset($keys_new['indexes'])) { +// foreach ($keys_new['indexes'] as $name => $fields) { +// db_add_index($ret, $table, $name, $fields); +// } +// } +//} + +/** + * 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['sqlite_type'])) { + $map = db_type_map(); + $field['sqlite_type'] = $map[$field['type'] .':'. $field['size']]; + } + + if ($field['type'] == 'serial') { + $field['auto_increment'] = TRUE; + } + + if ($field['type'] == 'varchar' || $field['type'] == 'char') { + unset($field['length']); + } + + 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['sqlite_type']; + + if (!empty($spec['auto_increment'])) { + $sql .= ' PRIMARY KEY AUTOINCREMENT'; + return $sql; + } + + if (!empty($spec['unsigned'])) { + $sql .= " CHECK ([$name] >= 0)"; + } + + if (!empty($spec['length'])) { + $sql .= '('. $spec['length'] .')'; + } + elseif (isset($spec['precision']) && isset($spec['scale'])) { + $sql .= '('. $spec['precision'] .', '. $spec['scale'] .')'; + } + + if (isset($spec['not null']) && $spec['not null']) { + $sql .= ' NOT NULL'; + } + + if (isset($spec['default'])) { + $default = is_string($spec['default']) ? "'". $spec['default'] ."'" : $spec['default']; + $sql .= " DEFAULT $default"; + } + + return $sql; +} + +/** + * Rename a table. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be renamed. + * @param $new_name + * The new name for the table. + */ +//function db_rename_table(&$ret, $table, $new_name) { +// $ret[] = update_sql('ALTER TABLE [{'. $table .'}] RENAME TO [{'. $new_name .'}]'); +//} + +/** + * 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. + * The specification may also contain the key 'initial', the newly + * created field will be set to the value of the key in all rows. + * This is most useful for creating NOT NULL columns with no default + * value in existing tables. + * @param $keys_new + * Optional keys and indexes specification to be created on the + * table along with adding the field. The format is the same as a + * table specification but without the 'fields' element. If you are + * adding a type 'serial' field, you MUST specify at least one key + * or index including it in this array. @see db_change_field for more + * explanation why. + */ +//function db_add_field(&$ret, $table, $field, $spec, $keys_new = array()) { +// $fixnull = FALSE; +// if (!empty($spec['not null']) && !isset($spec['default'])) { +// $fixnull = TRUE; +// $spec['not null'] = FALSE; +// } +// $query = 'ALTER TABLE [{'. $table .'}] ADD COLUMN '; +// $query .= _db_create_field_sql($field, _db_process_field($spec)); +// $ret[] = update_sql($query); +// if (isset($spec['initial'])) { +// // All this because update_sql does not support %-placeholders. +// $sql = 'UPDATE [{'. $table .'}] SET '. $field .' = '. db_type_placeholder($spec['type']); +// $result = db_query($sql, $spec['initial']); +// $ret[] = array('success' => $result !== FALSE, 'query' => check_plain($sql .' ('. $spec['initial'] .')')); +// } +// if ($fixnull) { +// $ret[] = update_sql("ALTER TABLE [{". $table ."}] ALTER $field SET NOT NULL"); +// } +// if (isset($keys_new)) { +// _db_create_keys($ret, $table, $keys_new); +// } +//} + +/** + * 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 COLUMN ['. $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 (['. implode('], [', $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 CONSTRAINT [{'. $table .'}_pkey]'); +//} + +/** + * Add a unique key. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the key. + * @param $fields + * An array of field names. + */ +//function db_add_unique_key(&$ret, $table, $name, $fields) { +// $name = '{'. $table .'}_'. $name .'_key'; +// $ret[] = update_sql('ALTER TABLE [{'. $table .'}] ADD CONSTRAINT ['. $name .'] UNIQUE (['. implode('], [', $fields) .'])'); +//} + +/** + * Drop a unique key. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the key. + */ +//function db_drop_unique_key(&$ret, $table, $name) { +// $name = '{'. $table .'}_'. $name .'_key'; +// $ret[] = update_sql('ALTER TABLE [{'. $table .'}] DROP CONSTRAINT ['. $name .']'); +//} + +/** + * Add an index. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the index. + * @param $fields + * An array of field names. + */ +//function db_add_index(&$ret, $table, $name, $fields) { +// $ret[] = update_sql(_db_create_index_sql($table, $name, $fields)); +//} + +/** + * Drop an index. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * The table to be altered. + * @param $name + * The name of the index. + */ +//function db_drop_index(&$ret, $table, $name) { +// $name = '{'. $table .'}_'. $name .'_idx'; +// $ret[] = update_sql('DROP INDEX ['. $name .']'); +//} + +/** + * Change a field definition. + * + * IMPORTANT NOTE: To maintain database portability, you have to explicitly + * recreate all indices and primary keys that are using the changed field. + * + * That means that you have to drop all affected keys and indexes with + * db_drop_{primary_key,unique_key,index}() before calling db_change_field(). + * To recreate the keys and indices, pass the key definitions as the + * optional $keys_new argument directly to db_change_field(). + * + * For example, suppose you have: + * @code + * $schema['foo'] = array( + * 'fields' => array( + * 'bar' => array('type' => 'int', 'not null' => TRUE) + * ), + * 'primary key' => array('bar') + * ); + * @endcode + * and you want to change foo.bar to be type serial, leaving it as the + * primary key. The correct sequence is: + * @code + * db_drop_primary_key($ret, 'foo'); + * db_change_field($ret, 'foo', 'bar', 'bar', + * array('type' => 'serial', 'not null' => TRUE), + * array('primary key' => array('bar'))); + * @endcode + * + * The reasons for this are due to the different database engines: + * + * On PostgreSQL, changing a field definition involves adding a new field + * and dropping an old one which* causes any indices, primary keys and + * sequences (from serial-type fields) that use the changed field to be dropped. + * + * On MySQL, all type 'serial' fields must be part of at least one key + * or index as soon as they are created. You cannot use + * db_add_{primary_key,unique_key,index}() for this purpose because + * the ALTER TABLE command will fail to add the column without a key + * or index specification. The solution is to use the optional + * $keys_new argument to create the key or index at the same time as + * field. + * + * You could use db_add_{primary_key,unique_key,index}() in all cases + * unless you are converting a field to be type serial. You can use + * the $keys_new argument in all cases. + * + * @param $ret + * Array to which query results will be added. + * @param $table + * Name of the table. + * @param $field + * Name of the field to change. + * @param $field_new + * New name for the field (set to the same as $field if you don't want to change the name). + * @param $spec + * The field specification for the new field. + * @param $keys_new + * Optional keys and indexes specification to be created on the + * table along with changing the field. The format is the same as a + * table specification but without the 'fields' element. + */ +//function db_change_field(&$ret, $table, $field, $field_new, $spec, $keys_new = array()) { +// $ret[] = update_sql("ALTER TABLE [{". $table ."}] RENAME [$field] TO [". $field ."_old]"); +// $not_null = isset($spec['not null']) ? $spec['not null'] : FALSE; +// unset($spec['not null']); +// +// db_add_field($ret, $table, "$field_new", $spec); +// +// $ret[] = update_sql("UPDATE [{". $table ."}] SET [$field_new] = [". $field ."_old]"); +// +// if ($not_null) { +// $ret[] = update_sql("ALTER TABLE [{". $table ."}] ALTER [$field_new] SET NOT NULL"); +// } +// +// db_drop_field($ret, $table, $field .'_old'); +// +// if (isset($keys_new)) { +// _db_create_keys($ret, $table, $keys_new); +// } +//} + +/** + * @} End of "ingroup schemaapi". + */ Index: includes/session.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/session.inc,v retrieving revision 1.44.2.1 diff -u -p -r1.44.2.1 session.inc --- includes/session.inc 7 Feb 2008 11:58:40 -0000 1.44.2.1 +++ includes/session.inc 31 Mar 2008 17:26:34 -0000 @@ -29,7 +29,7 @@ function sess_read($key) { } // Otherwise, if the session is still active, we have a record of the client's session in the database. - $user = db_fetch_object(db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = '%s'", $key)); + $user = db_fetch_object(db_query("SELECT u.*, s.* FROM [{users}] u INNER JOIN [{sessions}] s ON u.[uid] = s.[uid] WHERE s.[sid] = %s", $key)); // We found the client's session record and they are an authenticated user if ($user && $user->uid > 0) { @@ -39,7 +39,7 @@ function sess_read($key) { // Add roles element to $user $user->roles = array(); $user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; - $result = db_query("SELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = %d", $user->uid); + $result = db_query("SELECT r.[rid], r.[name] FROM [{role}] r INNER JOIN [{users_roles}] ur ON ur.[rid] = r.[rid] WHERE ur.[uid] = %d", $user->uid); while ($role = db_fetch_object($result)) { $user->roles[$role->rid] = $role->name; } @@ -62,7 +62,7 @@ function sess_write($key, $value) { return TRUE; } - $result = db_result(db_query("SELECT COUNT(*) FROM {sessions} WHERE sid = '%s'", $key)); + $result = db_result(db_query("SELECT COUNT(*) FROM [{sessions}] WHERE [sid] = %s", $key)); if (!$result) { // Only save session data when when the browser sends a cookie. This keeps @@ -70,16 +70,16 @@ function sess_write($key, $value) { // and gives more useful statistics. We can't eliminate anonymous session // table rows without breaking throttle module and "Who's Online" block. if ($user->uid || $value || count($_COOKIE)) { - db_query("INSERT INTO {sessions} (sid, uid, cache, hostname, session, timestamp) VALUES ('%s', %d, %d, '%s', '%s', %d)", $key, $user->uid, isset($user->cache) ? $user->cache : '', ip_address(), $value, time()); + db_query("INSERT INTO [{sessions}] ([sid], [uid], [cache], [hostname], [session], [timestamp]) VALUES (%s, %d, %d, %s, %s, %d)", $key, $user->uid, isset($user->cache) ? $user->cache : '', ip_address(), $value, time()); } } else { - db_query("UPDATE {sessions} SET uid = %d, cache = %d, hostname = '%s', session = '%s', timestamp = %d WHERE sid = '%s'", $user->uid, isset($user->cache) ? $user->cache : '', ip_address(), $value, time(), $key); + db_query("UPDATE [{sessions}] SET [uid] = %d, [cache] = %d, [hostname] = %s, [session] = %s, [timestamp] = %d WHERE [sid] = %s", $user->uid, isset($user->cache) ? $user->cache : '', ip_address(), $value, time(), $key); // Last access time is updated no more frequently than once every 180 seconds. // This reduces contention in the users table. if ($user->uid && time() - $user->access > variable_get('session_write_interval', 180)) { - db_query("UPDATE {users} SET access = %d WHERE uid = %d", time(), $user->uid); + db_query("UPDATE [{users}] SET [access] = %d WHERE [uid] = %d", time(), $user->uid); } } @@ -103,7 +103,7 @@ function sess_regenerate() { session_regenerate_id(); - db_query("UPDATE {sessions} SET sid = '%s' WHERE sid = '%s'", session_id(), $old_session_id); + db_query("UPDATE [{sessions}] SET [sid] = %s WHERE [sid] = %s", session_id(), $old_session_id); } /** @@ -120,8 +120,8 @@ function sess_regenerate() { * The number of users with sessions. */ function sess_count($timestamp = 0, $anonymous = true) { - $query = $anonymous ? ' AND uid = 0' : ' AND uid > 0'; - return db_result(db_query('SELECT COUNT(sid) AS count FROM {sessions} WHERE timestamp >= %d'. $query, $timestamp)); + $query = $anonymous ? ' AND [uid] = 0' : ' AND [uid] > 0'; + return db_result(db_query('SELECT COUNT([sid]) AS [count] FROM [{sessions}] WHERE [timestamp] >= %d'. $query, $timestamp)); } /** @@ -131,7 +131,7 @@ function sess_count($timestamp = 0, $ano * the session id */ function sess_destroy_sid($sid) { - db_query("DELETE FROM {sessions} WHERE sid = '%s'", $sid); + db_query("DELETE FROM [{sessions}] WHERE [sid] = %s", $sid); } /** @@ -141,7 +141,7 @@ function sess_destroy_sid($sid) { * the user id */ function sess_destroy_uid($uid) { - db_query('DELETE FROM {sessions} WHERE uid = %d', $uid); + db_query('DELETE FROM [{sessions}] WHERE [uid] = %d', $uid); } function sess_gc($lifetime) { @@ -150,7 +150,7 @@ function sess_gc($lifetime) { // for three weeks before deleting them, you need to set gc_maxlifetime // to '1814400'. At that value, only after a user doesn't log in after // three weeks (1814400 seconds) will his/her session be removed. - db_query("DELETE FROM {sessions} WHERE timestamp < %d", time() - $lifetime); + db_query("DELETE FROM [{sessions}] WHERE [timestamp] < %d", time() - $lifetime); return TRUE; } Index: includes/tablesort.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/tablesort.inc,v retrieving revision 1.47 diff -u -p -r1.47 tablesort.inc --- includes/tablesort.inc 4 Jan 2008 09:31:48 -0000 1.47 +++ includes/tablesort.inc 31 Mar 2008 17:26:34 -0000 @@ -40,7 +40,7 @@ function tablesort_sql($header, $before $ts = tablesort_init($header); if ($ts['sql']) { // Based on code from db_escape_table(), but this can also contain a dot. - $field = preg_replace('/[^A-Za-z0-9_.]+/', '', $ts['sql']); + $field = preg_replace('/[^A-Za-z0-9_.\[\]]+/', '', $ts['sql']); // Sort order can only be ASC or DESC. $sort = drupal_strtoupper($ts['sort']); Index: includes/theme.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/theme.inc,v retrieving revision 1.415 diff -u -p -r1.415 theme.inc --- includes/theme.inc 27 Jan 2008 19:47:06 -0000 1.415 +++ includes/theme.inc 31 Mar 2008 17:26:39 -0000 @@ -418,7 +418,7 @@ function list_themes($refresh = FALSE) { // Extract from the database only when it is available. // Also check that the site is not in the middle of an install or update. if (db_is_active() && !defined('MAINTENANCE_MODE')) { - $result = db_query("SELECT * FROM {system} WHERE type = '%s'", 'theme'); + $result = db_query("SELECT * FROM [{system}] WHERE [type] = %s", 'theme'); while ($theme = db_fetch_object($result)) { if (file_exists($theme->filename)) { $theme->info = unserialize($theme->info); Index: modules/aggregator/aggregator.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/aggregator/aggregator.admin.inc,v retrieving revision 1.7 diff -u -p -r1.7 aggregator.admin.inc --- modules/aggregator/aggregator.admin.inc 10 Jan 2008 22:47:17 -0000 1.7 +++ modules/aggregator/aggregator.admin.inc 31 Mar 2008 17:26:41 -0000 @@ -20,7 +20,7 @@ function aggregator_admin_overview() { * The page HTML. */ function aggregator_view() { - $result = db_query('SELECT f.*, COUNT(i.iid) AS items FROM {aggregator_feed} f LEFT JOIN {aggregator_item} i ON f.fid = i.fid GROUP BY f.fid, f.title, f.url, f.refresh, f.checked, f.link, f.description, f.etag, f.modified, f.image, f.block ORDER BY f.title'); + $result = db_query('SELECT f.*, COUNT(i.[iid]) AS [items] FROM [{aggregator_feed}] f LEFT JOIN [{aggregator_item}] i ON f.[fid] = i.[fid] GROUP BY f.[fid], f.[title], f.[url], f.[refresh], f.[checked], f.[link], f.[description], f.[etag], f.[modified], f.[image], f.[block] ORDER BY f.[title]'); $output = '

    '. t('Feed overview') .'

    '; @@ -31,7 +31,7 @@ function aggregator_view() { } $output .= theme('table', $header, $rows); - $result = db_query('SELECT c.cid, c.title, count(ci.iid) as items FROM {aggregator_category} c LEFT JOIN {aggregator_category_item} ci ON c.cid = ci.cid GROUP BY c.cid, c.title ORDER BY title'); + $result = db_query('SELECT c.[cid], c.[title], COUNT(ci.[iid]) AS [items] FROM [{aggregator_category}] c LEFT JOIN [{aggregator_category_item}] ci ON c.[cid] = ci.[cid] GROUP BY c.[cid], c.[title] ORDER BY [title]'); $output .= '

    '. t('Category overview') .'

    '; @@ -83,7 +83,7 @@ function aggregator_form_feed(&$form_sta // Handling of categories: $options = array(); $values = array(); - $categories = db_query('SELECT c.cid, c.title, f.fid FROM {aggregator_category} c LEFT JOIN {aggregator_category_feed} f ON c.cid = f.cid AND f.fid = %d ORDER BY title', $edit['fid']); + $categories = db_query('SELECT c.[cid], c.[title], f.[fid] FROM [{aggregator_category}] c LEFT JOIN [{aggregator_category_feed}] f ON c.[cid] = f.[cid] AND f.[fid] = %d ORDER BY [title]', $edit['fid']); while ($category = db_fetch_object($categories)) { $options[$category->cid] = check_plain($category->title); if ($category->fid) $values[] = $category->cid; @@ -117,10 +117,10 @@ function aggregator_form_feed_validate($ } // Check for duplicate titles. if (isset($form_state['values']['fid'])) { - $result = db_query("SELECT title, url FROM {aggregator_feed} WHERE (title = '%s' OR url='%s') AND fid != %d", $form_state['values']['title'], $form_state['values']['url'], $form_state['values']['fid']); + $result = db_query("SELECT [title], [url] FROM [{aggregator_feed}] WHERE ([title] = %s OR [url] = %s) AND [fid] <> %d", $form_state['values']['title'], $form_state['values']['url'], $form_state['values']['fid']); } else { - $result = db_query("SELECT title, url FROM {aggregator_feed} WHERE title = '%s' OR url='%s'", $form_state['values']['title'], $form_state['values']['url']); + $result = db_query("SELECT [title], [url] FROM [{aggregator_feed}] WHERE [title] = %s OR [url] = %s", $form_state['values']['title'], $form_state['values']['url']); } while ($feed = db_fetch_object($result)) { if (strcasecmp($feed->title, $form_state['values']['title']) == 0) { @@ -286,10 +286,10 @@ function aggregator_form_category_valida if ($form_state['values']['op'] == t('Save')) { // Check for duplicate titles if (isset($form_state['values']['cid'])) { - $category = db_fetch_object(db_query("SELECT cid FROM {aggregator_category} WHERE title = '%s' AND cid != %d", $form_state['values']['title'], $form_state['values']['cid'])); + $category = db_fetch_object(db_query("SELECT [cid] FROM [{aggregator_category}] WHERE [title] = %s AND [cid] <> %d", $form_state['values']['title'], $form_state['values']['cid'])); } else { - $category = db_fetch_object(db_query("SELECT cid FROM {aggregator_category} WHERE title = '%s'", $form_state['values']['title'])); + $category = db_fetch_object(db_query("SELECT [cid] FROM [{aggregator_category}] WHERE [title] = %s", $form_state['values']['title'])); } if ($category) { form_set_error('title', t('A category named %category already exists. Please enter a unique title.', array('%category' => $form_state['values']['title']))); Index: modules/aggregator/aggregator.install =================================================================== RCS file: /cvs/drupal/drupal/modules/aggregator/aggregator.install,v retrieving revision 1.14 diff -u -p -r1.14 aggregator.install --- modules/aggregator/aggregator.install 18 Dec 2007 12:59:20 -0000 1.14 +++ modules/aggregator/aggregator.install 31 Mar 2008 17:26:41 -0000 @@ -44,6 +44,7 @@ function aggregator_schema() { 'description' => array( 'type' => 'text', 'not null' => TRUE, + 'default' => '', 'size' => 'big', 'description' => t('Description of the category'), ), @@ -143,12 +144,14 @@ function aggregator_schema() { 'description' => array( 'type' => 'text', 'not null' => TRUE, + 'default' => '', 'size' => 'big', 'description' => t("The parent website's description; comes from the element in the feed."), ), 'image' => array( 'type' => 'text', 'not null' => TRUE, + 'default' => '', 'size' => 'big', 'description' => t('An image representing the feed.'), ), @@ -216,8 +219,9 @@ function aggregator_schema() { 'description' => t('Author of the feed item.'), ), 'description' => array( - 'type' => 'text', + 'type' => 'blob', 'not null' => TRUE, + 'default' => '', 'size' => 'big', 'description' => t('Body of the feed item.'), ), Index: modules/aggregator/aggregator.module =================================================================== RCS file: /cvs/drupal/drupal/modules/aggregator/aggregator.module,v retrieving revision 1.374 diff -u -p -r1.374 aggregator.module --- modules/aggregator/aggregator.module 15 Jan 2008 08:06:32 -0000 1.374 +++ modules/aggregator/aggregator.module 31 Mar 2008 17:26:44 -0000 @@ -270,7 +270,7 @@ function aggregator_init() { * TRUE if there is at least one category and the user has access to them, FALSE otherwise. */ function _aggregator_has_categories() { - return user_access('access news feeds') && db_result(db_query('SELECT COUNT(*) FROM {aggregator_category}')); + return user_access('access news feeds') && db_result(db_query('SELECT COUNT(*) FROM [{aggregator_category}]')); } /** @@ -286,7 +286,7 @@ function aggregator_perm() { * Checks news feeds for updates once their refresh interval has elapsed. */ function aggregator_cron() { - $result = db_query('SELECT * FROM {aggregator_feed} WHERE checked + refresh < %d', time()); + $result = db_query('SELECT * FROM [{aggregator_feed}] WHERE [checked] + [refresh] < %d', time()); while ($feed = db_fetch_array($result)) { aggregator_refresh($feed); } @@ -300,11 +300,11 @@ function aggregator_cron() { function aggregator_block($op = 'list', $delta = 0, $edit = array()) { if (user_access('access news feeds')) { if ($op == 'list') { - $result = db_query('SELECT cid, title FROM {aggregator_category} ORDER BY title'); + $result = db_query('SELECT [cid], [title] FROM [{aggregator_category}] ORDER BY [title]'); while ($category = db_fetch_object($result)) { $block['category-'. $category->cid]['info'] = t('!title category latest items', array('!title' => $category->title)); } - $result = db_query('SELECT fid, title FROM {aggregator_feed} ORDER BY fid'); + $result = db_query('SELECT [fid], [title] FROM [{aggregator_feed}] ORDER BY [fid]'); while ($feed = db_fetch_object($result)) { $block['feed-'. $feed->fid]['info'] = t('!title feed latest items', array('!title' => $feed->title)); } @@ -312,10 +312,10 @@ function aggregator_block($op = 'list', else if ($op == 'configure') { list($type, $id) = explode('-', $delta); if ($type == 'category') { - $value = db_result(db_query('SELECT block FROM {aggregator_category} WHERE cid = %d', $id)); + $value = db_result(db_query('SELECT [block] FROM [{aggregator_category}] WHERE [cid] = %d', $id)); } else { - $value = db_result(db_query('SELECT block FROM {aggregator_feed} WHERE fid = %d', $id)); + $value = db_result(db_query('SELECT [block] FROM [{aggregator_feed}] WHERE [fid] = %d', $id)); } $form['block'] = array('#type' => 'select', '#title' => t('Number of news items in block'), '#default_value' => $value, '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20))); return $form; @@ -323,27 +323,27 @@ function aggregator_block($op = 'list', else if ($op == 'save') { list($type, $id) = explode('-', $delta); if ($type == 'category') { - $value = db_query('UPDATE {aggregator_category} SET block = %d WHERE cid = %d', $edit['block'], $id); + $value = db_query('UPDATE [{aggregator_category}] SET [block] = %d WHERE [cid] = %d', $edit['block'], $id); } else { - $value = db_query('UPDATE {aggregator_feed} SET block = %d WHERE fid = %d', $edit['block'], $id); + $value = db_query('UPDATE [{aggregator_feed}] SET [block] = %d WHERE [fid] = %d', $edit['block'], $id); } } else if ($op == 'view') { list($type, $id) = explode('-', $delta); switch ($type) { case 'feed': - if ($feed = db_fetch_object(db_query('SELECT fid, title, block FROM {aggregator_feed} WHERE fid = %d', $id))) { + if ($feed = db_fetch_object(db_query('SELECT [fid], [title], [block] FROM [{aggregator_feed}] WHERE [fid] = %d', $id))) { $block['subject'] = check_plain($feed->title); - $result = db_query_range('SELECT * FROM {aggregator_item} WHERE fid = %d ORDER BY timestamp DESC, iid DESC', $feed->fid, 0, $feed->block); + $result = db_query_range('SELECT * FROM [{aggregator_item}] WHERE [fid] = %d ORDER BY [timestamp] DESC, [iid] DESC', $feed->fid, 0, $feed->block); $read_more = theme('more_link', url('aggregator/sources/'. $feed->fid), t("View this feed's recent news.")); } break; case 'category': - if ($category = db_fetch_object(db_query('SELECT cid, title, block FROM {aggregator_category} WHERE cid = %d', $id))) { + if ($category = db_fetch_object(db_query('SELECT [cid], [title], [block] FROM [{aggregator_category}] WHERE [cid] = %d', $id))) { $block['subject'] = check_plain($category->title); - $result = db_query_range('SELECT i.* FROM {aggregator_category_item} ci LEFT JOIN {aggregator_item} i ON ci.iid = i.iid WHERE ci.cid = %d ORDER BY i.timestamp DESC, i.iid DESC', $category->cid, 0, $category->block); + $result = db_query_range('SELECT i.* FROM [{aggregator_category_item}] ci LEFT JOIN [{aggregator_item}] i ON ci.[iid] = i.[iid] WHERE ci.[cid] = %d ORDER BY i.[timestamp] DESC, i.[iid] DESC', $category->cid, 0, $category->block); $read_more = theme('more_link', url('aggregator/categories/'. $category->cid), t("View this category's recent news.")); } break; @@ -375,18 +375,18 @@ function aggregator_save_category($edit) if (!empty($edit['cid'])) { $link_path .= $edit['cid']; if (!empty($edit['title'])) { - db_query("UPDATE {aggregator_category} SET title = '%s', description = '%s' WHERE cid = %d", $edit['title'], $edit['description'], $edit['cid']); + db_query("UPDATE [{aggregator_category}] SET [title] = %s, [description] = %s WHERE [cid] = %d", $edit['title'], $edit['description'], $edit['cid']); $op = 'update'; } else { - db_query('DELETE FROM {aggregator_category} WHERE cid = %d', $edit['cid']); + db_query('DELETE FROM [{aggregator_category}] WHERE [cid] = %d', $edit['cid']); $edit['title'] = ''; $op = 'delete'; } } else if (!empty($edit['title'])) { // A single unique id for bundles and feeds, to use in blocks - db_query("INSERT INTO {aggregator_category} (title, description, block) VALUES ('%s', '%s', 5)", $edit['title'], $edit['description']); + db_query("INSERT INTO [{aggregator_category}] ([title], [description], [block]) VALUES (%s, %s, %d)", $edit['title'], $edit['description'], 5); $link_path .= db_last_insert_id('aggregator', 'cid'); $op = 'insert'; } @@ -404,25 +404,25 @@ function aggregator_save_category($edit) function aggregator_save_feed($edit) { if (!empty($edit['fid'])) { // An existing feed is being modified, delete the category listings. - db_query('DELETE FROM {aggregator_category_feed} WHERE fid = %d', $edit['fid']); + db_query('DELETE FROM [{aggregator_category_feed}] WHERE [fid] = %d', $edit['fid']); } if (!empty($edit['fid']) && !empty($edit['title'])) { - db_query("UPDATE {aggregator_feed} SET title = '%s', url = '%s', refresh = %d WHERE fid = %d", $edit['title'], $edit['url'], $edit['refresh'], $edit['fid']); + db_query("UPDATE [{aggregator_feed}] SET [title] = %s, [url] = %s, [refresh] = %d WHERE [fid] = %d", $edit['title'], $edit['url'], $edit['refresh'], $edit['fid']); } else if (!empty($edit['fid'])) { $items = array(); - $result = db_query('SELECT iid FROM {aggregator_item} WHERE fid = %d', $edit['fid']); + $result = db_query('SELECT [iid] FROM [{aggregator_item}] WHERE [fid] = %d', $edit['fid']); while ($item = db_fetch_object($result)) { - $items[] = "iid = $item->iid"; + $items[] = "[iid] = $item->iid"; } if (!empty($items)) { - db_query('DELETE FROM {aggregator_category_item} WHERE '. implode(' OR ', $items)); + db_query('DELETE FROM [{aggregator_category_item}] WHERE '. implode(' OR ', $items)); } - db_query('DELETE FROM {aggregator_feed} WHERE fid = %d', $edit['fid']); - db_query('DELETE FROM {aggregator_item} WHERE fid = %d', $edit['fid']); + db_query('DELETE FROM [{aggregator_feed}] WHERE [fid] = %d', $edit['fid']); + db_query('DELETE FROM [{aggregator_item}] WHERE [fid] = %d', $edit['fid']); } else if (!empty($edit['title'])) { - db_query("INSERT INTO {aggregator_feed} (title, url, refresh, block, description, image) VALUES ('%s', '%s', %d, 5, '', '')", $edit['title'], $edit['url'], $edit['refresh']); + db_query("INSERT INTO [{aggregator_feed}] ([title], [url], [refresh], [block], [description], [image]) VALUES (%s, %s, %d, %d, %s, %s)", $edit['title'], $edit['url'], $edit['refresh'], 5, '', ''); // A single unique id for bundles and feeds, to use in blocks. $edit['fid'] = db_last_insert_id('aggregator_feed', 'fid'); } @@ -431,7 +431,7 @@ function aggregator_save_feed($edit) { if (!empty($edit['category'])) { foreach ($edit['category'] as $cid => $value) { if ($value) { - db_query('INSERT INTO {aggregator_category_feed} (fid, cid) VALUES (%d, %d)', $edit['fid'], $cid); + db_query('INSERT INTO [{aggregator_category_feed}] ([fid], [cid]) VALUES (%d, %d)', $edit['fid'], $cid); } } } @@ -445,15 +445,15 @@ function aggregator_save_feed($edit) { * An associative array describing the feed to be cleared. */ function aggregator_remove($feed) { - $result = db_query('SELECT iid FROM {aggregator_item} WHERE fid = %d', $feed['fid']); + $result = db_query('SELECT [iid] FROM [{aggregator_item}] WHERE [fid] = %d', $feed['fid']); while ($item = db_fetch_object($result)) { - $items[] = "iid = $item->iid"; + $items[] = "[iid] = $item->iid"; } if (!empty($items)) { - db_query('DELETE FROM {aggregator_category_item} WHERE '. implode(' OR ', $items)); + db_query('DELETE FROM [{aggregator_category_item}] WHERE '. implode(' OR ', $items)); } - db_query('DELETE FROM {aggregator_item} WHERE fid = %d', $feed['fid']); - db_query("UPDATE {aggregator_feed} SET checked = 0, etag = '', modified = 0 WHERE fid = %d", $feed['fid']); + db_query('DELETE FROM [{aggregator_item}] WHERE [fid] = %d', $feed['fid']); + db_query("UPDATE [{aggregator_feed}] SET [checked] = %d, [etag] = %s, [modified] = %d WHERE [fid] = %d", 0, '', 0, $feed['fid']); drupal_set_message(t('The news items from %site have been removed.', array('%site' => $feed['title']))); } @@ -594,7 +594,7 @@ function aggregator_refresh($feed) { // Process HTTP response code. switch ($result->code) { case 304: - db_query('UPDATE {aggregator_feed} SET checked = %d WHERE fid = %d', time(), $feed['fid']); + db_query('UPDATE [{aggregator_feed}] SET [checked] = %d WHERE [fid] = %d', time(), $feed['fid']); drupal_set_message(t('There is no new syndicated content from %site.', array('%site' => $feed['title']))); break; case 301: @@ -628,7 +628,7 @@ function aggregator_refresh($feed) { $etag = empty($result->headers['ETag']) ? '' : $result->headers['ETag']; // Update the feed data. - db_query("UPDATE {aggregator_feed} SET url = '%s', checked = %d, link = '%s', description = '%s', image = '%s', etag = '%s', modified = %d WHERE fid = %d", $feed['url'], time(), $channel['LINK'], $channel['DESCRIPTION'], $image, $etag, $modified, $feed['fid']); + db_query("UPDATE [{aggregator_feed}] SET [url] = %s, [checked] = %d, [link] = %s, [description] = %s, [image] = %s, [etag] = %s, [modified] = %d WHERE [fid] = %d", $feed['url'], time(), $channel['LINK'], $channel['DESCRIPTION'], $image, $etag, $modified, $feed['fid']); // Clear the cache. cache_clear_all(); @@ -785,13 +785,13 @@ function aggregator_parse_feed(&$data, $ // we find a duplicate entry, we resolve it and pass along its ID is such // that we can update it if needed. if (!empty($guid)) { - $entry = db_fetch_object(db_query("SELECT iid FROM {aggregator_item} WHERE fid = %d AND guid = '%s'", $feed['fid'], $guid)); + $entry = db_fetch_object(db_query("SELECT [iid] FROM [{aggregator_item}] WHERE [fid] = %d AND [guid] = %s", $feed['fid'], $guid)); } else if ($link && $link != $feed['link'] && $link != $feed['url']) { - $entry = db_fetch_object(db_query("SELECT iid FROM {aggregator_item} WHERE fid = %d AND link = '%s'", $feed['fid'], $link)); + $entry = db_fetch_object(db_query("SELECT [iid] FROM [{aggregator_item}] WHERE [fid] = %d AND [link] = %s", $feed['fid'], $link)); } else { - $entry = db_fetch_object(db_query("SELECT iid FROM {aggregator_item} WHERE fid = %d AND title = '%s'", $feed['fid'], $title)); + $entry = db_fetch_object(db_query("SELECT [iid] FROM [{aggregator_item}] WHERE [fid] = %d AND [title] = %s", $feed['fid'], $title)); } $item += array('AUTHOR' => '', 'DESCRIPTION' => ''); aggregator_save_item(array('iid' => (isset($entry->iid) ? $entry->iid: ''), 'fid' => $feed['fid'], 'timestamp' => $timestamp, 'title' => $title, 'link' => $link, 'author' => $item['AUTHOR'], 'description' => $item['DESCRIPTION'], 'guid' => $guid)); @@ -799,7 +799,7 @@ function aggregator_parse_feed(&$data, $ // Remove all items that are older than flush item timer. $age = time() - variable_get('aggregator_clear', 9676800); - $result = db_query('SELECT iid FROM {aggregator_item} WHERE fid = %d AND timestamp < %d', $feed['fid'], $age); + $result = db_query('SELECT [iid] FROM [{aggregator_item}] WHERE [fid] = %d AND [timestamp] < %d', $feed['fid'], $age); $items = array(); $num_rows = FALSE; @@ -808,8 +808,8 @@ function aggregator_parse_feed(&$data, $ $num_rows = TRUE; } if ($num_rows) { - db_query('DELETE FROM {aggregator_category_item} WHERE iid IN ('. implode(', ', $items) .')'); - db_query('DELETE FROM {aggregator_item} WHERE fid = %d AND timestamp < %d', $feed['fid'], $age); + db_query('DELETE FROM [{aggregator_category_item}] WHERE [iid] IN ('. implode(', ', $items) .')'); + db_query('DELETE FROM [{aggregator_item}] WHERE [fid] = %d AND [timestamp] < %d', $feed['fid'], $age); } return 1; @@ -823,19 +823,18 @@ function aggregator_parse_feed(&$data, $ */ function aggregator_save_item($edit) { if ($edit['iid'] && $edit['title']) { - db_query("UPDATE {aggregator_item} SET title = '%s', link = '%s', author = '%s', description = '%s', guid = '%s', timestamp = %d WHERE iid = %d", $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['guid'], $edit['timestamp'], $edit['iid']); + drupal_write_record("aggregator_item", $edit, 'iid'); } else if ($edit['iid']) { - db_query('DELETE FROM {aggregator_item} WHERE iid = %d', $edit['iid']); - db_query('DELETE FROM {aggregator_category_item} WHERE iid = %d', $edit['iid']); + db_query('DELETE FROM [{aggregator_item}] WHERE [iid] = %d', $edit['iid']); + db_query('DELETE FROM [{aggregator_category_item}] WHERE [iid] = %d', $edit['iid']); } else if ($edit['title'] && $edit['link']) { - db_query("INSERT INTO {aggregator_item} (fid, title, link, author, description, timestamp, guid) VALUES (%d, '%s', '%s', '%s', '%s', %d, '%s')", $edit['fid'], $edit['title'], $edit['link'], $edit['author'], $edit['description'], $edit['timestamp'], $edit['guid']); - $edit['iid'] = db_last_insert_id('aggregator_item', 'iid'); + drupal_write_record("aggregator_item", $edit); // file the items in the categories indicated by the feed - $categories = db_query('SELECT cid FROM {aggregator_category_feed} WHERE fid = %d', $edit['fid']); + $categories = db_query('SELECT [cid] FROM [{aggregator_category_feed}] WHERE [fid] = %d', $edit['fid']); while ($category = db_fetch_object($categories)) { - db_query('INSERT INTO {aggregator_category_item} (cid, iid) VALUES (%d, %d)', $category->cid, $edit['iid']); + db_query('INSERT INTO [{aggregator_category_item}] ([cid], [iid]) VALUES (%d, %d)', $category->cid, $edit['iid']); } } } @@ -851,7 +850,7 @@ function aggregator_save_item($edit) { function aggregator_feed_load($fid) { static $feeds; if (!isset($feeds[$fid])) { - $feeds[$fid] = db_fetch_array(db_query('SELECT * FROM {aggregator_feed} WHERE fid = %d', $fid)); + $feeds[$fid] = db_fetch_array(db_query('SELECT * FROM [{aggregator_feed}] WHERE [fid] = %d', $fid)); } return $feeds[$fid]; } @@ -867,7 +866,7 @@ function aggregator_feed_load($fid) { function aggregator_category_load($cid) { static $categories; if (!isset($categories[$cid])) { - $categories[$cid] = db_fetch_array(db_query('SELECT * FROM {aggregator_category} WHERE cid = %d', $cid)); + $categories[$cid] = db_fetch_array(db_query('SELECT * FROM [{aggregator_category}] WHERE [cid] = %d', $cid)); } return $categories[$cid]; } Index: modules/aggregator/aggregator.pages.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/aggregator/aggregator.pages.inc,v retrieving revision 1.12 diff -u -p -r1.12 aggregator.pages.inc --- modules/aggregator/aggregator.pages.inc 8 Jan 2008 10:35:40 -0000 1.12 +++ modules/aggregator/aggregator.pages.inc 31 Mar 2008 17:26:45 -0000 @@ -15,7 +15,7 @@ function aggregator_page_last() { drupal_add_feed(url('aggregator/rss'), variable_get('site_name', 'Drupal') .' '. t('aggregator')); - $items = aggregator_feed_items_load('SELECT i.*, f.title AS ftitle, f.link AS flink FROM {aggregator_item} i INNER JOIN {aggregator_feed} f ON i.fid = f.fid ORDER BY i.timestamp DESC, i.iid DESC'); + $items = aggregator_feed_items_load('SELECT i.*, f.[title] AS [ftitle], f.[link] AS [flink] FROM [{aggregator_item}] i INNER JOIN [{aggregator_feed}] f ON i.[fid] = f.[fid] ORDER BY i.[timestamp] DESC, i.[iid] DESC'); return _aggregator_page_list($items, arg(1)); } @@ -42,7 +42,7 @@ function aggregator_page_source($arg1, $ // It is safe to include the fid in the query because it's loaded from the // database by aggregator_feed_load. - $items = aggregator_feed_items_load('SELECT * FROM {aggregator_item} WHERE fid = '. $feed->fid .' ORDER BY timestamp DESC, iid DESC'); + $items = aggregator_feed_items_load('SELECT * FROM [{aggregator_item}] WHERE [fid] = '. $feed->fid .' ORDER BY [timestamp] DESC, [iid] DESC'); return _aggregator_page_list($items, arg(3), $feed_source); } @@ -69,7 +69,7 @@ function aggregator_page_category($arg1, // It is safe to include the cid in the query because it's loaded from the // database by aggregator_category_load. - $items = aggregator_feed_items_load('SELECT i.*, f.title AS ftitle, f.link AS flink FROM {aggregator_category_item} c LEFT JOIN {aggregator_item} i ON c.iid = i.iid LEFT JOIN {aggregator_feed} f ON i.fid = f.fid WHERE cid = '. $category['cid'] .' ORDER BY timestamp DESC, i.iid DESC'); + $items = aggregator_feed_items_load('SELECT i.*, f.[title] AS [ftitle], f.[link] AS [flink] FROM [{aggregator_category_item}] c LEFT JOIN [{aggregator_item}] i ON c.[iid] = i.[iid] LEFT JOIN [{aggregator_feed}] f ON i.[fid] = f.[fid] WHERE [cid] = '. $category['cid'] .' ORDER BY [timestamp] DESC, i.[iid] DESC'); return _aggregator_page_list($items, arg(3)); } @@ -87,7 +87,7 @@ function aggregator_feed_items_load($sql if (isset($sql)) { $result = pager_query($sql, 20); while ($item = db_fetch_object($result)) { - $result_category = db_query('SELECT c.title, c.cid FROM {aggregator_category_item} ci LEFT JOIN {aggregator_category} c ON ci.cid = c.cid WHERE ci.iid = %d ORDER BY c.title', $item->iid); + $result_category = db_query('SELECT c.[title], c.[cid] FROM [{aggregator_category_item}] ci LEFT JOIN [{aggregator_category}] c ON ci.[cid] = c.[cid] WHERE ci.[iid] = %d ORDER BY c.[title]', $item->iid); $item->categories = array(); while ($item_categories = db_fetch_object($result_category)) { $item->categories[] = $item_categories; @@ -153,7 +153,7 @@ function aggregator_categorize_items($it foreach ($items as $item) { $form['items'][$item->iid] = array('#value' => theme('aggregator_item', $item)); $form['categories'][$item->iid] = array(); - $categories_result = db_query('SELECT c.cid, c.title, ci.iid FROM {aggregator_category} c LEFT JOIN {aggregator_category_item} ci ON c.cid = ci.cid AND ci.iid = %d', $item->iid); + $categories_result = db_query('SELECT c.[cid], c.[title], ci.[iid] FROM [{aggregator_category}] c LEFT JOIN [{aggregator_category_item}] ci ON c.[cid] = ci.[cid] AND ci.[iid] = %d', $item->iid); $selected = array(); while ($category = db_fetch_object($categories_result)) { if (!$done) { @@ -192,10 +192,10 @@ function aggregator_categorize_items_val function aggregator_categorize_items_submit($form, &$form_state) { if (!empty($form_state['values']['categories'])) { foreach ($form_state['values']['categories'] as $iid => $selection) { - db_query('DELETE FROM {aggregator_category_item} WHERE iid = %d', $iid); + db_query('DELETE FROM [{aggregator_category_item}] WHERE [iid] = %d', $iid); foreach ($selection as $cid) { if ($cid) { - db_query('INSERT INTO {aggregator_category_item} (cid, iid) VALUES (%d, %d)', $cid, $iid); + db_query('INSERT INTO [{aggregator_category_item}] ([cid], [iid]) VALUES (%d, %d)', $cid, $iid); } } } @@ -250,7 +250,7 @@ function template_preprocess_aggregator_ $variables['feed_url'] = check_url($item->link); $variables['feed_title'] = check_plain($item->title); - $variables['content'] = aggregator_filter_xss($item->description); + $variables['content'] = aggregator_filter_xss(db_decode_blob($item->description)); $variables['source_url'] = ''; $variables['source_title'] = ''; @@ -275,14 +275,14 @@ function template_preprocess_aggregator_ * Menu callback; displays all the feeds used by the aggregator. */ function aggregator_page_sources() { - $result = db_query('SELECT f.fid, f.title, f.description, f.image, MAX(i.timestamp) AS last FROM {aggregator_feed} f LEFT JOIN {aggregator_item} i ON f.fid = i.fid GROUP BY f.fid, f.title, f.description, f.image ORDER BY last DESC, f.title'); + $result = db_query('SELECT f.[fid], f.[title], f.[description], f.[image], MAX(i.[timestamp]) AS [last] FROM [{aggregator_feed}] f LEFT JOIN [{aggregator_item}] i ON f.[fid] = i.[fid] GROUP BY f.[fid], f.[title], f.[description], f.[image] ORDER BY [last] DESC, f.[title]'); $output = ''; while ($feed = db_fetch_object($result)) { // Most recent items: $summary_items = array(); if (variable_get('aggregator_summary_items', 3)) { - $items = db_query_range('SELECT i.title, i.timestamp, i.link FROM {aggregator_item} i WHERE i.fid = %d ORDER BY i.timestamp DESC', $feed->fid, 0, variable_get('aggregator_summary_items', 3)); + $items = db_query_range('SELECT i.[title], i.[timestamp], i.[link] FROM [{aggregator_item}] i WHERE i.[fid] = %d ORDER BY i.[timestamp] DESC', $feed->fid, 0, variable_get('aggregator_summary_items', 3)); while ($item = db_fetch_object($items)) { $summary_items[] = theme('aggregator_summary_item', $item); } @@ -299,13 +299,13 @@ function aggregator_page_sources() { * Menu callback; displays all the categories used by the aggregator. */ function aggregator_page_categories() { - $result = db_query('SELECT c.cid, c.title, c.description FROM {aggregator_category} c LEFT JOIN {aggregator_category_item} ci ON c.cid = ci.cid LEFT JOIN {aggregator_item} i ON ci.iid = i.iid GROUP BY c.cid, c.title, c.description'); + $result = db_query('SELECT c.[cid], c.[title], c.[description] FROM [{aggregator_category}] c LEFT JOIN [{aggregator_category_item}] ci ON c.[cid] = ci.[cid] LEFT JOIN [{aggregator_item}] i ON ci.[iid] = i.[iid] GROUP BY c.[cid], c.[title], c.[description]'); $output = ''; while ($category = db_fetch_object($result)) { if (variable_get('aggregator_summary_items', 3)) { $summary_items = array(); - $items = db_query_range('SELECT i.title, i.timestamp, i.link, f.title as feed_title, f.link as feed_link FROM {aggregator_category_item} ci LEFT JOIN {aggregator_item} i ON i.iid = ci.iid LEFT JOIN {aggregator_feed} f ON i.fid = f.fid WHERE ci.cid = %d ORDER BY i.timestamp DESC', $category->cid, 0, variable_get('aggregator_summary_items', 3)); + $items = db_query_range('SELECT i.[title], i.[timestamp], i.[link], f.[title] AS [feed_title], f.[link] AS [feed_link] FROM [{aggregator_category_item}] ci LEFT JOIN [{aggregator_item}] i ON i.[iid] = ci.[iid] LEFT JOIN [{aggregator_feed}] f ON i.[fid] = f.[fid] WHERE ci.[cid] = %d ORDER BY i.[timestamp] DESC', $category->cid, 0, variable_get('aggregator_summary_items', 3)); while ($item = db_fetch_object($items)) { $summary_items[] = theme('aggregator_summary_item', $item); } @@ -324,14 +324,14 @@ function aggregator_page_rss() { $result = NULL; // arg(2) is the passed cid, only select for that category if (arg(2)) { - $category = db_fetch_object(db_query('SELECT cid, title FROM {aggregator_category} WHERE cid = %d', arg(2))); - $sql = 'SELECT i.*, f.title AS ftitle, f.link AS flink FROM {aggregator_category_item} c LEFT JOIN {aggregator_item} i ON c.iid = i.iid LEFT JOIN {aggregator_feed} f ON i.fid = f.fid WHERE cid = %d ORDER BY timestamp DESC, i.iid DESC'; + $category = db_fetch_object(db_query('SELECT [cid], [title] FROM [{aggregator_category}] WHERE [cid] = %d', arg(2))); + $sql = 'SELECT i.*, f.[title] AS [ftitle], f.[link] AS [flink] FROM [{aggregator_category_item}] c LEFT JOIN [{aggregator_item}] i ON c.[iid] = i.[iid] LEFT JOIN [{aggregator_feed}] f ON i.[fid] = f.[fid] WHERE [cid] = %d ORDER BY [timestamp] DESC, i.[iid] DESC'; $result = db_query_range($sql, $category->cid, 0, variable_get('feed_default_items', 10)); } // or, get the default aggregator items else { $category = NULL; - $sql = 'SELECT i.*, f.title AS ftitle, f.link AS flink FROM {aggregator_item} i INNER JOIN {aggregator_feed} f ON i.fid = f.fid ORDER BY i.timestamp DESC, i.iid DESC'; + $sql = 'SELECT i.*, f.[title] AS [ftitle], f.[link] AS [flink] FROM [{aggregator_item}] i INNER JOIN [{aggregator_feed}] f ON i.[fid] = f.[fid] ORDER BY i.[timestamp] DESC, i.[iid] DESC'; $result = db_query_range($sql, 0, variable_get('feed_default_items', 10)); } @@ -357,6 +357,7 @@ function theme_aggregator_page_rss($feed $items = ''; $feed_length = variable_get('feed_item_length', 'teaser'); foreach ($feeds as $feed) { + $feed->description = db_decode_blob($feed->description); switch ($feed_length) { case 'teaser': $teaser = node_teaser($feed->description); @@ -394,10 +395,10 @@ function theme_aggregator_page_rss($feed */ function aggregator_page_opml($cid = NULL) { if ($cid) { - $result = db_query('SELECT f.title, f.url FROM {aggregator_feed} f LEFT JOIN {aggregator_category_feed} c on f.fid = c.fid WHERE c.cid = %d ORDER BY title', $cid); + $result = db_query('SELECT f.[title], f.[url] FROM [{aggregator_feed}] f LEFT JOIN [{aggregator_category_feed}] c on f.[fid] = c.[fid] WHERE c.[cid] = %d ORDER BY [title]', $cid); } else { - $result = db_query('SELECT * FROM {aggregator_feed} ORDER BY title'); + $result = db_query('SELECT * FROM [{aggregator_feed}] ORDER BY [title]'); } $feeds = array(); Index: modules/block/block.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/block/block.admin.inc,v retrieving revision 1.14 diff -u -p -r1.14 block.admin.inc --- modules/block/block.admin.inc 22 Dec 2007 23:24:24 -0000 1.14 +++ modules/block/block.admin.inc 31 Mar 2008 17:26:46 -0000 @@ -95,7 +95,7 @@ function block_admin_display_form_submit foreach ($form_state['values'] as $block) { $block['status'] = $block['region'] != BLOCK_REGION_NONE; $block['region'] = $block['status'] ? $block['region'] : ''; - db_query("UPDATE {blocks} SET status = %d, weight = %d, region = '%s', throttle = %d WHERE module = '%s' AND delta = '%s' AND theme = '%s'", $block['status'], $block['weight'], $block['region'], isset($block['throttle']) ? $block['throttle'] : 0, $block['module'], $block['delta'], $block['theme']); + db_query("UPDATE [{blocks}] SET [status] = %d, [weight] = %d, [region] = %s, [throttle] = %d WHERE [module] = %s AND [delta] = %s AND [theme] = %s", $block['status'], $block['weight'], $block['region'], isset($block['throttle']) ? $block['throttle'] : 0, $block['module'], $block['delta'], $block['theme']); } drupal_set_message(t('The block settings have been updated.')); cache_clear_all(); @@ -144,7 +144,7 @@ function block_admin_configure(&$form_st $form['module'] = array('#type' => 'value', '#value' => $module); $form['delta'] = array('#type' => 'value', '#value' => $delta); - $edit = db_fetch_array(db_query("SELECT pages, visibility, custom, title FROM {blocks} WHERE module = '%s' AND delta = '%s'", $module, $delta)); + $edit = db_fetch_array(db_query("SELECT [pages], [visibility], [custom], [title] FROM [{blocks}] WHERE [module] = %s AND [delta] = %s", $module, $delta)); $form['block_settings'] = array( '#type' => 'fieldset', @@ -194,11 +194,11 @@ function block_admin_configure(&$form_st // Role-based visibility settings $default_role_options = array(); - $result = db_query("SELECT rid FROM {blocks_roles} WHERE module = '%s' AND delta = '%s'", $module, $delta); + $result = db_query("SELECT [rid] FROM [{blocks_roles}] WHERE [module] = %s AND [delta] = %s", $module, $delta); while ($role = db_fetch_object($result)) { $default_role_options[] = $role->rid; } - $result = db_query('SELECT rid, name FROM {role} ORDER BY name'); + $result = db_query('SELECT [rid], [name] FROM [{role}] ORDER BY [name]'); $role_options = array(); while ($role = db_fetch_object($result)) { $role_options[$role->rid] = $role->name; @@ -260,7 +260,7 @@ function block_admin_configure(&$form_st function block_admin_configure_validate($form, &$form_state) { if ($form_state['values']['module'] == 'block') { - if (empty($form_state['values']['info']) || db_result(db_query("SELECT COUNT(*) FROM {boxes} WHERE bid != %d AND info = '%s'", $form_state['values']['delta'], $form_state['values']['info']))) { + if (empty($form_state['values']['info']) || db_result(db_query("SELECT COUNT(*) FROM [{boxes}] WHERE [bid] <> %d AND [info] = %s", $form_state['values']['delta'], $form_state['values']['info']))) { form_set_error('info', t('Please ensure that each block description is unique.')); } } @@ -268,10 +268,10 @@ function block_admin_configure_validate( function block_admin_configure_submit($form, &$form_state) { if (!form_get_errors()) { - db_query("UPDATE {blocks} SET visibility = %d, pages = '%s', custom = %d, title = '%s' WHERE module = '%s' AND delta = '%s'", $form_state['values']['visibility'], trim($form_state['values']['pages']), $form_state['values']['custom'], $form_state['values']['title'], $form_state['values']['module'], $form_state['values']['delta']); - db_query("DELETE FROM {blocks_roles} WHERE module = '%s' AND delta = '%s'", $form_state['values']['module'], $form_state['values']['delta']); + db_query("UPDATE [{blocks}] SET [visibility] = %d, [pages] = %s, [custom] = %d, [title] = %s WHERE [module] = %s AND [delta] = %s", $form_state['values']['visibility'], trim($form_state['values']['pages']), $form_state['values']['custom'], $form_state['values']['title'], $form_state['values']['module'], $form_state['values']['delta']); + db_query("DELETE FROM [{blocks_roles}] WHERE [module] = %s AND [delta] = %s", $form_state['values']['module'], $form_state['values']['delta']); foreach (array_filter($form_state['values']['roles']) as $rid) { - db_query("INSERT INTO {blocks_roles} (rid, module, delta) VALUES (%d, '%s', '%s')", $rid, $form_state['values']['module'], $form_state['values']['delta']); + db_query("INSERT INTO [{blocks_roles}] ([rid], [module], [delta]) VALUES (%d, %s, %s)", $rid, $form_state['values']['module'], $form_state['values']['delta']); } module_invoke($form_state['values']['module'], 'block', 'save', $form_state['values']['delta'], $form_state['values']); drupal_set_message(t('The block configuration has been saved.')); @@ -289,7 +289,7 @@ function block_add_block_form(&$form_sta } function block_add_block_form_validate($form, &$form_state) { - if (empty($form_state['values']['info']) || db_result(db_query("SELECT COUNT(*) FROM {boxes} WHERE info = '%s'", $form_state['values']['info']))) { + if (empty($form_state['values']['info']) || db_result(db_query("SELECT COUNT(*) FROM [{boxes}] WHERE [info] = %s", $form_state['values']['info']))) { form_set_error('info', t('Please ensure that each block description is unique.')); } } @@ -298,17 +298,17 @@ function block_add_block_form_validate($ * Save the new custom block. */ function block_add_block_form_submit($form, &$form_state) { - db_query("INSERT INTO {boxes} (body, info, format) VALUES ('%s', '%s', %d)", $form_state['values']['body'], $form_state['values']['info'], $form_state['values']['format']); - $delta = db_last_insert_id('boxes', 'bid'); + drupal_write_record('boxes', $form_state['values']); + $delta = $form_state['values']['bid']; foreach (list_themes() as $key => $theme) { if ($theme->status) { - db_query("INSERT INTO {blocks} (visibility, pages, custom, title, module, theme, status, weight, delta, cache) VALUES(%d, '%s', %d, '%s', '%s', '%s', %d, %d, %d, %d)", $form_state['values']['visibility'], trim($form_state['values']['pages']), $form_state['values']['custom'], $form_state['values']['title'], $form_state['values']['module'], $theme->name, 0, 0, $delta, BLOCK_NO_CACHE); + db_query("INSERT INTO [{blocks}] ([visibility], [pages], [custom], [title], [module], [theme], [status], [weight], [delta], [cache]) VALUES(%d, %s, %d, %s, %s, %s, %d, %d, %d, %d)", $form_state['values']['visibility'], trim($form_state['values']['pages']), $form_state['values']['custom'], $form_state['values']['title'], $form_state['values']['module'], $theme->name, 0, 0, $delta, BLOCK_NO_CACHE); } } foreach (array_filter($form_state['values']['roles']) as $rid) { - db_query("INSERT INTO {blocks_roles} (rid, module, delta) VALUES (%d, '%s', '%s')", $rid, $form_state['values']['module'], $delta); + db_query("INSERT INTO [{blocks_roles}] ([rid], [module], [delta]) VALUES (%d, %s, %s)", $rid, $form_state['values']['module'], $delta); } drupal_set_message(t('The block has been created.')); @@ -333,8 +333,8 @@ function block_box_delete(&$form_state, * Deletion of custom blocks. */ function block_box_delete_submit($form, &$form_state) { - db_query('DELETE FROM {boxes} WHERE bid = %d', $form_state['values']['bid']); - db_query("DELETE FROM {blocks} WHERE module = 'block' AND delta = %d", $form_state['values']['bid']); + db_query('DELETE FROM [{boxes}] WHERE [bid] = %d', $form_state['values']['bid']); + db_query("DELETE FROM [{blocks}] WHERE [module] = 'block' AND [delta] = %d", $form_state['values']['bid']); drupal_set_message(t('The block %name has been removed.', array('%name' => $form_state['values']['info']))); cache_clear_all(); $form_state['redirect'] = 'admin/build/block'; Index: modules/block/block.install =================================================================== RCS file: /cvs/drupal/drupal/modules/block/block.install,v retrieving revision 1.8 diff -u -p -r1.8 block.install --- modules/block/block.install 18 Dec 2007 12:59:20 -0000 1.8 +++ modules/block/block.install 31 Mar 2008 17:26:46 -0000 @@ -79,6 +79,7 @@ function block_schema() { 'pages' => array( 'type' => 'text', 'not null' => TRUE, + 'default' => '', 'description' => t('Contents of the "Pages" block; contains either a list of paths on which to include/exclude the block or PHP code, depending on "visibility" setting.'), ), 'title' => array( @@ -112,18 +113,21 @@ function block_schema() { 'type' => 'varchar', 'length' => 64, 'not null' => TRUE, + 'default' => '', 'description' => t("The block's origin module, from {blocks}.module."), ), 'delta' => array( 'type' => 'varchar', 'length' => 32, 'not null' => TRUE, + 'default' => '', 'description' => t("The block's unique delta within module, from {blocks}.delta."), ), 'rid' => array( 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, + 'default' => 0, 'description' => t("The user's role ID from {users_roles}.rid."), ), ), @@ -147,7 +151,7 @@ function block_schema() { 'description' => t("The block's {blocks}.bid."), ), 'body' => array( - 'type' => 'text', + 'type' => 'blob', 'not null' => FALSE, 'size' => 'big', 'description' => t('Block contents.'), Index: modules/block/block.module =================================================================== RCS file: /cvs/drupal/drupal/modules/block/block.module,v retrieving revision 1.299 diff -u -p -r1.299 block.module --- modules/block/block.module 3 Feb 2008 19:12:57 -0000 1.299 +++ modules/block/block.module 31 Mar 2008 17:26:47 -0000 @@ -188,7 +188,7 @@ function block_block($op = 'list', $delt case 'list': $blocks = array(); - $result = db_query('SELECT bid, info FROM {boxes} ORDER BY info'); + $result = db_query('SELECT [bid], [info] FROM [{boxes}] ORDER BY [info]'); while ($block = db_fetch_object($result)) { $blocks[$block->bid]['info'] = $block->info; // Not worth caching. @@ -211,8 +211,8 @@ function block_block($op = 'list', $delt break; case 'view': - $block = db_fetch_object(db_query('SELECT body, format FROM {boxes} WHERE bid = %d', $delta)); - $data['content'] = check_markup($block->body, $block->format, FALSE); + $block = db_fetch_object(db_query('SELECT [body], [format] FROM [{boxes}] WHERE [bid] = %d', $delta)); + $data['content'] = check_markup(db_decode_blob($block->body), $block->format, FALSE); return $data; } } @@ -228,7 +228,7 @@ function _block_rehash() { init_theme(); - $result = db_query("SELECT * FROM {blocks} WHERE theme = '%s'", $theme_key); + $result = db_query("SELECT * FROM [{blocks}] WHERE [theme] = %s", $theme_key); $old_blocks = array(); while ($old_block = db_fetch_array($result)) { $old_blocks[$old_block['module']][$old_block['delta']] = $old_block; @@ -248,7 +248,7 @@ function _block_rehash() { $block['delta'] = $delta; $block['theme'] = $theme_key; if (!isset($block['pages'])) { - // {block}.pages is type 'text', so it cannot have a + // [{block}].[pages] is type 'text', so it cannot have a // default value, and not null, so we need to provide // value if the module did not. $block['pages'] = ''; @@ -288,14 +288,14 @@ function _block_rehash() { // Remove blocks that are no longer defined by the code from the database. foreach ($old_blocks as $module => $old_module_blocks) { foreach ($old_module_blocks as $delta => $block) { - db_query("DELETE FROM {blocks} WHERE module = '%s' AND delta = '%s' AND theme = '%s'", $module, $delta, $theme_key); + db_query("DELETE FROM [{blocks}] WHERE [module] = %s AND [delta] = %s AND [theme] = %s", $module, $delta, $theme_key); } } return $blocks; } function block_box_get($bid) { - return db_fetch_array(db_query("SELECT bx.*, bl.title FROM {boxes} bx INNER JOIN {blocks} bl ON bx.bid = bl.delta WHERE bl.module = 'block' AND bx.bid = %d", $bid)); + return db_fetch_array(db_query("SELECT bx.*, bl.[title] FROM [{boxes}] bx INNER JOIN [{blocks}] bl ON bx.[bid] = bl.[delta] WHERE bl.[module] = 'block' AND bx.[bid] = %d", $bid)); } /** @@ -319,7 +319,7 @@ function block_box_form($edit = array()) $form['body_field']['body'] = array( '#type' => 'textarea', '#title' => t('Block body'), - '#default_value' => $edit['body'], + '#default_value' => db_decode_blob($edit['body']), '#rows' => 15, '#description' => t('The content of the block as shown to the user.'), '#weight' => -17, @@ -337,7 +337,8 @@ function block_box_save($edit, $delta) { $edit['format'] = FILTER_FORMAT_DEFAULT; } - db_query("UPDATE {boxes} SET body = '%s', info = '%s', format = %d WHERE bid = %d", $edit['body'], $edit['info'], $edit['format'], $delta); + $edit['bid'] = $delta; + drupal_write_record('boxes', $edit, 'bid'); return TRUE; } @@ -353,7 +354,7 @@ function block_user($type, $edit, &$acco case 'form': if ($category == 'account') { $rids = array_keys($account->roles); - $result = db_query("SELECT DISTINCT b.* FROM {blocks} b LEFT JOIN {blocks_roles} r ON b.module = r.module AND b.delta = r.delta WHERE b.status = 1 AND b.custom != 0 AND (r.rid IN (". db_placeholders($rids) .") OR r.rid IS NULL) ORDER BY b.weight, b.module", $rids); + $result = db_query("SELECT DISTINCT b.* FROM [{blocks}] b LEFT JOIN [{blocks_roles}] r ON b.[module] = r.[module] AND b.[delta] = r.[delta] WHERE b.[status] = 1 AND b.[custom] <> 0 AND (r.[rid] IN (". db_placeholders($rids) .") OR r.[rid] IS NULL) ORDER BY b.[weight], b.[module]", $rids); $form['block'] = array('#type' => 'fieldset', '#title' => t('Block configuration'), '#weight' => 3, '#collapsible' => TRUE, '#tree' => TRUE); while ($block = db_fetch_object($result)) { $data = module_invoke($block->module, 'block', 'list'); @@ -400,7 +401,7 @@ function block_list($region) { if (!count($blocks)) { $rids = array_keys($user->roles); - $result = db_query(db_rewrite_sql("SELECT DISTINCT b.* FROM {blocks} b LEFT JOIN {blocks_roles} r ON b.module = r.module AND b.delta = r.delta WHERE b.theme = '%s' AND b.status = 1 AND (r.rid IN (". db_placeholders($rids) .") OR r.rid IS NULL) ORDER BY b.region, b.weight, b.module", 'b', 'bid'), array_merge(array($theme_key), $rids)); + $result = db_query(db_rewrite_sql("SELECT DISTINCT b.* FROM [{blocks}] b LEFT JOIN [{blocks_roles}] r ON b.[module] = r.[module] AND b.[delta] = r.[delta] WHERE b.[theme] = %s AND b.[status] = 1 AND (r.[rid] IN (". db_placeholders($rids) .") OR r.[rid] IS NULL) ORDER BY b.[region], b.[weight], b.[module]", 'b', 'bid'), array_merge(array($theme_key), $rids)); while ($block = db_fetch_object($result)) { if (!isset($blocks[$block->region])) { $blocks[$block->region] = array(); Index: modules/blog/blog.module =================================================================== RCS file: /cvs/drupal/drupal/modules/blog/blog.module,v retrieving revision 1.297 diff -u -p -r1.297 blog.module --- modules/blog/blog.module 9 Jan 2008 09:51:34 -0000 1.297 +++ modules/blog/blog.module 31 Mar 2008 17:26:48 -0000 @@ -86,7 +86,7 @@ function blog_form(&$node) { $node->body = ''. $blog->body .' ['. l($blog->name, "node/$nid") .']'; } - if ($iid && $item = db_fetch_object(db_query('SELECT i.*, f.title as ftitle, f.link as flink FROM {aggregator_item} i, {aggregator_feed} f WHERE i.iid = %d AND i.fid = f.fid', $iid))) { + if ($iid && $item = db_fetch_object(db_query('SELECT i.*, f.[title] AS [ftitle], f.[link] AS [flink] FROM [{aggregator_item}] i, [{aggregator_feed}] f WHERE i.[iid] = %d AND i.[fid] = f.[fid]', $iid))) { $node->title = $item->title; // Note: $item->description has been validated on aggregation. $node->body = ''. check_plain($item->title) .' - '. $item->description .' ['. check_plain($item->ftitle) ."]\n"; @@ -180,7 +180,7 @@ function blog_block($op = 'list', $delta } else if ($op == 'view') { if (user_access('access content')) { - $result = db_query_range(db_rewrite_sql("SELECT n.nid, n.title, n.created FROM {node} n WHERE n.type = 'blog' AND n.status = 1 ORDER BY n.created DESC"), 0, 10); + $result = db_query_range(db_rewrite_sql("SELECT n.[nid], n.[title], n.[created] FROM [{node}] n WHERE n.[type] = 'blog' AND n.[status] = 1 ORDER BY n.[created] DESC"), 0, 10); if ($node_title_list = node_title_list($result)) { $block['content'] = $node_title_list; $block['content'] .= theme('more_link', url('blog'), t('Read the latest blog entries.')); Index: modules/blog/blog.pages.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/blog/blog.pages.inc,v retrieving revision 1.6.2.1 diff -u -p -r1.6.2.1 blog.pages.inc --- modules/blog/blog.pages.inc 8 Feb 2008 21:15:12 -0000 1.6.2.1 +++ modules/blog/blog.pages.inc 31 Mar 2008 17:26:48 -0000 @@ -25,7 +25,7 @@ function blog_page_user($account) { $output = theme('item_list', $items); - $result = pager_query(db_rewrite_sql("SELECT n.nid, n.sticky, n.created FROM {node} n WHERE n.type = 'blog' AND n.uid = %d AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC"), variable_get('default_nodes_main', 10), 0, NULL, $account->uid); + $result = pager_query(db_rewrite_sql("SELECT n.[nid], n.[sticky], n.[created] FROM [{node}] n WHERE n.[type] = 'blog' AND n.[uid] = %d AND n.[status] = 1 ORDER BY n.[sticky] DESC, n.[created] DESC"), variable_get('default_nodes_main', 10), 0, NULL, $account->uid); $has_posts = FALSE; while ($node = db_fetch_object($result)) { @@ -64,7 +64,7 @@ function blog_page_last() { $output = theme('item_list', $items); - $result = pager_query(db_rewrite_sql("SELECT n.nid, n.created FROM {node} n WHERE n.type = 'blog' AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC"), variable_get('default_nodes_main', 10)); + $result = pager_query(db_rewrite_sql("SELECT n.[nid], n.[created] FROM [{node}] n WHERE n.[type] = 'blog' AND n.[status] = 1 ORDER BY n.[sticky] DESC, n.[created] DESC"), variable_get('default_nodes_main', 10)); $has_posts = FALSE; while ($node = db_fetch_object($result)) { @@ -87,7 +87,7 @@ function blog_page_last() { * Menu callback; displays an RSS feed containing recent blog entries of a given user. */ function blog_feed_user($account) { - $result = db_query_range(db_rewrite_sql("SELECT n.nid, n.created FROM {node} n WHERE n.type = 'blog' AND n.uid = %d AND n.status = 1 ORDER BY n.created DESC"), $account->uid, 0, variable_get('feed_default_items', 10)); + $result = db_query_range(db_rewrite_sql("SELECT n.[nid], n.[created] FROM [{node}] n WHERE n.[type] = 'blog' AND n.[uid] = %d AND n.[status] = 1 ORDER BY n.[created] DESC"), $account->uid, 0, variable_get('feed_default_items', 10)); $channel['title'] = $account->name ."'s blog"; $channel['link'] = url('blog/'. $account->uid, array('absolute' => TRUE)); @@ -102,7 +102,7 @@ function blog_feed_user($account) { * Menu callback; displays an RSS feed containing recent blog entries of all users. */ function blog_feed_last() { - $result = db_query_range(db_rewrite_sql("SELECT n.nid, n.created FROM {node} n WHERE n.type = 'blog' AND n.status = 1 ORDER BY n.created DESC"), 0, variable_get('feed_default_items', 10)); + $result = db_query_range(db_rewrite_sql("SELECT n.[nid], n.[created] FROM [{node}] n WHERE n.[type] = 'blog' AND n.[status] = 1 ORDER BY n.[created] DESC"), 0, variable_get('feed_default_items', 10)); $channel['title'] = variable_get('site_name', 'Drupal') .' blogs'; $channel['link'] = url('blog', array('absolute' => TRUE)); Index: modules/blogapi/blogapi.module =================================================================== RCS file: /cvs/drupal/drupal/modules/blogapi/blogapi.module,v retrieving revision 1.115.2.1 diff -u -p -r1.115.2.1 blogapi.module --- modules/blogapi/blogapi.module 7 Feb 2008 20:11:02 -0000 1.115.2.1 +++ modules/blogapi/blogapi.module 31 Mar 2008 17:26:51 -0000 @@ -338,10 +338,10 @@ function blogapi_blogger_get_recent_post } if ($bodies) { - $result = db_query_range("SELECT n.nid, n.title, r.body, r.format, n.comment, n.created, u.name FROM {node} n, {node_revisions} r, {users} u WHERE n.uid = u.uid AND n.vid = r.vid AND n.type = '%s' AND n.uid = %d ORDER BY n.created DESC", $blogid, $user->uid, 0, $number_of_posts); + $result = db_query_range("SELECT n.[nid], n.[title], r.[body], r.[format], n.[comment], n.[created], u.[name] FROM [{node}] n, [{node_revisions}] r, [{users}] u WHERE n.[uid] = u.[uid] AND n.[vid] = r.[vid] AND n.[type] = %s AND n.[uid] = %d ORDER BY n.[created] DESC", $blogid, $user->uid, 0, $number_of_posts); } else { - $result = db_query_range("SELECT n.nid, n.title, n.created, u.name FROM {node} n, {users} u WHERE n.uid = u.uid AND n.type = '%s' AND n.uid = %d ORDER BY n.created DESC", $blogid, $user->uid, 0, $number_of_posts); + $result = db_query_range("SELECT n.[nid], n.[title], n.[created], u.[name] FROM [{node}] n, [{users}] u WHERE n.[uid] = u.[uid] AND n.[type] = %s AND n.[uid] = %d ORDER BY n.[created] DESC", $blogid, $user->uid, 0, $number_of_posts); } $blogs = array(); while ($blog = db_fetch_object($result)) { Index: modules/book/book.install =================================================================== RCS file: /cvs/drupal/drupal/modules/book/book.install,v retrieving revision 1.20 diff -u -p -r1.20 book.install --- modules/book/book.install 10 Jan 2008 18:13:42 -0000 1.20 +++ modules/book/book.install 31 Mar 2008 17:26:52 -0000 @@ -16,7 +16,7 @@ function book_install() { */ function book_uninstall() { // Delete menu links. - db_query("DELETE FROM {menu_links} WHERE module = 'book'"); + db_query("DELETE FROM [{menu_links}] WHERE [module] = 'book'"); menu_cache_clear_all(); // Remove tables. drupal_uninstall_schema('book'); Index: modules/book/book.module =================================================================== RCS file: /cvs/drupal/drupal/modules/book/book.module,v retrieving revision 1.454.2.2 diff -u -p -r1.454.2.2 book.module --- modules/book/book.module 13 Feb 2008 11:20:47 -0000 1.454.2.2 +++ modules/book/bo