/** * 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, $db; /// ADD YOUR CODE HERE require_once $CFG->libdir . '/ddllib.php'; /// Where all the tests will be stored $tests = array(); /// The back to edit table button $b = ' <p class="centerpara buttons">'; $b .= '<a href="index.php">[' . $this->str['back'] . ']</a>'; $b .= '</p>'; $o = $b; /// Silenty drop any previous test tables $table = new XMLDBTable('testtable'); if (table_exists($table)) { $status = drop_table($table, true, false); } $table = new XMLDBTable('anothertest'); if (table_exists($table)) { $status = drop_table($table, true, false); } $table = new XMLDBTable('newnameforthetable'); if (table_exists($table)) { $status = drop_table($table, true, false); } /// 1st test. Complete table creation. $table = new XMLDBTable('testtable'); $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null); $table->addFieldInfo('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('type', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM, array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general'); $table->addFieldInfo('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null, null); $table->addFieldInfo('intro', XMLDB_TYPE_TEXT, 'small', null, XMLDB_NOTNULL, null, null, null, null); $table->addFieldInfo('logo', XMLDB_TYPE_BINARY, 'big', null, XMLDB_NOTNULL, null, null, null); $table->addFieldInfo('assessed', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('assesstimestart', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('assesstimefinish', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('scale', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('maxbytes', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('forcesubscribe', XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('trackingtype', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '1'); $table->addFieldInfo('rsstype', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('rssarticles', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('timemodified', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('grade', XMLDB_TYPE_NUMBER, '20,0', XMLDB_UNSIGNED, null, null, null, null, null); $table->addFieldInfo('percent', XMLDB_TYPE_NUMBER, '5,2', null, null, null, null, null, null); $table->addFieldInfo('warnafter', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('blockafter', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('blockperiod', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id')); $table->addKeyInfo('type-name', XMLDB_KEY_UNIQUE, array('type', 'name')); $table->addIndexInfo('course', XMLDB_INDEX_NOTUNIQUE, array('course')); $table->addIndexInfo('rsstype', XMLDB_INDEX_UNIQUE, array('rsstype')); $table->setComment("This is a test'n drop table. You can drop it safely"); /// Get SQL code and execute it $test = new stdClass(); $test->sql = $table->getCreateTableSQL($CFG->dbtype, $CFG->prefix, true); $test->status = create_table($table, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['create table'] = $test; /// 2nd test. drop table if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $test->sql = $table->getDropTableSQL($CFG->dbtype, $CFG->prefix, true); $test->status = drop_table($table, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['drop table'] = $test; } /// 3rd test. creating another, smaller table if ($test->status) { $table = new XMLDBTable('anothertest'); $table->addFieldInfo('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null); $table->addFieldInfo('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('name', XMLDB_TYPE_CHAR, '30', null, null, null, null, null, 'Moodle'); $table->addFieldInfo('secondname', XMLDB_TYPE_CHAR, '30', null, XMLDB_NOTNULL, null, null, null, null); $table->addFieldInfo('intro', XMLDB_TYPE_TEXT, 'medium', null, XMLDB_NOTNULL, null, null, null, null); $table->addFieldInfo('avatar', XMLDB_TYPE_BINARY, 'medium', null, null, null, null, null, null); $table->addFieldInfo('grade', XMLDB_TYPE_NUMBER, '20,10', null, null, null, null, null); $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id')); /// Get SQL code and execute it $test = new stdClass(); $test->sql = $table->getCreateTableSQL($CFG->dbtype, $CFG->prefix, true); $test->status = create_table($table, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['create table - 2'] = $test; } /// Insert two records to do the work with real data $rec->course = 1; $rec->name = 'Martin'; $rec->secondname = 'Dougiamas'; $rec->intro = 'The creator of Moodle'; $rec->grade = 10.0001; insert_record('anothertest', $rec); $rec->course = 2; $rec->name = 'Eloy'; $rec->secondname = 'Lafuente'; $rec->intro = 'One poor developer'; $rec->grade = 9.99; insert_record('anothertest', $rec); /// 4th test. Adding one complex enum field if ($test->status) { /// Create a new field with complex specs (enums are good candidates) $field = new XMLDBField('type'); $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM, array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general', 'course'); /// Get SQL code and execute it $test = new stdClass(); $test->sql = $table->getAddFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = add_field($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['add enum field'] = $test; } /// 5th test. Dropping one complex enum field if ($test->status) { /// Create a new field with complex specs (enums are good candidates) $test = new stdClass(); $test->sql = $table->getDropFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = drop_field($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['drop enum field'] = $test; } /// 6th test. Adding one complex enum field if ($test->status) { /// Create a new field with complex specs (enums are good candidates) $field = new XMLDBField('type'); $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM, array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general', 'course'); /// Get SQL code and execute it $test = new stdClass(); $test->sql = $table->getAddFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = add_field($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['add enum field again'] = $test; } /// 7th test. Adding one numeric field if ($test->status) { /// Create a new field (numeric) $field = new XMLDBField('onenumber'); $field->setAttributes(XMLDB_TYPE_INTEGER, '6', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, 0, 'type'); /// Get SQL code and execute it $test = new stdClass(); $test->sql = $table->getAddFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = add_field($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['add numeric field'] = $test; } /// 8th test. Dropping one complex enum field if ($test->status) { /// Create a new field with complex specs (enums are good candidates) $field = new XMLDBField('type'); $test = new stdClass(); $test->sql = $table->getDropFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = drop_field($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['drop enum field again'] = $test; } /// 9th test. Change the type of one column from integer to varchar if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('course'); $field->setAttributes(XMLDB_TYPE_CHAR, '30', null, XMLDB_NOTNULL, null, null, null, '0'); $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_type($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['change field type (int2char)'] = $test; } /// 10th test. Change the type of one column from varchar to integer if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('course'); $field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_type($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['change field type (char2int)'] = $test; } /// 11th test. Change the type of one column from number to varchar if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('grade'); $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, null, "test'n drop"); $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_type($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['change field type (number2char)'] = $test; } /// 12th test. Change the type of one column from varchar to float if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('grade'); $field->setAttributes(XMLDB_TYPE_FLOAT, '20,10', XMLDB_UNSIGNED, null, null, null, null, null); $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_type($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['change field type (char2float)'] = $test; } /// 13th test. Change the type of one column from float to char if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('grade'); $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, null, 'test'); $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_type($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['change field type (float2char)'] = $test; } /// 14th test. Change the type of one column from char to number if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('grade'); $field->setAttributes(XMLDB_TYPE_NUMBER, '20,10', XMLDB_UNSIGNED, null, null, null, null, null); $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_type($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['change field type (char2number)'] = $test; } /// 15th test. Change the precision of one text field if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('intro'); $field->setAttributes(XMLDB_TYPE_TEXT, 'big', null, XMLDB_NOTNULL, null, null, null, null); $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_precision($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['change field precision (text)'] = $test; } /// 16th test. Change the precision of one char field if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('secondname'); $field->setAttributes(XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, null, null, null); $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_precision($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['change field precision (char)'] = $test; } /// 17th test. Change the precision of one numeric field if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('grade'); $field->setAttributes(XMLDB_TYPE_NUMBER, '10,2', null, null, null, null, null, null); $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_precision($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['change field precision (number)'] = $test; } /// 18th test. Change the precision of one integer field to a smaller one if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('course'); $field->setAttributes(XMLDB_TYPE_INTEGER, '5', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_precision($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['change field precision (integer) to smaller one'] = $test; } /// 19th test. Change the sign of one numeric field to unsigned if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('grade'); $field->setAttributes(XMLDB_TYPE_NUMBER, '10,2', XMLDB_UNSIGNED, null, null, null, null, null); $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_unsigned($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['change field sign (unsigned)'] = $test; } /// 20th test. Change the sign of one numeric field to signed if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('grade'); $field->setAttributes(XMLDB_TYPE_NUMBER, '10,2', null, null, null, null, null, null); $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_unsigned($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['change field sign (signed)'] = $test; } /// 21th test. Change the nullability of one char field to not null if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('name'); $field->setAttributes(XMLDB_TYPE_CHAR, '30', null, XMLDB_NOTNULL, null, null, null, 'Moodle'); $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_notnull($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['change field nullability (not null)'] = $test; } /// 22th test. Change the nullability of one char field to null if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('name'); $field->setAttributes(XMLDB_TYPE_CHAR, '30', null, null, null, null, null, 'Moodle'); $test->sql = $table->getAlterFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_notnull($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['change field nullability (null)'] = $test; } /// 23th test. Dropping the default of one field if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('name'); $field->setAttributes(XMLDB_TYPE_CHAR, '30', null, null, null, null, null, null); $test->sql = $table->getModifyDefaultSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_default($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['drop field default of NULL field'] = $test; } /// 24th test. Creating the default for one field if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('name'); $field->setAttributes(XMLDB_TYPE_CHAR, '30', null, null, null, null, null, 'Moodle'); $test->sql = $table->getModifyDefaultSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_default($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['add field default of NULL field'] = $test; } /// 25th test. Creating the default for one field if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('secondname'); $field->setAttributes(XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, null, null, 'Moodle2'); $test->sql = $table->getModifyDefaultSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_default($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['add field default of NOT NULL field'] = $test; } /// 26th test. Dropping the default of one NOT NULL field if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('secondname'); $field->setAttributes(XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, null, null, null); $test->sql = $table->getModifyDefaultSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_default($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['drop field default of NOT NULL field'] = $test; } /// 27th test. Adding one unique index to the table if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $index = new XMLDBIndex('secondname'); $index->setAttributes(XMLDB_INDEX_UNIQUE, array('name', 'secondname', 'grade')); $test->sql = $table->getAddIndexSQL($CFG->dbtype, $CFG->prefix, $index, true); $test->status = add_index($table, $index, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['add unique index'] = $test; } /// 28th test. Adding one not unique index to the table if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $index = new XMLDBIndex('secondname'); $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('course', 'name')); $test->sql = $table->getAddIndexSQL($CFG->dbtype, $CFG->prefix, $index, true); $test->status = add_index($table, $index, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['add not unique index'] = $test; } /// 29th test. Re-add the same index than previous test. Check find_index_name() works. if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $index = new XMLDBIndex('secondname'); $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('name', 'course')); if ($indexfound = find_index_name($table, $index)) { $test->status = true; $test->sql = array(); } else { $test->status = true; $test->error = 'Index not found!'; $test->sql = array(); } $tests['check find_index_name()'] = $test; } /// 30th test. Dropping one index from the table if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $index = new XMLDBIndex('name'); $index->setAttributes(XMLDB_INDEX_UNIQUE, array('name', 'grade', 'secondname')); $test->sql = $table->getDropIndexSQL($CFG->dbtype, $CFG->prefix, $index, true); $test->status = drop_index($table, $index, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['drop index'] = $test; } /// 31th test. Adding one unique key to the table if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $key = new XMLDBKey('id-course-grade'); $key->setAttributes(XMLDB_KEY_UNIQUE, array('id', 'course', 'grade')); $test->sql = $table->getAddKeySQL($CFG->dbtype, $CFG->prefix, $key, true); $test->status = add_key($table, $key, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['add unique key'] = $test; } /// 32th test. Adding one foreign+unique key to the table if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $key = new XMLDBKey('course'); $key->setAttributes(XMLDB_KEY_FOREIGN_UNIQUE, array('course'), 'anothertest', array('id')); $test->sql = $table->getAddKeySQL($CFG->dbtype, $CFG->prefix, $key, true); $test->status = add_key($table, $key, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['add foreign+unique key'] = $test; } /// 33th test. Drop one key if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $key = new XMLDBKey('course'); $key->setAttributes(XMLDB_KEY_FOREIGN_UNIQUE, array('course'), 'anothertest', array('id')); $test->sql = $table->getDropKeySQL($CFG->dbtype, $CFG->prefix, $key, true); $test->status = drop_key($table, $key, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['drop foreign+unique key'] = $test; } /// 34th test. Adding one foreign key to the table if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $key = new XMLDBKey('course'); $key->setAttributes(XMLDB_KEY_FOREIGN, array('course'), 'anothertest', array('id')); $test->sql = $table->getAddKeySQL($CFG->dbtype, $CFG->prefix, $key, true); $test->status = add_key($table, $key, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['add foreign key'] = $test; } /// 35th test. Drop one foreign key if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $key = new XMLDBKey('course'); $key->setAttributes(XMLDB_KEY_FOREIGN, array('course'), 'anothertest', array('id')); $test->sql = $table->getDropKeySQL($CFG->dbtype, $CFG->prefix, $key, true); $test->status = drop_key($table, $key, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['drop foreign key'] = $test; } /// 36th test. Adding one complex enum field if ($test->status) { /// Create a new field with complex specs (enums are good candidates) $field = new XMLDBField('type'); $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM, array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general', 'course'); /// Get SQL code and execute it $test = new stdClass(); $test->sql = $table->getAddFieldSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = add_field($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['add field with enum'] = $test; } /// 37th test. Dropping the enum of one field if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('type'); $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, null, 'general', 'course'); $test->sql = $table->getModifyEnumSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_enum($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['delete enumlist from one field'] = $test; } /// 38th test. Creating the enum for one field if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('type'); $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM, array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general', 'course'); $test->sql = $table->getModifyEnumSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_enum($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['add enumlist to one field'] = $test; } /// 39th test. Renaming one index if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $index = new XMLDBIndex('anyname'); $index->setAttributes(XMLDB_INDEX_UNIQUE, array('name', 'course')); $test->sql = $table->getRenameIndexSQL($CFG->dbtype, $CFG->prefix, $index, 'newnamefortheindex', true); $test->status = rename_index($table, $index, 'newnamefortheindex', false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['rename index (experimental. DO NOT USE IT)'] = $test; } /// 40th test. Renaming one key if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $key = new XMLDBKey('anyname'); $key->setAttributes(XMLDB_KEY_UNIQUE, array('id', 'course', 'grade')); $test->sql = $table->getRenameKeySQL($CFG->dbtype, $CFG->prefix, $key, 'newnameforthekey', true); $test->status = rename_key($table, $key, 'newnameforthekey', false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['rename key (experimental. DO NOT USE IT)'] = $test; } /// 41th test. Renaming one field if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $field = new XMLDBField('type'); $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM, array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general', 'course'); $test->sql = $table->getRenameFieldSQL($CFG->dbtype, $CFG->prefix, $field, 'newnameforthefield', true); $test->status = rename_field($table, $field, 'newnameforthefield', false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['rename field'] = $test; } /// 42th test. Renaming one table if ($test->status) { /// Get SQL code and execute it $test = new stdClass(); $test->sql = $table->getRenameTableSQL($CFG->dbtype, $CFG->prefix, 'newnameforthetable', true); $test->status = rename_table($table, 'newnameforthetable', false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['rename table'] = $test; } /// 43th test. Add enum to field containing enum if ($test->status) { /// Add enum to field containing enum $table->setName('newnameforthetable'); $field = new XMLDBField('newnameforthefield'); $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, XMLDB_ENUM, array('single', 'news', 'general', 'social', 'eachuser', 'teacher', 'qanda'), 'general', 'course'); /// Get SQL code and execute it $test = new stdClass(); $test->sql = $table->getModifyEnumSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_enum($table, $field, false, false); /// Let's see if the constraint exists to alter results if (check_constraint_exists($table, $field)) { $test->sql = array('Nothing executed. Enum already exists. Correct.'); } else { $test->status = false; } if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['add enum to field containing enum'] = $test; } /// 44th test. Drop enum from field containing enum if ($test->status) { /// Drop enum from field containing enum $table->setName('newnameforthetable'); $field = new XMLDBField('newnameforthefield'); $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, null, 'general', 'course'); /// Get SQL code and execute it $test = new stdClass(); $test->sql = $table->getModifyEnumSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_enum($table, $field, false, false); if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['drop enum from field containing enum'] = $test; } /// 45th test. Drop enum from field not containing enum if ($test->status) { /// Drop enum from field not containing enum $table->setName('newnameforthetable'); $field = new XMLDBField('newnameforthefield'); $field->setAttributes(XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, null, 'general', 'course'); /// Get SQL code and execute it $test = new stdClass(); $test->sql = $table->getModifyEnumSQL($CFG->dbtype, $CFG->prefix, $field, true); $test->status = change_field_enum($table, $field, false, false); /// Let's see if the constraint exists to alter results if (!check_constraint_exists($table, $field)) { $test->sql = array('Nothing executed. Enum does not exists. Correct.'); } else { $test->status = false; } if (!$test->status) { $test->error = $db->ErrorMsg(); } $tests['drop enum from field not containing enum'] = $test; } /// 46th test. Getting the PK sequence name for one table if ($test->status) { $test = new stdClass(); $test->sql = array(find_sequence_name($table)); $test->status = find_sequence_name($table); if (!$test->status) { if (!($test->error = $db->ErrorMsg())) { //If no db errors, result is ok. Just the driver doesn't support this $test->sql = array('Not needed for this DB. Correct.'); $test->status = true; } } $tests['find sequence name'] = $test; } /// 47th test. Inserting TEXT contents $textlib = textlib_get_instance(); if ($test->status) { $test = new stdClass(); $test->status = false; $test->sql = array(); $basetext = "\\ ''語 • Русский • Deutsch • English • Español • Français • Italiano • Nederlands • Polski • Português • Svenska • العربية • فارسی 한국어 • עברית • ไทย中文 Ελληνικά • Български • Српски • Українська • Bosanski • Català • Česky • Dansk • Eesti • Simple English • Esperanto • Euskara • Galego • Hrvatski • Ido • Bahasa Indonesia • Íslenska • Lëtzebuergesch • Lietuvių • Magyar • Bahasa Melayu اردو • ئۇيغۇرچه • हिन्दी • नेपाल भाषा मराठी • தமிழ் Հայերեն • Беларуская • Чăваш • Ирон æвзаг • Македонски • Сибирской говор • Afrikaans • Aragonés • Arpitan • Asturianu • Kreyòl Ayisyen • Azərbaycan • Bân-lâm-gú • Basa Banyumasan • Brezhoneg • Corsu • Cymraeg • Deitsch • Føroyskt • Frysk • Furlan • Gaeilge • Gàidhlig • Ilokano • Interlingua • Basa Jawa • Kapampangan • Kernewek • Kurdî كوردی • Ladino לאדינו • Latina • Latviešu • Limburgs • Lumbaart • Nedersaksisch • Nouormand • Occitan • O‘zbek • Piemontèis • Plattdüütsch • Ripoarisch • Sámegiella • Scots • Shqip • Sicilianu • Sinugboanon • Srpskohrvatski / Српскохрватски • Basa Sunda • Kiswahili • Tagalog • Tatarça • Walon • Winaray Авар • Башҡорт • Кыргызча Монгол • Қазақша • Тоҷикӣ • Удмурт • Armãneashce • Bamanankan • Eald Englisc • Gaelg • Interlingue • Kaszëbsczi • Kongo • Ligure • Lingála • lojban • Malagasy • Malti • Māori • Nāhuatl • Ekakairũ Naoero • Novial • Pangasinán • Tok Pisin • Romani / रोमानी • Rumantsch • Runa Simi • Sardu • Tetun • Türkmen / تركمن / Туркмен • Vèneto • Volapük • Võro • West-Vlaoms • Wollof • Zazaki • Žemaitėška"; /// Create one big text (1.500.000 chars) $fulltext = ''; for ($i = 0; $i < 1000; $i++) { //1500 * 1000 chars $fulltext .= $basetext; } /// Build the record to insert $rec->intro = addslashes($fulltext); $rec->name = 'texttest'; /// Calculate its length $textlen = $textlib->strlen($fulltext); if ($rec->id = insert_record('newnameforthetable', $rec)) { if ($new = get_record('newnameforthetable', 'id', $rec->id)) { delete_records('newnameforthetable', 'id', $new->id); $newtextlen = $textlib->strlen($new->intro); if ($fulltext === $new->intro) { $test->sql = array($newtextlen . ' cc. (text) sent and received ok'); $test->status = true; } else { $test->error = $db->ErrorMsg(); $test->sql = array($newtextlen . ' cc. (text) transfer failed. Data changed!'); print_object($new); $test->status = false; } } else { $test->error = $db->ErrorMsg(); } } else { $test->error = $db->ErrorMsg(); } $tests['insert record ' . $textlen . ' cc. (text)'] = $test; } /// 48th test. Inserting BINARY contents if ($test->status) { $test = new stdClass(); $test->status = false; /// Build the record to insert $rec->avatar = addslashes($fulltext); $rec->name = 'binarytest'; /// Calculate its length $textlen = strlen($fulltext); if ($rec->id = insert_record('newnameforthetable', $rec)) { if ($new = get_record('newnameforthetable', 'id', $rec->id)) { $newtextlen = strlen($new->avatar); if ($fulltext === $new->avatar) { $test->sql = array($newtextlen . ' bytes (binary) sent and received ok'); $test->status = true; } else { $test->error = $db->ErrorMsg(); $test->sql = array($newtextlen . ' bytes (binary) transfer failed. Data changed!'); $test->status = false; } } else { $test->error = $db->ErrorMsg(); } } else { $test->error = $db->ErrorMsg(); } $tests['insert record ' . $textlen . ' bytes (binary)'] = $test; } /// 49th test. update_record with TEXT and BINARY contents if ($test->status) { $test = new stdClass(); $test->status = false; $test->sql = array(); /// Build the record to insert $rec->intro = addslashes($basetext); $rec->avatar = addslashes($basetext); $rec->name = 'updatelobs'; /// Calculate its length $textlen = $textlib->strlen($basetext); $imglen = strlen($basetext); if (update_record('newnameforthetable', $rec)) { if ($new = get_record('newnameforthetable', 'id', $rec->id)) { $newtextlen = $textlib->strlen($new->intro); $newimglen = strlen($new->avatar); if ($basetext === $new->avatar && $basetext === $new->intro) { $test->sql = array($newtextlen . ' cc. (text) sent and received ok', $newimglen . ' bytes (binary) sent and received ok'); $test->status = true; } else { if ($rec->avatar !== $new->avatar) { $test->error = $db->ErrorMsg(); $test->sql = array($newimglen . ' bytes (binary) transfer failed. Data changed!'); $test->status = false; } else { $test->error = $db->ErrorMsg(); $test->sql = array($newtextlen . ' cc. (text) transfer failed. Data changed!'); $test->status = false; } } } else { $test->error = $db->ErrorMsg(); } } else { $test->error = $db->ErrorMsg(); } $tests['update record ' . $textlen . ' cc. (text) and ' . $imglen . ' bytes (binary)'] = $test; } /// 50th test. set_field with TEXT contents if ($test->status) { $test = new stdClass(); $test->status = false; $test->sql = array(); /// Build the record to insert $rec->intro = addslashes($fulltext); $rec->name = 'updatelobs'; /// Calculate its length $textlen = $textlib->strlen($fulltext); if (set_field('newnameforthetable', 'intro', $rec->intro, 'name', $rec->name)) { if ($new = get_record('newnameforthetable', 'id', $rec->id)) { $newtextlen = $textlib->strlen($new->intro); if ($fulltext === $new->intro) { $test->sql = array($newtextlen . ' cc. (text) sent and received ok'); $test->status = true; } else { $test->error = $db->ErrorMsg(); $test->sql = array($newtextlen . ' cc. (text) transfer failed. Data changed!'); $test->status = false; } } else { $test->error = $db->ErrorMsg(); } } else { $test->error = $db->ErrorMsg(); } $tests['set field ' . $textlen . ' cc. (text)'] = $test; } /// 51th test. set_field with BINARY contents if ($test->status) { $test = new stdClass(); $test->status = false; $test->sql = array(); /// Build the record to insert $rec->avatar = addslashes($fulltext); $rec->name = 'updatelobs'; /// Calculate its length $textlen = strlen($fulltext); if (set_field('newnameforthetable', 'avatar', $rec->avatar, 'name', $rec->name)) { if ($new = get_record('newnameforthetable', 'id', $rec->id)) { $newtextlen = strlen($new->avatar); if ($fulltext === $new->avatar) { $test->sql = array($newtextlen . ' bytes (binary) sent and received ok'); $test->status = true; } else { $test->error = $db->ErrorMsg(); $test->sql = array($newtextlen . ' bytes (binary) transfer failed. Data changed!'); $test->status = false; } } else { $test->error = $db->ErrorMsg(); } } else { $test->error = $db->ErrorMsg(); } $tests['set field ' . $textlen . ' bytes (binary)'] = $test; } /// TODO: Check here values of the inserted records to see that everything ha the correct value /// Iterate over tests, showing information as needed $o .= '<ol>'; foreach ($tests as $key => $test) { $o .= '<li>' . $key . ($test->status ? '<font color="green"> Ok</font>' : ' <font color="red">Error</font>'); if (!$test->status) { $o .= '<br/><font color="red">' . $test->error . '</font>'; } $o .= '<pre>' . implode('<br/>', $test->sql) . '</pre>'; $o .= '</li>'; } $o .= '</ol>'; $this->output = $o; /// Launch postaction if exists (leave this here!) if ($this->getPostAction() && $result) { return $this->launch($this->getPostAction()); } /// Return ok if arrived here return $result; }
/** * Insert a record into a table and return the "id" field if required * * If the return ID isn't required, then this just reports success as true/false. * $dataobject is an object containing needed data * * @uses $db * @uses $CFG * @param string $table The database table to be checked against. * @param object $dataobject A data object with values for one or more fields in the record * @param bool $returnid Should the id of the newly created record entry be returned? If this option is not requested then true/false is returned. * @param string $primarykey (obsolete) This is now forced to be 'id'. */ function insert_record($table, $dataobject, $returnid = true, $primarykey = 'id') { global $db, $CFG, $empty_rs_cache; if (empty($db)) { return false; } /// Check we are handling a proper $dataobject if (is_array($dataobject)) { debugging('Warning. Wrong call to insert_record(). $dataobject must be an object. array found instead', DEBUG_DEVELOPER); $dataobject = (object) $dataobject; } /// Temporary hack as part of phasing out all access to obsolete user tables XXX if (!empty($CFG->rolesactive)) { if (in_array($table, array('user_students', 'user_teachers', 'user_coursecreators', 'user_admins'))) { if (debugging()) { var_dump(debug_backtrace()); } error('This SQL relies on obsolete tables (' . $table . ')! Your code must be fixed by a developer.'); } } if (defined('MDL_PERFDB')) { global $PERF; $PERF->dbqueries++; } /// In Moodle we always use auto-numbering fields for the primary key /// so let's unset it now before it causes any trouble later unset($dataobject->{$primarykey}); /// Get an empty recordset. Cache for multiple inserts. if (empty($empty_rs_cache[$table])) { /// Execute a dummy query to get an empty recordset if (!($empty_rs_cache[$table] = $db->Execute('SELECT * FROM ' . $CFG->prefix . $table . ' WHERE ' . $primarykey . ' = \'-1\''))) { return false; } } $rs = $empty_rs_cache[$table]; /// Postgres doesn't have the concept of primary key built in /// and will return the OID which isn't what we want. /// The efficient and transaction-safe strategy is to /// move the sequence forward first, and make the insert /// with an explicit id. if ($CFG->dbfamily === 'postgres' && $returnid == true) { if ($nextval = (int) get_field_sql("SELECT NEXTVAL('{$CFG->prefix}{$table}_{$primarykey}_seq')")) { $dataobject->{$primarykey} = $nextval; } } /// Begin DIRTY HACK if ($CFG->dbfamily == 'oracle') { oracle_dirty_hack($table, $dataobject); // Convert object to the correct "empty" values for Oracle DB } /// End DIRTY HACK /// Under Oracle, MSSQL and PostgreSQL we have our own insert record process /// detect all the clob/blob fields and change their contents to @#CLOB#@ and @#BLOB#@ /// saving them into $foundclobs and $foundblobs [$fieldname]->contents /// Same for mssql (only processing blobs - image fields) if ($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres') { $foundclobs = array(); $foundblobs = array(); db_detect_lobs($table, $dataobject, $foundclobs, $foundblobs); } /// Under Oracle, if the primary key inserted has been requested OR /// if there are LOBs to insert, we calculate the next value via /// explicit query to the sequence. /// Else, the pre-insert trigger will do the job, because the primary /// key isn't needed at all by the rest of PHP code if ($CFG->dbfamily === 'oracle' && ($returnid == true || !empty($foundclobs) || !empty($foundblobs))) { /// We need this here (move this function to dmlib?) include_once $CFG->libdir . '/ddllib.php'; $xmldb_table = new XMLDBTable($table); $seqname = find_sequence_name($xmldb_table); if (!$seqname) { /// Fallback, seqname not found, something is wrong. Inform and use the alternative getNameForObject() method debugging('Sequence name for table ' . $table->getName() . ' not found', DEBUG_DEVELOPER); $generator = new XMLDBoci8po(); $generator->setPrefix($CFG->prefix); $seqname = $generator->getNameForObject($table, $primarykey, 'seq'); } if ($nextval = (int) $db->GenID($seqname)) { $dataobject->{$primarykey} = $nextval; } else { debugging('Not able to get value from sequence ' . $seqname, DEBUG_DEVELOPER); } } /// Get the correct SQL from adoDB if (!($insertSQL = $db->GetInsertSQL($rs, (array) $dataobject, true))) { return false; } /// Under Oracle, MSSQL and PostgreSQL, replace all the '@#CLOB#@' and '@#BLOB#@' ocurrences to proper default values /// if we know we have some of them in the query if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'mssql' || $CFG->dbfamily == 'postgres') && (!empty($foundclobs) || !empty($foundblobs))) { /// Initial configuration, based on DB switch ($CFG->dbfamily) { case 'oracle': $clobdefault = 'empty_clob()'; //Value of empty default clobs for this DB $blobdefault = 'empty_blob()'; //Value of empty default blobs for this DB break; case 'mssql': case 'postgres': $clobdefault = 'null'; //Value of empty default clobs for this DB (under mssql this won't be executed $blobdefault = 'null'; //Value of empty default blobs for this DB break; } $insertSQL = str_replace("'@#CLOB#@'", $clobdefault, $insertSQL); $insertSQL = str_replace("'@#BLOB#@'", $blobdefault, $insertSQL); } /// Run the SQL statement if (!($rs = $db->Execute($insertSQL))) { debugging($db->ErrorMsg() . '<br /><br />' . s($insertSQL)); if (!empty($CFG->dblogerror)) { $debug = array_shift(debug_backtrace()); error_log("SQL " . $db->ErrorMsg() . " in {$debug['file']} on line {$debug['line']}. STATEMENT: {$insertSQL}"); } return false; } /// Under Oracle and PostgreSQL, finally, update all the Clobs and Blobs present in the record /// if we know we have some of them in the query if (($CFG->dbfamily == 'oracle' || $CFG->dbfamily == 'postgres') && !empty($dataobject->{$primarykey}) && (!empty($foundclobs) || !empty($foundblobs))) { if (!db_update_lobs($table, $dataobject->{$primarykey}, $foundclobs, $foundblobs)) { return false; //Some error happened while updating LOBs } } /// If a return ID is not needed then just return true now (but not in MSSQL DBs, where we may have some pending tasks) if (!$returnid && $CFG->dbfamily != 'mssql') { return true; } /// We already know the record PK if it's been passed explicitly, /// or if we've retrieved it from a sequence (Postgres and Oracle). if (!empty($dataobject->{$primarykey})) { return $dataobject->{$primarykey}; } /// This only gets triggered with MySQL and MSQL databases /// however we have some postgres fallback in case we failed /// to find the sequence. $id = $db->Insert_ID(); /// Under MSSQL all the Clobs and Blobs (IMAGE) present in the record /// if we know we have some of them in the query if ($CFG->dbfamily == 'mssql' && !empty($id) && (!empty($foundclobs) || !empty($foundblobs))) { if (!db_update_lobs($table, $id, $foundclobs, $foundblobs)) { return false; //Some error happened while updating LOBs } } if ($CFG->dbfamily === 'postgres') { // try to get the primary key based on id if (($rs = $db->Execute('SELECT ' . $primarykey . ' FROM ' . $CFG->prefix . $table . ' WHERE oid = ' . $id)) && $rs->RecordCount() == 1) { trigger_error("Retrieved {$primarykey} from oid on table {$table} because we could not find the sequence."); return (int) reset($rs->fields); } trigger_error('Failed to retrieve primary key after insert: SELECT ' . $primarykey . ' FROM ' . $CFG->prefix . $table . ' WHERE oid = ' . $id); return false; } return (int) $id; }
/** * Returns the names of sequences for each autoincrementing id field in all standard tables. * @static * @return array $table=>$sequencename */ public static function get_sequencenames() { if (isset(self::$sequencenames)) { return self::$sequencenames; } if (!($structure = self::get_tablestructure())) { return array(); } self::$sequencenames = array(); foreach ($structure as $table => $ignored) { $name = find_sequence_name(new XMLDBTable($table)); if ($name !== false) { self::$sequencenames[$table] = $name; } } return self::$sequencenames; }