MDL-35129 implement new export_table_recordset()

This is necessary because MySQL get_recordset_sql() stores the data in memory, unfortunately the alternative resultset iteration blocks concurrent access - that is why we need new method for export.
This commit is contained in:
Petr Škoda 2012-09-15 10:49:48 +02:00
parent 1025b58b44
commit cabc411215
4 changed files with 66 additions and 1 deletions

View File

@ -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.
*

View File

@ -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);
}

View File

@ -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();

View File

@ -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());
}