After trying unsuccessfully to install Drupal 6 with a custom database prefix...

drush site-install --db-url='mysqli://username:password@domain/db' --db-prefix='drupal_' --account-name='username' --account-pass='password' --account-mail='username@domain.com' --site-name='generic' --site-mail='username@domain.com'

...Drupal 6 installed and runs, but without the prefix. Turns out that while drush_core_site_install_db_spec() parses $db_spec['db_prefix'] correctly, drush_core_pre_site_install() doesn't actually use it for Drupal 6 configurations; it just appends the $db_url to the end of the file instead of parsing / finding and replacing.

// On D6, we have to write $db_url ourselves. On D7+, the installer does it.
file_put_contents($settingsfile, "\n" . '$db_url = \'' . drush_get_option('db-url') . "';\n", FILE_APPEND);

I understand that's a design decision and easier to maintain, but the end result is that db-prefix doesn't get written.

I've attached a patch, which includes a more verbose comment about how the configuration is being written and why.

Comments

fluxsauce’s picture

Status: Active » Needs review
moshe weitzman’s picture

Version: 7.x-4.4 »
Status: Needs review » Needs work

Seems reasonable. However, db_prefix can be an array. We should var_export it, no?

fluxsauce’s picture

I've been thinking about this over the holiday weekend...

var_export would be fine in this instance.

$db_prefix_config = '$db_prefix = ' . var_export($db_prefix, TRUE) . ";\n";

The question, which makes this a little trickier: how to get the pairs?

runserver in Drush 5 doesn't parse arrays from the command line, but I think that in this instance we can get away with it due to the simplicity of database table naming conventions. (Ref: http://dev.mysql.com/doc/refman/5.5/en/identifiers.html and function db_prefix_tables - http://api.drupal.org/api/drupal/includes--database.inc/function/db_pref... )

Here's a $db_prefix definition for a multi-site configuration:

$db_prefix = array(
  'default' => 'default_',
  'users' => 'shared_',
  'sessions' => 'shared_',
  'role' => 'shared_',
  'authmap' => 'shared_',
);

This can be serialized and be included on the command line, but it's a little messy and needs to be generated.

a:5:{s:7:"default";s:8:"default_";s:5:"users";s:7:"shared_";s:8:"sessions";s:7:"shared_";s:4:"role";s:7:"shared_";s:7:"authmap";s:7:"shared_";}

Human readable proposal - If $db_spec['db_prefix'] contains comma (an illegal character for a table name), explode on comma, explode each on colon and build the $db_prefix that way.

A different separator, like | could be used instead of a comma.

Syntax: No spaces, comma separated TABLE:PREFIX

# comma
--db-prefix='default:default_,users:shared_,sessions:shared_,role:shared_,authmap:shared_'
# pipe
--db-prefix='default:default_|users:shared_|sessions:shared_|role:shared_,authmap:shared_'
# serialized, for comparison
--db-prefix='a:5:{s:7:"default";s:8:"default_";s:5:"users";s:7:"shared_";s:8:"sessions";s:7:"shared_";s:4:"role";s:7:"shared_";s:7:"authmap";s:7:"shared_";}'

Code that parses human readable pairs:

// db_prefix - parse multiple table / prefix pairs
if ((FALSE !== strpos($db_spec['db_prefix'], ',')) && FALSE !== strpos($db_spec['db_prefix'], ':')) {
  $db_config_parsed = array();
  $db_config_pairs = explode(',', $db_spec['db_prefix']);
  foreach ($db_config_pairs as $config_pair) {
    $table_prefix = explode(':', $config_pair);
    $db_config_parsed[$table_prefix[0]] = $table_prefix[1];
  }
  // Write db_prefix configuration as an array
  $db_prefix_config = '$db_prefix = ' . var_export($db_config_parsed, TRUE) . ";\n";
  file_put_contents($settingsfile, "\n" . $db_prefix_config, FILE_APPEND);
} else {
  // Write db_prefix configuration as a string
  file_put_contents($settingsfile, "\n" . '$db_prefix = \'' . $db_spec['db_prefix'] . "';\n", FILE_APPEND);
}

