Skip to content

Instantly share code, notes, and snippets.

@jfut
Last active March 16, 2021 08:17
Show Gist options
  • Save jfut/52778f2db456384c2547a0800e1420ef to your computer and use it in GitHub Desktop.
Save jfut/52778f2db456384c2547a0800e1420ef to your computer and use it in GitHub Desktop.
moodle-v3.1.17-dbtransfer-retry.patch
diff --git a/admin/tool/dbtransfer/cli/migrate.php b/admin/tool/dbtransfer/cli/migrate.php
index 0d32e2ae..dea01740 100644
--- a/admin/tool/dbtransfer/cli/migrate.php
+++ b/admin/tool/dbtransfer/cli/migrate.php
@@ -49,6 +49,10 @@ Options:
--dbport=NUMBER Database port.
--prefix=STRING Table prefix for above database tables.
--dbsocket=PATH Use database sockets. Available for some databases only.
+--dbcollation=COLLATION Use database collation for mysql/mariadb
+-r, --retry=BOOLEAN Retry to copy tables. If the number of records is the
+ same in the source and target tables, the update will
+ not be reflected.
-h, --help Print out this help.
Example:
@@ -67,11 +71,14 @@ list($options, $unrecognized) = cli_get_params(
'dbport' => null,
'prefix' => null,
'dbsocket' => null,
+ 'dbcollation' => null,
+ 'retry' => false,
'maintenance' => null,
'list' => false,
'help' => false,
),
array(
+ 'r' => 'retry',
'm' => 'maintenance',
'l' => 'list',
'h' => 'help',
@@ -167,10 +174,13 @@ if ($options['dbport']) {
if ($options['dbsocket']) {
$dboptions['dbsocket'] = $options['dbsocket'];
}
+if ($options['dbcollation']) {
+ $dboptions['dbcollation'] = $options['dbcollation'];
+}
try {
$targetdb->connect($options['dbhost'], $options['dbuser'], $options['dbpass'], $options['dbname'],
$options['prefix'], $dboptions);
- if ($targetdb->get_tables()) {
+ if ($options['retry'] == false && $targetdb->get_tables()) {
$problem .= get_string('targetdatabasenotempty', 'tool_dbtransfer');
}
} catch (moodle_exception $e) {
diff --git a/lib/dtl/database_mover.php b/lib/dtl/database_mover.php
index 419080e0..f022226c 100644
--- a/lib/dtl/database_mover.php
+++ b/lib/dtl/database_mover.php
@@ -27,6 +27,8 @@ defined('MOODLE_INTERNAL') || die();
class database_mover extends database_exporter {
/** @var database_importer Importer object used to transfer data. */
protected $importer;
+ /** @var moodle_database Connection to the target database (a @see moodle_database object). */
+ protected $importer_mdb;
/** @var progress_trace Progress tracing object */
protected $feedback;
@@ -55,6 +57,7 @@ class database_mover extends database_exporter {
parent::__construct($mdb_source, $check_schema);
$this->feedback->output(get_string('creatingtargettables', 'core_dbtransfer'));
$this->importer = new database_importer($mdb_target, $check_schema);
+ $this->importer_mdb = $mdb_target;
}
/**
@@ -119,4 +122,62 @@ class database_mover extends database_exporter {
public function finish_database_export() {
$this->importer->finish_database_import();
}
+
+ /**
+ * Generic method to export the database. It checks the schema (if
+ * @see $check_schema is true), queries the database and calls
+ * appropriate callbacks.
+ *
+ * @throws dbtransfer_exception if any checking (e.g. database schema) fails
+ *
+ * @param string $description a user description of the data.
+ */
+ public function export_database($description=null) {
+ global $CFG;
+
+ $options = array('changedcolumns' => false); // Column types may be fixed by transfer.
+ if ($this->check_schema and $errors = $this->manager->check_database_schema($this->schema, $options)) {
+ $details = '';
+ foreach ($errors as $table=>$items) {
+ $details .= '<div>'.get_string('tablex', 'dbtransfer', $table);
+ $details .= '<ul>';
+ foreach ($items as $item) {
+ $details .= '<li>'.$item.'</li>';
+ }
+ $details .= '</ul></div>';
+ }
+ throw new dbtransfer_exception('exportschemaexception', $details);
+ }
+ $tables = $this->schema->getTables();
+ $this->begin_database_export($CFG->version, $CFG->release, date('c'), $description);
+ foreach ($tables as $table) {
+ $count_source = $this->mdb->count_records($table->getName());
+ $count_target = $this->importer_mdb->count_records($table->getName());
+ if ($count_source == $count_target) {
+ // TODO: lang file
+ $this->feedback->output(' Skip copying table ' . $table->getName() . ': the same number of records, source: ' . $count_source . ', target: ' . $count_target);
+ continue;
+ } else {
+ // TODO: lang file
+ $this->feedback->output(' Re-copying all records in table ' . $table->getName() . ': different number of records, source: ' . $count_source . ', target: ' . $count_target);
+ }
+
+ $rs = $this->mdb->export_table_recordset($table->getName());
+ if (!$rs) {
+ throw new ddl_table_missing_exception($table->getName());
+ }
+ $this->begin_table_export($table);
+ foreach ($rs as $row) {
+ try {
+ $this->export_table_data($table, $row);
+ } catch (moodle_exception $e) {
+ $this->feedback->output(' Error moodle_exception: ' . $e->getMessage() . '\n' . $e->getTraceAsString());
+ throw $e;
+ }
+ }
+ $this->finish_table_export($table);
+ $rs->close();
+ }
+ $this->finish_database_export();
+ }
}
@jfut
Copy link
Author

jfut commented Mar 15, 2021

New features:

  • --dbcollation=COLLATION Use database collation for mysql/mariadb
  • -r, --retry=BOOLEAN Retry to copy tables. If the number of records is the same in the source and target tables, the update will not be reflected.
  • print stack trace for an moodle_exception
$ time php --dbtype='mariadb' --dbhost='xxx.xxx.xxx.xxx' --dbname='bitnami_moodle' --dbuser='bn_moodle' --dbport=3306 --prefix='mdl_' --dbsocket='' --dbcollation='utf8mb4_bin' -r

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment