예제 #1
0
 /**
  * Invoke method, every class will have its own
  * returns true/false on completion, setting both
  * errormsg and output as necessary
  */
 function invoke()
 {
     parent::invoke();
     $result = true;
     /// Set own core attributes
     $this->does_generate = ACTION_NONE;
     //$this->does_generate = ACTION_GENERATE_HTML;
     /// These are always here
     global $CFG, $XMLDB;
     /// Do the job, setting $result as needed
     /// Get the dir containing the file
     $dirpath = required_param('dir', PARAM_PATH);
     $dirpath = $CFG->dirroot . $dirpath;
     /// Get the correct dir
     if (!empty($XMLDB->dbdirs)) {
         $dbdir =& $XMLDB->dbdirs[$dirpath];
         if ($dbdir) {
             /// Set some defaults
             $dbdir->xml_exists = false;
             $dbdir->xml_writeable = false;
             $dbdir->xml_loaded = false;
             ///Only if the directory exists
             if (!$dbdir->path_exists) {
                 return false;
             }
             $xmldb_file = new xmldb_file($dbdir->path . '/install.xml');
             ///Set the XML DTD and schema
             $xmldb_file->setDTD($CFG->dirroot . '/lib/xmldb/xmldb.dtd');
             $xmldb_file->setSchema($CFG->dirroot . '/lib/xmldb/xmldb.xsd');
             /// Set dbdir as necessary
             if ($xmldb_file->fileExists()) {
                 $dbdir->xml_exists = true;
             }
             if ($xmldb_file->fileWriteable()) {
                 $dbdir->xml_writeable = true;
             }
             /// Load the XML contents to structure
             $loaded = $xmldb_file->loadXMLStructure();
             if ($loaded && $xmldb_file->isLoaded()) {
                 $dbdir->xml_loaded = true;
                 $dbdir->filemtime = filemtime($dbdir->path . '/install.xml');
             }
             $dbdir->xml_file = $xmldb_file;
         } else {
             $this->errormsg = 'Wrong directory (' . $dirpath . ')';
             $result = false;
         }
     } else {
         $this->errormsg = 'XMLDB structure not found';
         $result = false;
     }
     /// Launch postaction if exists
     if ($this->getPostAction() && $result) {
         return $this->launch($this->getPostAction());
     }
     return $result;
 }
예제 #2
0
/**
 * Returns names of all known tables == tables that moodle knowns about.
 * @return array of lowercase table names
 */
function get_used_table_names()
{
    $table_names = array();
    $dbdirs = get_db_directories();
    foreach ($dbdirs as $dbdir) {
        $file = $dbdir . '/install.xml';
        $xmldb_file = new xmldb_file($file);
        if (!$xmldb_file->fileExists()) {
            continue;
        }
        $loaded = $xmldb_file->loadXMLStructure();
        $structure = $xmldb_file->getStructure();
        if ($loaded and $tables = $structure->getTables()) {
            foreach ($tables as $table) {
                $table_names[] = strtolower($table->name);
            }
        }
    }
    return $table_names;
}
예제 #3
0
 /**
  * Invoke method, every class will have its own
  * returns true/false on completion, setting both
  * errormsg and output as necessary
  */
 function invoke()
 {
     parent::invoke();
     $result = true;
     /// Set own core attributes
     $this->does_generate = ACTION_NONE;
     //$this->does_generate = ACTION_GENERATE_HTML;
     /// These are always here
     global $CFG, $XMLDB;
     /// Do the job, setting $result as needed
     /// Iterate over $XMLDB->dbdirs, loading their XML data to memory
     if ($XMLDB->dbdirs) {
         $dbdirs =& $XMLDB->dbdirs;
         foreach ($dbdirs as $dbdir) {
             /// Set some defaults
             $dbdir->xml_exists = false;
             $dbdir->xml_writeable = false;
             $dbdir->xml_loaded = false;
             ///Only if the directory exists
             if (!$dbdir->path_exists) {
                 continue;
             }
             $xmldb_file = new xmldb_file($dbdir->path . '/install.xml');
             /// Set dbdir as necessary
             if ($xmldb_file->fileExists()) {
                 $dbdir->xml_exists = true;
             }
             if ($xmldb_file->fileWriteable()) {
                 $dbdir->xml_writeable = true;
             }
             /// Load the XML contents to structure
             $loaded = $xmldb_file->loadXMLStructure();
             if ($loaded && $xmldb_file->isLoaded()) {
                 $dbdir->xml_loaded = true;
             }
             $dbdir->xml_file = $xmldb_file;
         }
     }
     return $result;
 }