Thoughts? Should it include error checking? If it sounds good, I'll write the patch.

moshe weitzman’s picture

I don't mind the human readable option that much, but IMO we should do what runserver does and ask users to use drushrc.php is they need to pass an array.

fluxsauce’s picture

StatusFileSize
new2.84 KB

Makes sense, thanks for your feedback. I've attached the patch for the 7.x-4.x branch, includes documentation and example.

moshe weitzman’s picture

+++ b/commands/core/core.drush.inc
@@ -166,7 +166,7 @@ function core_drush_command() {
-      'db-prefix' => 'An optional table prefix to use for initial install.',
+      'db-prefix' => 'An optional table prefix to use for initial install.  For D6, can be a key-value array of tables/prefixes in a drushrc file (not the command line).',

Why is D6 special here? Is D7 different with respect to prefixes?

+++ b/commands/core/site_install.drush.inc
@@ -60,8 +60,21 @@ function drush_core_pre_site_install() {
+        } else {

must use two lines here per coding standards

+++ b/examples/example.drushrc.php
@@ -141,6 +141,15 @@
+// Drupal 6 database table prefix
+# $options['db-prefix'] = array(
+#   'default' => 'default_',
+#   'users' => 'shared_',
+#   'sessions' => 'shared_',
+#   'role' => 'shared_',
+#   'authmap' => 'shared_',
+# );

Lets do this as $command_specific for site-install. sql-sync does not support db_prefix.

moshe weitzman’s picture

does not apply cleanly against master branch.

greg.1.anderson’s picture

D7 puts the database prefix into the $databases array, so this patch only works with D6.

Since drush itself does not support database prefixes, this feature is slightly dubious. First step on the road, I guess, but it should support D7 as well.

fluxsauce’s picture

Status: Needs work » Needs review
StatusFileSize
new2.7 KB

Sorry about the confusion regarding branches; this patch is against the master. I adjusted the patch to use $command_specific, fixed the coding standard issue, and adjusted the help to reflect that it works for both Drupal 6 and 7 (tested, verified in both configuration and in database).

No modifications were necessary for it to work in Drupal 7, but there is a minor warning from drupal_strlen from the form validation.

Starting Drupal installation. This takes a few seconds ... [0.13 sec, 9.8 B] [ok]
WD php: Warning: mb_strlen() expects parameter 1 to be string, array given in drupal_strlen() (line 441 of /XXX/includes/unicode.inc). [0.28 sec, 17.31 MB] [warning]
WD system: user module installed. [3.28 sec, 18.75 MB] [info]
...
WD cron: Cron run completed. [31.43 sec, 35.01 MB] [notice]
Installation complete.  User name: USERNAME  User password: PASSWORD [31.44 sec, 35 MB] [ok]
mb_strlen() expects parameter 1 to be string, array given in drupal_strlen() (line 441 of /XXX/includes/unicode.inc). [31.44 sec, 35 MB] [warning]
Command dispatch complete [31.44 sec, 34.97 MB] [notice]

Drupal 7 result:

$databases = array (
  'default' =>
  array (
    'default' =>
    array (
      'database' => 'DATABASE',
      'username' => 'USERNAME',
      'password' => 'PASSWORD',
      'host' => 'HOST',
      'port' => '',
      'driver' => 'mysql',
      'prefix' =>
      array (
        'default' => 'default_',
        'users' => 'shared_',
        'sessions' => 'shared_',
        'role' => 'shared_',
        'authmap' => 'shared_',
      ),
    ),
  ),
);
moshe weitzman’s picture

Status: Needs review » Patch (to be ported)

Committed. Thanks.

I decided not to clutter the example.drushrc file with this niche example. The command docs describe what to do.

msonnabaum’s picture

Status: Patch (to be ported) » Fixed

Backported to 4.x

Automatically closed -- issue fixed for 2 weeks with no activity.