diff --git a/lib/dml/moodle_database.php b/lib/dml/moodle_database.php index 4fa3ca432c9..ef53f0830a7 100644 --- a/lib/dml/moodle_database.php +++ b/lib/dml/moodle_database.php @@ -1101,6 +1101,20 @@ abstract class moodle_database { */ public abstract function get_recordset_sql($sql, array $params=null, $limitfrom=0, $limitnum=0); + /** + * Get all records from a table. + * + * This method works around potential memory problems and may improve performance, + * this method may block access to table until the recordset is closed. + * + * @param string $table Name of database table. + * @return moodle_recordset A moodle_recordset instance {@link function get_recordset}. + * @throws dml_exception A DML specific exception is thrown for any errors. + */ + public function export_table_recordset($table) { + return $this->get_recordset($table, array()); + } + /** * Get a number of records as an array of objects where all the given conditions met. * diff --git a/lib/dml/mysqli_native_moodle_database.php b/lib/dml/mysqli_native_moodle_database.php index 38eb523a9b3..5a91e9c91d1 100644 --- a/lib/dml/mysqli_native_moodle_database.php +++ b/lib/dml/mysqli_native_moodle_database.php @@ -909,6 +909,27 @@ class mysqli_native_moodle_database extends moodle_database { return $this->create_recordset($result); } + /** + * Get all records from a table. + * + * This method works around potential memory problems and may improve performance, + * this method may block access to table until the recordset is closed. + * + * @param string $table Name of database table. + * @return moodle_recordset A moodle_recordset instance {@link function get_recordset}. + * @throws dml_exception A DML specific exception is thrown for any errors. + */ + public function export_table_recordset($table) { + $sql = $this->fix_table_names("SELECT * FROM {{$table}}"); + + $this->query_start($sql, array(), SQL_QUERY_SELECT); + // MYSQLI_STORE_RESULT may eat all memory for large tables, unfortunately MYSQLI_USE_RESULT blocks other queries. + $result = $this->mysqli->query($sql, MYSQLI_USE_RESULT); + $this->query_end($result); + + return $this->create_recordset($result); + } + protected function create_recordset($result) { return new mysqli_native_moodle_recordset($result); } diff --git a/lib/dml/tests/dml_test.php b/lib/dml/tests/dml_test.php index 4289cbbe863..c820be99ca7 100644 --- a/lib/dml/tests/dml_test.php +++ b/lib/dml/tests/dml_test.php @@ -1300,6 +1300,36 @@ class dml_testcase extends database_driver_testcase { // note: fetching nulls, empties, LOBs already tested by test_insert_record() no needed here } + public function test_export_table_recordset() { + $DB = $this->tdb; + $dbman = $DB->get_manager(); + + $table = $this->get_test_table(); + $tablename = $table->getName(); + + $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); + $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); + $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); + $dbman->create_table($table); + + $ids = array(); + $ids[] = $DB->insert_record($tablename, array('course' => 3)); + $ids[] = $DB->insert_record($tablename, array('course' => 5)); + $ids[] = $DB->insert_record($tablename, array('course' => 4)); + $ids[] = $DB->insert_record($tablename, array('course' => 3)); + $ids[] = $DB->insert_record($tablename, array('course' => 2)); + $ids[] = $DB->insert_record($tablename, array('course' => 1)); + $ids[] = $DB->insert_record($tablename, array('course' => 0)); + + $rs = $DB->export_table_recordset($tablename); + $rids = array(); + foreach ($rs as $record) { + $rids[] = $record->id; + } + $rs->close(); + $this->assertEquals($ids, $rids, '', 0, 0, true); + } + public function test_get_records() { $DB = $this->tdb; $dbman = $DB->get_manager(); diff --git a/lib/dtl/database_exporter.php b/lib/dtl/database_exporter.php index 5d3c1218030..4d9b7bb0dfb 100644 --- a/lib/dtl/database_exporter.php +++ b/lib/dtl/database_exporter.php @@ -144,7 +144,7 @@ abstract class database_exporter { $tables = $this->schema->getTables(); $this->begin_database_export($CFG->version, $CFG->release, date('c'), $description); foreach ($tables as $table) { - $rs = $this->mdb->get_recordset_sql('SELECT * FROM {'.$table->getName().'}'); + $rs = $this->mdb->export_table_recordset($table->getName()); if (!$rs) { throw new ddl_table_missing_exception($table->getName()); }