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 ascending Description
SqlBase

File

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