예제 #4
0
 private function recreate_table($component, $tablename)
 {
     global $DB;
     unset($DB->donesetup);
     $manager = $DB->get_manager();
     $filename = get_component_directory($component) . "/db/install.xml";
     $xmldbfile = new xmldb_file($filename);
     if (!$xmldbfile->fileExists()) {
         throw new ddl_exception('ddlxmlfileerror', null, 'File does not exist');
     }
     $loaded = $xmldbfile->loadXMLStructure();
     if (!$loaded || !$xmldbfile->isLoaded()) {
         // Show info about the error if we can find it.
         if ($structure =& $xmldbfile->getStructure()) {
             if ($errors = $structure->getAllErrors()) {
                 throw new ddl_exception('ddlxmlfileerror', null, 'Errors found in XMLDB file: ' . implode(', ', $errors));
             }
         }
         throw new ddl_exception('ddlxmlfileerror', null, 'not loaded??');
     }
     $structure = $xmldbfile->getStructure();
     $table = $structure->getTable($tablename);
     $manager->create_table($table);
     $DB->donesetup = true;
 }
예제 #5
0
/**
 * Create temporary tables to speed up log generation
 */
function stats_temp_table_create()
{
    global $CFG, $DB;
    $dbman = $DB->get_manager();
    // We are going to use database_manager services
    stats_temp_table_drop();
    $xmlfile = $CFG->dirroot . '/lib/db/install.xml';
    $tables = array();
    // Allows for the additional xml files to be used (if necessary)
    $files = array($xmlfile => array('stats_daily' => array('temp_stats_daily'), 'stats_user_daily' => array('temp_stats_user_daily'), 'temp_enroled_template' => array('temp_enroled'), 'temp_log_template' => array('temp_log1', 'temp_log2')));
    foreach ($files as $file => $contents) {
        $xmldb_file = new xmldb_file($file);
        if (!$xmldb_file->fileExists()) {
            throw new ddl_exception('ddlxmlfileerror', null, 'File does not exist');
        }
        $loaded = $xmldb_file->loadXMLStructure();
        if (!$loaded || !$xmldb_file->isLoaded()) {
            throw new ddl_exception('ddlxmlfileerror', null, 'not loaded??');
        }
        $xmldb_structure = $xmldb_file->getStructure();
        foreach ($contents as $template => $names) {
            $table = $xmldb_structure->getTable($template);
            if (is_null($table)) {
                throw new ddl_exception('ddlunknowntable', null, 'The table ' . $name . ' is not defined in the file ' . $xmlfile);
            }
            $table->setNext(null);
            $table->setPrevious(null);
            foreach ($names as $name) {
                $named = clone $table;
                $named->setName($name);
                $tables[$name] = $named;
            }
        }
    }
    try {
        foreach ($tables as $table) {
            $dbman->create_temp_table($table);
        }
    } catch (Exception $e) {
        mtrace('Temporary table creation failed: ' . $e->getMessage());
        return false;
    }
    return true;
}
예제 #6
0
 /**
  * Invoke method, every class will have its own
  * returns true/false on completion, setting both
  * errormsg and output as necessary
  */
 function invoke()
 {
     parent::invoke();
     $result = true;
     /// Set own core attributes
     $this->does_generate = ACTION_GENERATE_HTML;
     /// These are always here
     global $CFG, $XMLDB, $DB, $OUTPUT;
     /// And we nedd some ddl suff
     $dbman = $DB->get_manager();
     /// Here we'll acummulate all the wrong fields found
     $problemsfound = array();
     /// Do the job, setting $result as needed
     /// Get the confirmed to decide what to do
     $confirmed = optional_param('confirmed', false, PARAM_BOOL);
     /// If  not confirmed, show confirmation box
     if (!$confirmed) {
         $o = '<table class="generalbox" border="0" cellpadding="5" cellspacing="0" id="notice">';
         $o .= '  <tr><td class="generalboxcontent">';
         $o .= '    <p class="centerpara">' . $this->str[$this->introstr] . '</p>';
         $o .= '    <table class="boxaligncenter" cellpadding="20"><tr><td>';
         $o .= '      <div class="singlebutton">';
         $o .= '        <form action="index.php?action=' . $this->title . '&amp;confirmed=yes&amp;sesskey=' . sesskey() . '" method="post"><fieldset class="invisiblefieldset">';
         $o .= '          <input type="submit" value="' . $this->str['yes'] . '" /></fieldset></form></div>';
         $o .= '      </td><td>';
         $o .= '      <div class="singlebutton">';
         $o .= '        <form action="index.php?action=main_view" method="post"><fieldset class="invisiblefieldset">';
         $o .= '          <input type="submit" value="' . $this->str['no'] . '" /></fieldset></form></div>';
         $o .= '      </td></tr>';
         $o .= '    </table>';
         $o .= '  </td></tr>';
         $o .= '</table>';
         $this->output = $o;
     } else {
         /// The back to edit table button
         $b = ' <p class="centerpara buttons">';
         $b .= '<a href="index.php">[' . $this->str['back'] . ']</a>';
         $b .= '</p>';
         /// Iterate over $XMLDB->dbdirs, loading their XML data to memory
         if ($XMLDB->dbdirs) {
             $dbdirs =& $XMLDB->dbdirs;
             $o = '<ul>';
             foreach ($dbdirs as $dbdir) {
                 /// Only if the directory exists
                 if (!$dbdir->path_exists) {
                     continue;
                 }
                 /// Load the XML file
                 $xmldb_file = new xmldb_file($dbdir->path . '/install.xml');
                 /// Only if the file exists
                 if (!$xmldb_file->fileExists()) {
                     continue;
                 }
                 /// Load the XML contents to structure
                 $loaded = $xmldb_file->loadXMLStructure();
                 if (!$loaded || !$xmldb_file->isLoaded()) {
                     echo $OUTPUT->notification('Errors found in XMLDB file: ' . $dbdir->path . '/install.xml');
                     continue;
                 }
                 /// Arriving here, everything is ok, get the XMLDB structure
                 $structure = $xmldb_file->getStructure();
                 $o .= '    <li>' . str_replace($CFG->dirroot . '/', '', $dbdir->path . '/install.xml');
                 /// Getting tables
                 if ($xmldb_tables = $structure->getTables()) {
                     $o .= '        <ul>';
                     /// Foreach table, process its fields
                     foreach ($xmldb_tables as $xmldb_table) {
                         /// Skip table if not exists
                         if (!$dbman->table_exists($xmldb_table)) {
                             continue;
                         }
                         /// Fetch metadata from physical DB. All the columns info.
                         if (!($metacolumns = $DB->get_columns($xmldb_table->getName()))) {
                             //// Skip table if no metacolumns is available for it
                             continue;
                         }
                         /// Table processing starts here
                         $o .= '            <li>' . $xmldb_table->getName();
                         /// Do the specific check.
                         list($output, $newproblems) = $this->check_table($xmldb_table, $metacolumns);
                         $o .= $output;
                         $problemsfound = array_merge($problemsfound, $newproblems);
                         $o .= '    </li>';
                         /// Give the script some more time (resetting to current if exists)
                         if ($currenttl = @ini_get('max_execution_time')) {
                             @ini_set('max_execution_time', $currenttl);
                         }
                     }
                     $o .= '        </ul>';
                 }
                 $o .= '    </li>';
             }
             $o .= '</ul>';
         }
         /// Create a report of the problems found.
         $r = $this->display_results($problemsfound);
         /// Combine the various bits of output.
         $this->output = $b . $r . $o;
     }
     /// Launch postaction if exists (leave this here!)
     if ($this->getPostAction() && $result) {
         return $this->launch($this->getPostAction());
     }
     /// Return ok if arrived here
     return $result;
 }
 /**
  * Given one "real" tablename, create one temp table suitable for be used in backup/restore operations
  */
 public static function create_temptable_from_real_table($backupid, $realtablename, $temptablename)
 {
     global $CFG, $DB;
     $dbman = $DB->get_manager();
     // We are going to use database_manager services
     // As far as xmldb objects use a lot of circular references (prev and next) and we aren't destroying
     // them at all, that causes one memory leak of about 3M per backup execution, not problematic for
     // individual backups but critical for automated (multiple) ones.
     // So we are statically caching the xmldb_table definition here to produce the leak "only" once
     static $xmldb_tables = array();
     // Not cached, get it
     if (!isset($xmldb_tables[$realtablename])) {
         // Note: For now we are going to load the realtablename from core lib/db/install.xml
         // that way, any change in the "template" will be applied here automatically. If this causes
         // too much slow, we can always forget about the template and keep maintained the xmldb_table
         // structure inline - manually - here.
         // TODO: Right now, loading the whole lib/db/install.xml is "eating" 10M, we should
         // change our way here in order to decrease that memory usage
         $templatetablename = $realtablename;
         $targettablename = $temptablename;
         $xmlfile = $CFG->dirroot . '/lib/db/install.xml';
         $xmldb_file = new xmldb_file($xmlfile);
         if (!$xmldb_file->fileExists()) {
             throw new ddl_exception('ddlxmlfileerror', null, 'File does not exist');
         }
         $loaded = $xmldb_file->loadXMLStructure();
         if (!$loaded || !$xmldb_file->isLoaded()) {
             throw new ddl_exception('ddlxmlfileerror', null, 'not loaded??');
         }
         $xmldb_structure = $xmldb_file->getStructure();
         $xmldb_table = $xmldb_structure->getTable($templatetablename);
         if (is_null($xmldb_table)) {
             throw new ddl_exception('ddlunknowntable', null, 'The table ' . $templatetablename . ' is not defined in file ' . $xmlfile);
         }
         // Clean prev & next, we are alone
         $xmldb_table->setNext(null);
         $xmldb_table->setPrevious(null);
         // Rename
         $xmldb_table->setName($targettablename);
         // Cache it
         $xmldb_tables[$realtablename] = $xmldb_table;
     }
     // Arrived here, we have the table always in static cache, get it
     $xmldb_table = $xmldb_tables[$realtablename];
     // Set default backupid (not needed but this enforce any missing backupid). That's hackery in action!
     $xmldb_table->getField('backupid')->setDefault($backupid);
     $dbman->create_temp_table($xmldb_table);
     // And create it
 }
 /**
  * Reads the install.xml files for Moodle core and modules and returns an array of
  * xmldb_structure object with xmldb_table from these files.
  * @return xmldb_structure schema from install.xml files
  */
 public function get_install_xml_schema()
 {
     global $CFG;
     require_once $CFG->libdir . '/adminlib.php';
     $schema = new xmldb_structure('export');
     $schema->setVersion($CFG->version);
     $dbdirs = get_db_directories();
     foreach ($dbdirs as $dbdir) {
         $xmldb_file = new xmldb_file($dbdir . '/install.xml');
         if (!$xmldb_file->fileExists() or !$xmldb_file->loadXMLStructure()) {
             continue;
         }
         $structure = $xmldb_file->getStructure();
         $tables = $structure->getTables();
         foreach ($tables as $table) {
             $table->setPrevious(null);
             $table->setNext(null);
             $schema->addTable($table);
         }
     }
     return $schema;
 }
