Yaffs site version 1.1
[yaffs-website] / vendor / drush / drush / commands / sql / sql.drush.inc
1 <?php
2
3 /**
4  * @file
5  * Drush sql commands
6  */
7
8 /**
9  * Implementation of hook_drush_help().
10  */
11 function sql_drush_help($section) {
12   switch ($section) {
13     case 'meta:sql:title':
14       return dt('SQL commands');
15     case 'meta:sql:summary':
16       return dt('Examine and modify your Drupal database.');
17     case 'drush:sql-sanitize':
18       return dt('Run sanitization operations on the current database. You can add more sanitization to this command by implementing hook_drush_sql_sync_sanitize().');
19   }
20 }
21
22 /**
23  * Implementation of hook_drush_command().
24  */
25 function sql_drush_command() {
26   $options['database'] = array(
27     'description' => 'The DB connection key if using multiple connections in settings.php.',
28     'example-value' => 'key',
29   );
30   $db_url['db-url'] = array(
31     'description' => 'A Drupal 6 style database URL.',
32     'example-value' => 'mysql://root:pass@127.0.0.1/db',
33   );
34   $options['target'] = array(
35     'description' => 'The name of a target within the specified database connection. Defaults to \'default\'.',
36     'example-value' => 'key',
37     // Gets unhidden in help_alter(). We only want to show this to D7 users but have to
38     // declare it here since some commands do not bootstrap fully.
39     'hidden' => TRUE,
40   );
41
42   $items['sql-drop'] = array(
43     'description' => 'Drop all tables in a given database.',
44     'arguments' => array(
45     ),
46     'bootstrap' => DRUSH_BOOTSTRAP_NONE,
47     'options' => array(
48       'yes' => 'Skip confirmation and proceed.',
49       'result-file' => array(
50         'description' => 'Save to a file. The file should be relative to Drupal root. Recommended.',
51         'example-value' => '/path/to/file',
52       ),
53     ) + $options + $db_url,
54     'topics' => array('docs-policy'),
55   );
56   $items['sql-conf'] = array(
57     'description' => 'Print database connection details using print_r().',
58     'hidden' => TRUE,
59     'bootstrap' => DRUSH_BOOTSTRAP_NONE,
60     'options' => array(
61       'all' => 'Show all database connections, instead of just one.',
62       'show-passwords' => 'Show database password.',
63     ) + $options,
64     'outputformat' => array(
65       'default' => 'print-r',
66       'pipe-format' => 'var_export',
67       'private-fields' => 'password',
68     ),
69   );
70   $items['sql-connect'] = array(
71     'description' => 'A string for connecting to the DB.',
72     'bootstrap' => DRUSH_BOOTSTRAP_NONE,
73     'options' => $options + $db_url + array(
74       'extra' => array(
75         'description' => 'Add custom options to the connect string.',
76         'example-value' => '--skip-column-names',
77       ),
78     ),
79     'examples' => array(
80       '`drush sql-connect` < example.sql' => 'Bash: Import SQL statements from a file into the current database.',
81       'eval (drush sql-connect) < example.sql' => 'Fish: Import SQL statements from a file into the current database.',
82     ),
83   );
84   $items['sql-create'] = array(
85     'description' => 'Create a database.',
86     'bootstrap' => DRUSH_BOOTSTRAP_NONE,
87     'examples' => array(
88       'drush sql-create' => 'Create the database for the current site.',
89       'drush @site.test sql-create' => 'Create the database as specified for @site.test.',
90       'drush sql-create --db-su=root --db-su-pw=rootpassword --db-url="mysql://drupal_db_user:drupal_db_password@127.0.0.1/drupal_db"' =>
91         'Create the database as specified in the db-url option.'
92     ),
93     'options' => array(
94       'db-su' => 'Account to use when creating a new database. Optional.',
95       'db-su-pw' => 'Password for the "db-su" account. Optional.',
96     ) + $options + $db_url,
97   );
98   $items['sql-dump'] = array(
99     'description' => 'Exports the Drupal DB as SQL using mysqldump or equivalent.',
100     'bootstrap' => DRUSH_BOOTSTRAP_NONE,
101     'examples' => array(
102       'drush sql-dump --result-file=../18.sql' => 'Save SQL dump to the directory above Drupal root.',
103       'drush sql-dump --skip-tables-key=common' => 'Skip standard tables. @see example.drushrc.php',
104       'drush sql-dump --extra=--no-data' => 'Pass extra option to dump command.',
105     ),
106     'options' => drush_sql_get_table_selection_options() + array(
107       'result-file' => array(
108         'description' => 'Save to a file. The file should be relative to Drupal root. If --result-file is provided with no value, then date based filename will be created under ~/drush-backups directory.',
109         'example-value' => '/path/to/file',
110         'value' => 'optional',
111       ),
112       'create-db' => array('hidden' => TRUE, 'description' => 'Omit DROP TABLE statements. Postgres and Oracle only.  Used by sql-sync, since including the DROP TABLE statements interfere with the import when the database is created.'),
113       'data-only' => 'Dump data without statements to create any of the schema.',
114       'ordered-dump' => 'Order by primary key and add line breaks for efficient diff in revision control. Slows down the dump. Mysql only.',
115       'gzip' => 'Compress the dump using the gzip program which must be in your $PATH.',
116       'extra' => 'Add custom options to the dump command.',
117     ) + $options + $db_url,
118   );
119   $items['sql-query'] = array(
120     'bootstrap' => DRUSH_BOOTSTRAP_NONE,
121     'description' => 'Execute a query against a database.',
122     'examples' => array(
123       'drush sql-query "SELECT * FROM users WHERE uid=1"' => 'Browse user record. Table prefixes, if used, must be added to table names by hand.',
124       'drush sql-query --db-prefix "SELECT * FROM {users} WHERE uid=1"' => 'Browse user record. Table prefixes are honored.  Caution: curly-braces will be stripped from all portions of the query.',
125       '`drush sql-connect` < example.sql' => 'Import sql statements from a file into the current database.',
126       'drush sql-query --file=example.sql' => 'Alternate way to import sql statements from a file.',
127     ),
128     'arguments' => array(
129        'query' => 'An SQL query. Ignored if \'file\' is provided.',
130     ),
131     'options' => array(
132       'result-file' => array(
133         'description' => 'Save to a file. The file should be relative to Drupal root. Optional.',
134         'example-value' => '/path/to/file',
135       ),
136       'file' => 'Path to a file containing the SQL to be run. Gzip files are accepted.',
137       'extra' => array(
138         'description' => 'Add custom options to the database connection command.',
139         'example-value' => '--skip-column-names',
140       ),
141       'db-prefix' => 'Enable replacement of braces in your query.',
142       'db-spec' => array(
143         'description' => 'A database specification',
144         'hidden' => TRUE, // Hide since this is only used with --backend calls.
145       )
146     ) + $options + $db_url,
147     'aliases' => array('sqlq'),
148   );
149   $items['sql-cli'] = array(
150     'description' => "Open a SQL command-line interface using Drupal's credentials.",
151     'bootstrap' => DRUSH_BOOTSTRAP_NONE,
152     // 'options' => $options + $db_url,
153     'allow-additional-options' => array('sql-connect'),
154     'aliases' => array('sqlc'),
155     'examples' => array(
156       'drush sql-cli' => "Open a SQL command-line interface using Drupal's credentials.",
157       'drush sql-cli --extra=-A' => "Open a SQL CLI and skip reading table information.",
158     ),
159     'remote-tty' => TRUE,
160   );
161   return $items;
162 }
163
164 /**
165  * Implements hook_drush_help_alter().
166  */
167 function sql_drush_help_alter(&$command) {
168   // Drupal 7+ only options.
169   if (drush_drupal_major_version() >= 7) {
170     if ($command['commandfile'] == 'sql') {
171       unset($command['options']['target']['hidden']);
172     }
173   }
174 }
175
176 /**
177  * Safely bootstrap Drupal to the point where we can
178  * access the database configuration.
179  */
180 function drush_sql_bootstrap_database_configuration() {
181   // Under Drupal 7, if the database is configured but empty, then
182   // DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION will throw an exception.
183   // If this happens, we'll just catch it and continue.
184   // TODO:  Fix this in the bootstrap, per http://drupal.org/node/1996004
185   try {
186     drush_bootstrap_max(DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION);
187   }
188   catch (Exception $e) {
189   }
190 }
191
192 /**
193  * Check whether further bootstrap is needed. If so, do it.
194  */
195 function drush_sql_bootstrap_further() {
196   if (!drush_get_option(array('db-url', 'db-spec'))) {
197     drush_sql_bootstrap_database_configuration();
198   }
199 }
200
201 /**
202  * Command callback. Displays the Drupal site's database connection string.
203  */
204 function drush_sql_conf() {
205   drush_sql_bootstrap_database_configuration();
206   if (drush_get_option('all')) {
207     $sqlVersion = drush_sql_get_version();
208     return $sqlVersion->getAll();
209   }
210   else {
211     $sql = drush_sql_get_class();
212     return $sql->db_spec();
213   }
214 }
215
216 /**
217  * Command callback. Emits a connect string.
218  */
219 function drush_sql_connect() {
220   drush_sql_bootstrap_further();
221   $sql = drush_sql_get_class();
222   return $sql->connect(FALSE);
223 }
224
225 /**
226  * Command callback. Create a database.
227  */
228 function drush_sql_create() {
229   drush_sql_bootstrap_further();
230   $sql = drush_sql_get_class();
231   $db_spec = $sql->db_spec();
232   // Prompt for confirmation.
233   if (!drush_get_context('DRUSH_SIMULATE')) {
234     // @todo odd - maybe for sql-sync.
235     $txt_destination = (isset($db_spec['remote-host']) ? $db_spec['remote-host'] . '/' : '') . $db_spec['database'];
236     drush_print(dt("Creating database !target. Any possible existing database will be dropped!", array('!target' => $txt_destination)));
237
238     if (!drush_confirm(dt('Do you really want to continue?'))) {
239       return drush_user_abort();
240     }
241   }
242
243   return $sql->createdb(TRUE);
244 }
245
246
247 /**
248  * Command callback. Outputs the entire Drupal database in SQL format using mysqldump or equivalent.
249  */
250 function drush_sql_dump() {
251   drush_sql_bootstrap_further();
252   $sql = drush_sql_get_class();
253   return $sql->dump(drush_get_option('result-file', FALSE));
254 }
255
256 /**
257  * Construct an array that places table names in appropriate
258  * buckets based on whether the table is to be skipped, included
259  * for structure only, or have structure and data dumped.
260  * The keys of the array are:
261  * - skip: tables to be skipped completed in the dump
262  * - structure: tables to only have their structure i.e. DDL dumped
263  * - tables: tables to have structure and data dumped
264  *
265  * @return array
266  *   An array of table names with each table name in the appropriate
267  *   element of the array.
268  */
269 function drush_sql_get_table_selection() {
270   // Skip large core tables if instructed.  Used by 'sql-drop/sql-dump/sql-sync' commands.
271   $skip_tables = _drush_sql_get_raw_table_list('skip-tables');
272   // Skip any structure-tables as well.
273   $structure_tables = _drush_sql_get_raw_table_list('structure-tables');
274   // Dump only the specified tables.  Takes precedence over skip-tables and structure-tables.
275   $tables = _drush_sql_get_raw_table_list('tables');
276
277   return array('skip' => $skip_tables, 'structure' => $structure_tables, 'tables' => $tables);
278 }
279
280 function drush_sql_get_table_selection_options() {
281   return array(
282     'skip-tables-key' => 'A key in the $skip_tables array. @see example.drushrc.php. Optional.',
283     'structure-tables-key' => 'A key in the $structure_tables array. @see example.drushrc.php. Optional.',
284     'tables-key' => 'A key in the $tables array. Optional.',
285     'skip-tables-list' => 'A comma-separated list of tables to exclude completely. Optional.',
286     'structure-tables-list' => 'A comma-separated list of tables to include for structure, but not data. Optional.',
287     'tables-list' => 'A comma-separated list of tables to transfer. Optional.',
288   );
289 }
290
291 /**
292  * Expand wildcard tables.
293  *
294  * @param array $tables
295  *   An array of table names, some of which may contain wildcards (`*`).
296  * @param array $db_tables
297  *   An array with all the existing table names in the current database.
298  * @return
299  *   $tables array with wildcards resolved to real table names.
300  */
301 function drush_sql_expand_wildcard_tables($tables, $db_tables) {
302   // Table name expansion based on `*` wildcard.
303   $expanded_db_tables = array();
304   foreach ($tables as $k => $table) {
305     // Only deal with table names containing a wildcard.
306     if (strpos($table, '*') !== FALSE) {
307       $pattern = '/^' . str_replace('*', '.*', $table) . '$/i';
308       // Merge those existing tables which match the pattern with the rest of
309       // the expanded table names.
310       $expanded_db_tables += preg_grep($pattern, $db_tables);
311     }
312   }
313   return $expanded_db_tables;
314 }
315
316 /**
317  * Filters tables.
318  *
319  * @param array $tables
320  *   An array of table names to filter.
321  * @param array $db_tables
322  *   An array with all the existing table names in the current database.
323  * @return
324  *   An array with only valid table names (i.e. all of which actually exist in
325  *   the database).
326  */
327 function drush_sql_filter_tables($tables, $db_tables) {
328   // Ensure all the tables actually exist in the database.
329   foreach ($tables as $k => $table) {
330     if (!in_array($table, $db_tables)) {
331       unset($tables[$k]);
332     }
333   }
334
335   return $tables;
336 }
337
338 /**
339  * Given the table names in the input array that may contain wildcards (`*`),
340  * expand the table names so that the array returned only contains table names
341  * that exist in the database.
342  *
343  * @param array $tables
344  *   An array of table names where the table names may contain the
345  *   `*` wildcard character.
346  * @param array $db_tables
347  *   The list of tables present in a database.
348  * @return array
349  *   An array of tables with non-existant tables removed.
350  */
351 function _drush_sql_expand_and_filter_tables($tables, $db_tables) {
352   $expanded_tables = drush_sql_expand_wildcard_tables($tables, $db_tables);
353   $tables = drush_sql_filter_tables(array_merge($tables, $expanded_tables), $db_tables);
354   $tables = array_unique($tables);
355   sort($tables);
356   return $tables;
357 }
358
359 /**
360  * Consult the specified options and return the list of tables
361  * specified.
362  *
363  * @param option_name
364  *   The option name to check: skip-tables, structure-tables
365  *   or tables.  This function will check both *-key and *-list,
366  *   and, in the case of sql-sync, will also check target-*
367  *   and source-*, to see if an alias set one of these options.
368  * @returns array
369  *   Returns an array of tables based on the first option
370  *   found, or an empty array if there were no matches.
371  */
372 function _drush_sql_get_raw_table_list($option_name) {
373   foreach(array('' => 'cli', 'target-,,source-' => NULL) as $prefix_list => $context) {
374     foreach(explode(',',$prefix_list) as $prefix) {
375       $key_list = drush_get_option($prefix . $option_name . '-key', NULL, $context);
376       foreach(explode(',', $key_list) as $key) {
377         $all_tables = drush_get_option($option_name, array());
378         if (array_key_exists($key, $all_tables)) {
379           return $all_tables[$key];
380         }
381         if ($option_name != 'tables') {
382           $all_tables = drush_get_option('tables', array());
383           if (array_key_exists($key, $all_tables)) {
384             return $all_tables[$key];
385           }
386         }
387       }
388       $table_list = drush_get_option($prefix . $option_name . '-list', NULL, $context);
389       if (isset($table_list)) {
390         return empty($table_list) ? array() : explode(',', $table_list);
391       }
392     }
393   }
394
395   return array();
396 }
397
398 /**
399  * Command callback. Executes the given SQL query on the Drupal database.
400  */
401 function drush_sql_query($query = NULL) {
402   drush_sql_bootstrap_further();
403   $filename = drush_get_option('file', NULL);
404   // Enable prefix processing when db-prefix option is used.
405   if (drush_get_option('db-prefix')) {
406     drush_bootstrap_max(DRUSH_BOOTSTRAP_DRUPAL_DATABASE);
407   }
408   if (drush_get_context('DRUSH_SIMULATE')) {
409     if ($query) {
410       drush_print(dt('Simulating sql-query: !q', array('!q' => $query)));
411     }
412     else {
413       drush_print(dt('Simulating sql-import from !f', array('!f' => drush_get_option('file'))));
414     }
415   }
416   else {
417     $sql = drush_sql_get_class(drush_get_option('db-spec'));
418     $result = $sql->query($query, $filename, drush_get_option('result-file'));
419     if (!$result) {
420       return drush_set_error('DRUSH_SQL_NO_QUERY', dt('Query failed.'));
421     }
422     drush_print(implode("\n", drush_shell_exec_output()));
423   }
424   return TRUE;
425 }
426
427 /**
428  * Command callback. Drops all tables in the database.
429  */
430 function drush_sql_drop() {
431   drush_sql_bootstrap_further();
432   $sql = drush_sql_get_class();
433   $db_spec = $sql->db_spec();
434   if (!drush_confirm(dt('Do you really want to drop all tables in the database !db?', array('!db' => $db_spec['database'])))) {
435     return drush_user_abort();
436   }
437   $tables = $sql->listTables();
438   return $sql->drop($tables);
439 }
440
441 /**
442  * Command callback. Launches console a DB backend.
443  */
444 function drush_sql_cli() {
445   drush_sql_bootstrap_further();
446   $sql = drush_sql_get_class();
447   return !(bool)drush_shell_proc_open($sql->connect());
448 }
449
450 /**
451  * Call from a pre-sql-sync hook to register an sql
452  * query to be executed in the post-sql-sync hook.
453  * @see drush_sql_pre_sql_sync() and @see drush_sql_post_sql_sync().
454  *
455  * @param $id
456  *   String containing an identifier representing this
457  *   operation.  This id is not actually used at the
458  *   moment, it is just used to fufill the contract
459  *   of drush contexts.
460  * @param $message
461  *   String with the confirmation message that describes
462  *   to the user what the post-sync operation is going
463  *   to do.  This confirmation message is printed out
464  *   just before the user is asked whether or not the
465  *   sql-sync operation should be continued.
466  * @param $query
467  *   String containing the sql query to execute.  If no
468  *   query is provided, then the confirmation message will
469  *   be displayed to the user, but no action will be taken
470  *   in the post-sync hook.  This is useful for drush modules
471  *   that wish to provide their own post-sync hooks to fix
472  *   up the target database in other ways (e.g. through
473  *   Drupal APIs).
474  */
475 function drush_sql_register_post_sync_op($id, $message, $query = NULL) {
476   $options = drush_get_context('post-sync-ops');
477
478   $options[$id] = array('message' => $message, 'query' => $query);
479
480   drush_set_context('post-sync-ops', $options);
481 }
482
483 /**
484  * Builds a confirmation message for all post-sync operations.
485  *
486  * @return string
487  *   All post-sync operation messages concatenated together.
488  */
489 function _drush_sql_get_post_sync_messages() {
490   $messages = '';
491   $operations = drush_get_context('post-sync-ops');
492   if (!empty($operations)) {
493     $messages = dt('The following operations will be done on the target database:') . "\n";
494
495     $bullets = array_column($operations, 'message');
496     $messages .= " * " . implode("\n * ", $bullets) . "\n";
497   }
498   return $messages;
499 }
500
501 /**
502  * Wrapper for drush_get_class; instantiates an driver-specific instance
503  * of SqlBase class.
504  *
505  * @param array $db_spec
506  *   If known, specify a $db_spec that the class can operate with.
507  *
508  * @throws \Drush\Sql\SqlException
509  *
510  * @return Drush\Sql\SqlBase
511  */
512 function drush_sql_get_class($db_spec = NULL) {
513   $database = drush_get_option('database', 'default');
514   $target = drush_get_option('target', 'default');
515
516   // Try a few times to quickly get $db_spec.
517   if (!empty($db_spec)) {
518     if (!empty($db_spec['driver'])) {
519       return drush_get_class(array('Drush\Sql\Sql', 'Drupal\Driver\Database\\' .  $db_spec['driver'] . '\Drush'), array($db_spec), array($db_spec['driver']));
520     }
521   }
522   elseif ($url = drush_get_option('db-url')) {
523     $url =  is_array($url) ? $url[$database] : $url;
524     $db_spec = drush_convert_db_from_db_url($url);
525     $db_spec['db_prefix'] = drush_get_option('db-prefix');
526     return drush_sql_get_class($db_spec);
527   }
528   elseif (($databases = drush_get_option('databases')) && (array_key_exists($database, $databases)) && (array_key_exists($target, $databases[$database]))) {
529     $db_spec = $databases[$database][$target];
530     return drush_sql_get_class($db_spec);
531   }
532   else {
533     // No parameter or options provided. Determine $db_spec ourselves.
534     if ($sqlVersion = drush_sql_get_version()) {
535       if ($db_spec = $sqlVersion->get_db_spec()) {
536         return drush_sql_get_class($db_spec);
537       }
538     }
539   }
540
541   throw new \Drush\Sql\SqlException('Unable to find a matching SQL Class. Drush cannot find your database connection details.');
542 }
543
544 /**
545  * Wrapper for drush_get_class; instantiates a Drupal version-specific instance
546  * of SqlVersion class.
547  *
548  * @return Drush\Sql\SqlVersion
549  */
550 function drush_sql_get_version() {
551   return drush_get_class('Drush\Sql\Sql', array(), array(drush_drupal_major_version())) ?: NULL;
552 }
553
554 /**
555  * Implements hook_drush_sql_sync_sanitize().
556  *
557  * Sanitize usernames, passwords, and sessions when the --sanitize option is used.
558  * It is also an example of how to write a database sanitizer for sql sync.
559  *
560  * To write your own sync hook function, define mymodule_drush_sql_sync_sanitize()
561  * in mymodule.drush.inc and follow the form of this function to add your own
562  * database sanitization operations via the register post-sync op function;
563  * @see drush_sql_register_post_sync_op().  This is the only thing that the
564  * sync hook function needs to do; sql-sync takes care of the rest.
565  *
566  * The function below has a lot of logic to process user preferences and
567  * generate the correct SQL regardless of whether Postgres, Mysql,
568  * Drupal 6/7/8 is in use.  A simpler sanitize function that
569  * always used default values and only worked with Drupal 6 + mysql
570  * appears in the drush.api.php.  @see hook_drush_sql_sync_sanitize().
571  */
572 function sql_drush_sql_sync_sanitize($site) {
573   $site_settings = drush_sitealias_get_record($site);
574   $databases = sitealias_get_databases_from_record($site_settings);
575   $major_version = drush_drupal_major_version();
576   $wrap_table_name = (bool) drush_get_option('db-prefix');
577   $user_table_updates = array();
578   $message_list = array();
579
580   // Sanitize passwords.
581   $newpassword = drush_get_option(array('sanitize-password', 'destination-sanitize-password'), 'password');
582   if ($newpassword != 'no' && $newpassword !== 0) {
583     $pw_op = "";
584
585     // In Drupal 6, passwords are hashed via the MD5 algorithm.
586     if ($major_version == 6) {
587       $pw_op = "MD5('$newpassword')";
588     }
589     // In Drupal 7, passwords are hashed via a more complex algorithm,
590     // available via the user_hash_password function.
591     elseif ($major_version == 7) {
592       $core = DRUSH_DRUPAL_CORE;
593       include_once $core . '/includes/password.inc';
594       include_once $core . '/includes/bootstrap.inc';
595       $hash = user_hash_password($newpassword);
596       $pw_op = "'$hash'";
597     }
598     else {
599       // D8+. Mimic Drupal's /scripts/password-hash.sh
600       drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_FULL);
601       $password_hasher = \Drupal::service('password');
602       $hash = $password_hasher->hash($newpassword);
603       $pw_op = "'$hash'";
604     }
605     if (!empty($pw_op)) {
606       $user_table_updates[] = "pass = $pw_op";
607       $message_list[] =  "passwords";
608     }
609   }
610
611   // Sanitize email addresses.
612   $newemail = drush_get_option(array('sanitize-email', 'destination-sanitize-email'), 'user+%uid@localhost.localdomain');
613   if ($newemail != 'no' && $newemail !== 0) {
614     if (strpos($newemail, '%') !== FALSE) {
615       // We need a different sanitization query for Postgres and Mysql.
616
617       $db_driver = $databases['default']['default']['driver'];
618       if ($db_driver == 'pgsql') {
619         $email_map = array('%uid' => "' || uid || '", '%mail' => "' || replace(mail, '@', '_') || '", '%name' => "' || replace(name, ' ', '_') || '");
620         $newmail =  "'" . str_replace(array_keys($email_map), array_values($email_map), $newemail) . "'";
621       }
622       elseif ($db_driver == 'mssql') {
623         $email_map = array('%uid' => "' + uid + '", '%mail' => "' + replace(mail, '@', '_') + '", '%name' => "' + replace(name, ' ', '_') + '");
624         $newmail =  "'" . str_replace(array_keys($email_map), array_values($email_map), $newemail) . "'";
625       }
626       else {
627         $email_map = array('%uid' => "', uid, '", '%mail' => "', replace(mail, '@', '_'), '", '%name' => "', replace(name, ' ', '_'), '");
628         $newmail =  "concat('" . str_replace(array_keys($email_map), array_values($email_map), $newemail) . "')";
629       }
630       $user_table_updates[] = "mail = $newmail, init = $newmail";
631     }
632     else {
633       $user_table_updates[] = "mail = '$newemail', init = '$newemail'";
634     }
635     $message_list[] = 'email addresses';
636   }
637
638   if (!empty($user_table_updates)) {
639     $table = $major_version >= 8 ? 'users_field_data' : 'users';
640     if ($wrap_table_name) {
641       $table = "{{$table}}";
642     }
643     $sanitize_query = "UPDATE {$table} SET " . implode(', ', $user_table_updates) . " WHERE uid > 0;";
644     drush_sql_register_post_sync_op('user-email', dt('Reset !message in !table table', array('!message' => implode(' and ', $message_list), '!table' => $table)), $sanitize_query);
645   }
646
647   $sanitizer = new \Drush\Commands\core\SanitizeCommands();
648   $sanitizer->doSanitize($major_version);
649 }