SqlBase.php

  1. 8.0.x lib/Drush/Sql/SqlBase.php
  2. 7.x lib/Drush/Sql/SqlBase.php
  3. master lib/Drush/Sql/SqlBase.php

Namespace

Drush\Sql

Classes

Namesort descending Description
SqlBase

File

lib/Drush/Sql/SqlBase.php
View source
  1. <?php
  2. namespace Drush\Sql;
  3. use Drush\Log\LogLevel;
  4. class SqlBase {
  5. // An Drupal style array containing specs for connecting to database.
  6. public $db_spec;
  7. // Default code appended to sql-query connections.
  8. public $query_extra = '';
  9. // The way you pass a sql file when issueing a query.
  10. public $query_file = '<';
  11. /**
  12. * Typically, SqlBase objects are contructed via drush_sql_get_class().
  13. */
  14. public function __construct($db_spec = NULL) {
  15. $this->db_spec = $db_spec;
  16. }
  17. /*
  18. * Get the current $db_spec.
  19. */
  20. public function db_spec() {
  21. return $this->db_spec;
  22. }
  23. /**
  24. * The unix command used to connect to the database.
  25. * @return string
  26. */
  27. public function command() {}
  28. /**
  29. * A string for connecting to a database.
  30. *
  31. * @param bool $hide_password
  32. * If TRUE, DBMS should try to hide password from process list.
  33. * On mysql, that means using --defaults-extra-file to supply the user+password.
  34. *
  35. * @return string
  36. */
  37. public function connect($hide_password = TRUE) {
  38. return trim($this->command() . ' ' . $this->creds($hide_password) . ' ' . drush_get_option('extra', $this->query_extra));
  39. }
  40. /*
  41. * Execute a SQL dump and return the path to the resulting dump file.
  42. *
  43. * @param string|bool @file
  44. * The path where the dump file should be stored. If TRUE, generate a path
  45. * based on usual backup directory and current date.
  46. */
  47. public function dump($file = '') {
  48. $file_suffix = '';
  49. $table_selection = $this->get_expanded_table_selection();
  50. $file = $this->dumpFile($file);
  51. $cmd = $this->dumpCmd($table_selection);
  52. // Gzip the output from dump command(s) if requested.
  53. if (drush_get_option('gzip')) {
  54. $cmd .= ' | gzip -f';
  55. $file_suffix .= '.gz';
  56. }
  57. if ($file) {
  58. $file .= $file_suffix;
  59. $cmd .= ' > ' . drush_escapeshellarg($file);
  60. }
  61. // Avoid the php memory of the $output array in drush_shell_exec().
  62. if (!$return = drush_op_system($cmd)) {
  63. if ($file) {
  64. drush_log(dt('Database dump saved to !path', array('!path' => $file)), LogLevel::SUCCESS);
  65. drush_backend_set_result($file);
  66. }
  67. }
  68. else {
  69. return drush_set_error('DRUSH_SQL_DUMP_FAIL', 'Database dump failed');
  70. }
  71. }
  72. /*
  73. * Build bash for dumping a database.
  74. *
  75. * @param array $table_selection
  76. * Supported keys: 'skip', 'structure', 'tables'.
  77. * @return string
  78. * One or more mysqldump/pg_dump/sqlite3/etc statements that are ready for executing.
  79. * If multiple statements are needed, enclose in parenthesis.
  80. */
  81. public function dumpCmd($table_selection) {}
  82. /*
  83. * Generate a path to an output file for a SQL dump when needed.
  84. *
  85. * @param string|bool @file
  86. * If TRUE, generate a path based on usual backup directory and current date.
  87. * Otherwise, just return the path that was provided.
  88. */
  89. public function dumpFile($file) {
  90. $database = $this->db_spec['database'];
  91. // $file is passed in to us usually via --result-file. If the user
  92. // has set $options['result-file'] = TRUE, then we
  93. // will generate an SQL dump file in the same backup
  94. // directory that pm-updatecode uses.
  95. if ($file) {
  96. if ($file === TRUE) {
  97. // User did not pass a specific value for --result-file. Make one.
  98. $backup = drush_include_engine('version_control', 'backup');
  99. $backup_dir = $backup->prepare_backup_dir($database);
  100. if (empty($backup_dir)) {
  101. $backup_dir = drush_find_tmp();
  102. }
  103. $file = $backup_dir . '/@DATABASE_@DATE.sql';
  104. }
  105. $file = str_replace(array('@DATABASE', '@DATE'), array($database, gmdate('Ymd_His')), $file);
  106. }
  107. return $file;
  108. }
  109. /**
  110. * Execute a SQL query.
  111. *
  112. * Note: This is an API function. Try to avoid using drush_get_option() and instead
  113. * pass params in. If you don't want to query results to print during --debug then
  114. * provide a $result_file whose value can be drush_bit_bucket().
  115. *
  116. * @param string $query
  117. * The SQL to be executed. Should be NULL if $input_file is provided.
  118. * @param string $input_file
  119. * A path to a file containing the SQL to be executed.
  120. * @param string $result_file
  121. * A path to save query results to. Can be drush_bit_bucket() if desired.
  122. *
  123. * @return
  124. * TRUE on success, FALSE on failure
  125. */
  126. public function query($query, $input_file = NULL, $result_file = '') {
  127. $input_file_original = $input_file;
  128. if ($input_file && drush_file_is_tarball($input_file)) {
  129. if (drush_shell_exec('gunzip %s', $input_file)) {
  130. $input_file = trim($input_file, '.gz');
  131. }
  132. else {
  133. return drush_set_error(dt('Failed to gunzip input file.'));
  134. }
  135. }
  136. // Save $query to a tmp file if needed. We will redirect it in.
  137. if (!$input_file) {
  138. $query = $this->query_prefix($query);
  139. $query = $this->query_format($query);
  140. $input_file = drush_save_data_to_temp_file($query);
  141. }
  142. $parts = array(
  143. $this->command(),
  144. $this->creds(),
  145. $this->silent(), // This removes column header and various helpful things in mysql.
  146. drush_get_option('extra', $this->query_extra),
  147. $this->query_file,
  148. drush_escapeshellarg($input_file),
  149. );
  150. $exec = implode(' ', $parts);
  151. if ($result_file) {
  152. $exec .= ' > '. drush_escapeshellarg($result_file);
  153. }
  154. // In --verbose mode, drush_shell_exec() will show the call to mysql/psql/sqlite,
  155. // but the sql query itself is stored in a temp file and not displayed.
  156. // We show the query when --debug is used and this function created the temp file.
  157. if ((drush_get_context('DRUSH_DEBUG') || drush_get_context('DRUSH_SIMULATE')) && empty($input_file_original)) {
  158. drush_log('sql-query: ' . $query, LogLevel::NOTICE);
  159. }
  160. $success = drush_shell_exec($exec);
  161. if ($success && drush_get_option('file-delete')) {
  162. drush_op('drush_delete_dir', $input_file);
  163. }
  164. return $success;
  165. }
  166. /*
  167. * A string to add to the command when queries should not print their results.
  168. */
  169. public function silent() {}
  170. public function query_prefix($query) {
  171. // Inject table prefixes as needed.
  172. if (drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_DATABASE)) {
  173. // Enable prefix processing which can be dangerous so off by default. See http://drupal.org/node/1219850.
  174. if (drush_get_option('db-prefix')) {
  175. if (drush_drupal_major_version() >= 7) {
  176. $query = Database::getConnection()->prefixTables($query);
  177. }
  178. else {
  179. $query = db_prefix_tables($query);
  180. }
  181. }
  182. }
  183. return $query;
  184. }
  185. public function query_format($query) {
  186. return $query;
  187. }
  188. public function drop($tables) {
  189. if ($tables) {
  190. $sql = 'DROP TABLE '. implode(', ', $tables);
  191. return $this->query($sql);
  192. }
  193. }
  194. /**
  195. * Build a SQL string for dropping and creating a database.
  196. *
  197. * @param string dbname
  198. * The database name.
  199. * @param boolean $quoted
  200. * Quote the database name. Mysql uses backticks to quote which can cause problems
  201. * in a Windows shell. Set TRUE if the CREATE is not running on the bash command line.
  202. */
  203. public function createdb_sql($dbname, $quoted = FALSE) {}
  204. /**
  205. * Create a new database.
  206. *
  207. * @param boolean $quoted
  208. * Quote the database name. Mysql uses backticks to quote which can cause problems
  209. * in a Windows shell. Set TRUE if the CREATE is not running on the bash command line.
  210. */
  211. public function createdb($quoted = FALSE) {
  212. $dbname = $this->db_spec['database'];
  213. $sql = $this->createdb_sql($dbname);
  214. // Adjust connection to allow for superuser creds if provided.
  215. $this->su();
  216. return $this->query($sql);
  217. }
  218. /**
  219. * Drop all tables (if DB exists) or CREATE target database.
  220. *
  221. * return boolean
  222. * TRUE or FALSE depending on success.
  223. */
  224. public function drop_or_create() {
  225. if ($this->db_exists()) {
  226. $this->drop($this->listTables());
  227. }
  228. else {
  229. $this->createdb();
  230. }
  231. }
  232. /*
  233. * Determine if the specified DB already exists.
  234. *
  235. * @return bool
  236. */
  237. public function db_exists() {}
  238. public function delete() {}
  239. /**
  240. * Build a fragment connection parameters.
  241. *
  242. * @param bool $hide_password
  243. * If TRUE, DBMS should try to hide password from process list.
  244. * On mysql, that means using --defaults-extra-file to supply the user+password.
  245. * @return string
  246. */
  247. public function creds($hide_password = TRUE) {}
  248. /**
  249. * The active database driver.
  250. * @return string
  251. */
  252. public function scheme() {
  253. return $this->db_spec['driver'];
  254. }
  255. /**
  256. * Get a list of all table names and expand input that may contain
  257. * wildcards (`*`) if necessary so that the array returned only contains valid
  258. * table names i.e. actual tables that exist, without a wildcard.
  259. *
  260. * @return array
  261. * An array of tables with each table name in the appropriate
  262. * element of the array.
  263. */
  264. public function get_expanded_table_selection() {
  265. $table_selection = drush_sql_get_table_selection();
  266. // Get the existing table names in the specified database.
  267. $db_tables = $this->listTables();
  268. if (isset($table_selection['skip'])) {
  269. $table_selection['skip'] = _drush_sql_expand_and_filter_tables($table_selection['skip'], $db_tables);
  270. }
  271. if (isset($table_selection['structure'])) {
  272. $table_selection['structure'] = _drush_sql_expand_and_filter_tables($table_selection['structure'], $db_tables);
  273. }
  274. if (isset($table_selection['tables'])) {
  275. $table_selection['tables'] = _drush_sql_expand_and_filter_tables($table_selection['tables'], $db_tables);
  276. }
  277. return $table_selection;
  278. }
  279. /**
  280. * Extract the name of all existing tables in the given database.
  281. *
  282. * @return array
  283. * An array of table names which exist in the current database.
  284. */
  285. public function listTables() {}
  286. /*
  287. * Helper method to turn associative array into options with values.
  288. *
  289. * @return string
  290. * A bash fragment.
  291. */
  292. public function params_to_options($parameters) {
  293. // Turn each parameter into a valid parameter string.
  294. $parameter_strings = array();
  295. foreach ($parameters as $key => $value) {
  296. // Only escape the values, not the keys or the rest of the string.
  297. $value = drush_escapeshellarg($value);
  298. $parameter_strings[] = "--$key=$value";
  299. }
  300. // Join the parameters and return.
  301. return implode(' ', $parameter_strings);
  302. }
  303. /**
  304. * Adjust DB connection with superuser credentials if provided.
  305. *
  306. * The options 'db-su' and 'db-su-pw' will be retreived from the
  307. * specified site alias record, if it exists and contains those items.
  308. * If it does not, they will be fetched via drush_get_option.
  309. *
  310. * Note that in the context of sql-sync, the site alias record will
  311. * be taken from the target alias (e.g. `drush sql-sync @source @target`),
  312. * which will be overlayed with any options that begin with 'target-';
  313. * therefore, the commandline options 'target-db-su' and 'target-db-su-pw'
  314. * may also affect the operation of this function.
  315. *
  316. * @return null
  317. */
  318. public function su() {
  319. $create_db_target = $this->db_spec;
  320. $create_db_target['database'] = '';
  321. $db_superuser = drush_get_option('db-su');
  322. if (isset($db_superuser)) {
  323. $create_db_target['username'] = $db_superuser;
  324. }
  325. $db_su_pw = drush_get_option('db-su-pw');
  326. // If --db-su-pw is not provided and --db-su is, default to empty password.
  327. // This way db cli command will take password from .my.cnf or .pgpass.
  328. if (!empty($db_su_pw)) {
  329. $create_db_target['password'] = $db_su_pw;
  330. }
  331. elseif (isset($db_superuser)) {
  332. unset($create_db_target['password']);
  333. }
  334. $this->db_spec = $create_db_target;
  335. }
  336. }