예제 #9
0
 /**
  * Finds all of the XMLDB files within a given plugin path and sets up the overlay table array to include
  * the tables defined within those plugins.
  *
  * @param string $path The path to look for modules in
  * @return array An array of extra overlay tables
  */
 protected static function load_plugin_xmldb($path)
 {
     global $CFG;
     require_once $CFG->libdir . '/ddllib.php';
     $tables = array();
     switch ($path) {
         case 'mod':
             $prefix = 'mod_';
             break;
         case 'course/format':
             $prefix = 'format_';
             break;
         default:
             return array();
     }
     $plugins = get_list_of_plugins($path);
     if ($plugins) {
         foreach ($plugins as $plugin) {
             if (!file_exists($CFG->dirroot . '/' . $path . '/' . $plugin . '/db/install.xml')) {
                 continue;
             }
             // Load the XMLDB file and pull the tables out of the XML strcture.
             $xmldbfile = new xmldb_file($CFG->dirroot . '/' . $path . '/' . $plugin . '/db/install.xml');
             if (!$xmldbfile->fileExists()) {
                 continue;
             }
             $xmldbfile->loadXMLStructure();
             $xmldbstructure = $xmldbfile->getStructure();
             $xmldbtables = $xmldbstructure->getTables();
             if (!empty($xmldbtables)) {
                 foreach ($xmldbtables as $xmldbtable) {
                     // Add each table to the list of overlay tables.
                     $tables[$xmldbtable->getName()] = $prefix . $plugin;
                 }
             }
         }
     }
     return $tables;
 }
예제 #10
0
function cleanup()
{
    global $DB;
    $dbman = $DB->get_manager();
    $tablename = student::TABLE;
    $tempname = $tablename . '_temp';
    $table = new xmldb_table($tempname);
    if ($dbman->table_exists($table)) {
        if (!$dbman->drop_table($table)) {
            mtrace(' <<< Could not remove temporary table: ' . $tempname);
            exit;
        }
    }
    // Create a temporary table by reading in the XMLDB file that defines the student enrolment table
    $xmldb_file = new xmldb_file(elispm::file('db/install.xml'));
    if (!$xmldb_file->fileExists() or !$xmldb_file->loadXMLStructure()) {
        continue;
    }
    $structure = $xmldb_file->getStructure();
    $tables = $structure->getTables();
    foreach ($tables as $table) {
        if ($table->getName() == $tablename) {
            $xml_temptable = $table;
            $xml_temptable->setName($tempname);
            $xml_temptable->setPrevious(null);
            $xml_temptable->setNext(null);
            $tempstructure = new xmldb_structure('temp');
            $tempstructure->addTable($xml_temptable);
            try {
                $dbman->install_from_xmldb_structure($tempstructure);
            } catch (ddl_change_structure_exception $e) {
                mtrace(' <<< Could not create temporary table: ' . $tempname);
                exit;
            }
            mtrace(' >>> Created temporary table: ' . $tempname);
        }
    }
    $xml_table = new xmldb_table($tablename);
    // Step 1. -- attempt to move unique values into the temporary table in a way that should leave some duplicates but
    //            will remove the vast majority of the them
    $sql = "INSERT INTO {{$tempname}}\n                SELECT id, classid, userid, enrolmenttime, MIN(completetime) AS completetime, endtime, completestatusid,\n                       grade, credits, locked\n                FROM {{$tablename}}\n                GROUP BY classid, userid, completestatusid, grade, credits, locked";
    try {
        $DB->execute($sql);
    } catch (dml_exception $e) {
        mtrace(' <<< Could not move duplicate records from: ' . $tablename . ' into: ' . $tempname);
        exit;
    }
    mtrace(' >>> Moved duplicate records from: ' . $tablename . ' into: ' . $tempname);
    // Step 2. -- detect if we still have any duplicates remaining
    $sql = "SELECT id, COUNT(*) AS count, classid, userid, enrolmenttime, completetime, completestatusid, grade, credits, locked\n            FROM {{$tempname}}\n            GROUP BY classid, userid\n            ORDER BY count DESC, classid ASC, userid ASC";
    if ($dupcount = $DB->get_records_sql($sql, array(), 0, 1)) {
        $dupe = current($dupcount);
        if ($dupe->count > 1) {
            mtrace(' <<< Duplicate records still exist in temporary table');
        } else {
            mtrace(' >>> No duplicate records exist in temporary table');
        }
    }
    // Step 3. -- at this point duplicate data was found, so we will need to process each record in turn to find the first
    //            legitimate record that should be kept
    if ($rs = $DB->get_recordset_sql($sql)) {
        foreach ($rs as $dupe) {
            if ($dupe->count <= 1) {
                continue;
            }
            $classid = $dupe->classid;
            $userid = $dupe->userid;
            $goodid = 0;
            // The ID of the record we will keep
            // Find the record marked "complete" or "failed" and locked with the earliest completion time
            $sql2 = "SELECT id, completestatusid, grade locked\n                     FROM {{$tempname}}\n                     WHERE userid = {$userid}\n                     AND classid = {$classid}\n                     ORDER BY completetime ASC, completestatusid ASC, locked ASC";
            if ($rs2 = $DB->get_recordset_sql($sql2)) {
                foreach ($rs2 as $rec) {
                    // Store the last record ID just in case we need it for cleanup
                    $lastid = $rec->id;
                    // Don't bother looking at remaining records if we have found a record to keep
                    if (!empty($goodid)) {
                        continue;
                    }
                    if ($rec->completestatusid != 0 && ($rec->locked = 1)) {
                        $goodid = $rec->id;
                    }
                }
                $rs2->close();
                // We need to make sure we have a record ID to keep, if we found no "complete" and locked
                // records, let's just keep the last record we saw
                if (empty($goodid)) {
                    $goodid = $lastid;
                }
                $select = 'classid = ' . $classid . ' AND userid = ' . $userid . ' AND id != ' . $goodid;
            }
            // If we have some records to clean up, let's do that now
            if (!empty($select)) {
                $status = true;
                try {
                    $DB->delete_records_select($tempname, $select);
                } catch (dml_exception $e) {
                    mtrace(' <<< Could not clean up duplicate ' . $tempname . ' records for userid = ' . $userid . ', classid = ' . $classid);
                    $status = false;
                }
                if ($status) {
                    mtrace(' >>> Cleaned up duplicate ' . $tempname . ' records for userid = ' . $userid . ', classid = ' . $classid);
                }
            }
        }
        $rs->close();
    }
    // Step 4. -- drop the table containing duplicate values and rename the temporary table to take it's place
    try {
        $dbman->drop_table($xml_table);
    } catch (ddl_change_structure_exception $e) {
        mtrace(' <<< Could not drop table: ' . $tablename);
        exit;
    }
    mtrace(' >>> Successfully dropped table: ' . $tablename);
    // Rename the temporary table to allow it to replace the real table
    try {
        $dbman->rename_table($xml_temptable, $tablename);
    } catch (ddl_change_structure_exception $e) {
        mtrace(' <<< Could not rename table: ' . $tempname . ' to: ' . $tablename);
        exit;
    }
    mtrace(' >>> Successfully renamed table: ' . $tempname . ' to: ' . $tablename);
}