Merge branch 'w11_MDL-31899_m23_mysqlcolumns' of git://github.com/skodak/moodle

This commit is contained in:
Eloy Lafuente (stronk7)
2012-03-12 23:16:27 +01:00
2 changed files with 201 additions and 106 deletions
+17 -3
View File
@@ -544,14 +544,14 @@ class ddl_test extends UnitTestCase {
$this->assertEqual($columns['onechar']->meta_type ,'C');
$this->assertEqual($DB->get_field('test_table1', 'onechar', array(), IGNORE_MULTIPLE), 'Nice dflt!'); //check default has been applied
/// add one text field and check it
/// add one big text field and check it
$field = new xmldb_field('onetext');
$field->set_attributes(XMLDB_TYPE_TEXT);
$field->set_attributes(XMLDB_TYPE_TEXT, 'big');
$dbman->add_field($table, $field);
$this->assertTrue($dbman->field_exists($table, 'onetext'));
$columns = $DB->get_columns('test_table1');
$this->assertEqual($columns['onetext']->name ,'onetext');
$this->assertEqual($columns['onetext']->max_length , -1);
$this->assertEqual($columns['onetext']->max_length , -1); // -1 means unknown or big
$this->assertEqual($columns['onetext']->scale , null);
$this->assertEqual($columns['onetext']->not_null , false);
$this->assertEqual($columns['onetext']->primary_key , false);
@@ -560,6 +560,20 @@ class ddl_test extends UnitTestCase {
$this->assertEqual($columns['onetext']->default_value, null);
$this->assertEqual($columns['onetext']->meta_type ,'X');
/// add one medium text field and check it
$field = new xmldb_field('mediumtext');
$field->set_attributes(XMLDB_TYPE_TEXT, 'medium');
$dbman->add_field($table, $field);
$columns = $DB->get_columns('test_table1');
$this->assertTrue(($columns['mediumtext']->max_length == -1) or ($columns['mediumtext']->max_length >= 16777215)); // -1 means unknown or big
/// add one small text field and check it
$field = new xmldb_field('smalltext');
$field->set_attributes(XMLDB_TYPE_TEXT, 'small');
$dbman->add_field($table, $field);
$columns = $DB->get_columns('test_table1');
$this->assertTrue(($columns['smalltext']->max_length == -1) or ($columns['smalltext']->max_length >= 65535)); // -1 means unknown or big
/// add one binary field and check it
$field = new xmldb_field('onebinary');
$field->set_attributes(XMLDB_TYPE_BINARY);
+184 -103
View File
@@ -439,7 +439,12 @@ class mysqli_native_moodle_database extends moodle_database {
$this->columns[$table] = array();
$sql = "SHOW COLUMNS FROM {$this->prefix}$table";
$sql = "SELECT column_name, data_type, character_maximum_length, numeric_precision,
numeric_scale, is_nullable, column_type, column_default, column_key, extra
FROM information_schema.columns
WHERE table_name = '" . $this->prefix.$table . "'
AND table_schema = '" . $this->dbname . "'
ORDER BY ordinal_position";
$this->query_start($sql, null, SQL_QUERY_AUX);
$result = $this->mysqli->query($sql);
$this->query_end(true); // Don't want to throw anything here ever. MDL-30147
@@ -448,120 +453,196 @@ class mysqli_native_moodle_database extends moodle_database {
return array();
}
while ($rawcolumn = $result->fetch_assoc()) {
$rawcolumn = (object)array_change_key_case($rawcolumn, CASE_LOWER);
if ($result->num_rows > 0) {
// standard table exists
while ($rawcolumn = $result->fetch_assoc()) {
$info = (object)$this->get_column_info((object)$rawcolumn);
$this->columns[$table][$info->name] = new database_column_info($info);
}
$result->close();
$info = new stdClass();
$info->name = $rawcolumn->field;
$matches = null;
} else {
// temporary tables are not in information schema, let's try it the old way
$result->close();
$sql = "SHOW COLUMNS FROM {$this->prefix}$table";
$this->query_start($sql, null, SQL_QUERY_AUX);
$result = $this->mysqli->query($sql);
$this->query_end(true);
if ($result === false) {
return array();
}
while ($rawcolumn = $result->fetch_assoc()) {
$rawcolumn = (object)array_change_key_case($rawcolumn, CASE_LOWER);
$rawcolumn->column_name = $rawcolumn->field; unset($rawcolumn->field);
$rawcolumn->column_type = $rawcolumn->type; unset($rawcolumn->type);
$rawcolumn->character_maximum_length = null;
$rawcolumn->numeric_precision = null;
$rawcolumn->numeric_scale = null;
$rawcolumn->is_nullable = $rawcolumn->null; unset($rawcolumn->null);
$rawcolumn->column_default = $rawcolumn->default; unset($rawcolumn->default);
$rawcolumn->column_key = $rawcolumn->key; unset($rawcolumn->default);
$rawcolumn->extra = ($rawcolumn->column_name === 'id') ? 'auto_increment' : '';
if (preg_match('/(enum|varchar)\((\d+)\)/i', $rawcolumn->type, $matches)) {
$info->type = 'varchar';
$info->meta_type = 'C';
$info->max_length = $matches[2];
$info->scale = null;
$info->not_null = ($rawcolumn->null === 'NO');
$info->default_value = $rawcolumn->default;
$info->has_default = is_null($info->default_value) ? false : true;
$info->primary_key = ($rawcolumn->key === 'PRI');
$info->binary = false;
$info->unsigned = null;
$info->auto_increment= false;
$info->unique = null;
if (preg_match('/(enum|varchar)\((\d+)\)/i', $rawcolumn->column_type, $matches)) {
$rawcolumn->data_type = $matches[1];
$rawcolumn->character_maximum_length = $matches[2];
} else if (preg_match('/([a-z]*int[a-z]*)\((\d+)\)/i', $rawcolumn->column_type, $matches)) {
$rawcolumn->data_type = $matches[1];
$rawcolumn->character_maximum_length = $matches[2];
} else if (preg_match('/(decimal)\((\d+),(\d+)\)/i', $rawcolumn->column_type, $matches)) {
$rawcolumn->data_type = $matches[1];
$rawcolumn->numeric_precision = $matches[2];
$rawcolumn->numeric_scale = $matches[3];
} else if (preg_match('/(double|float)(\((\d+),(\d+)\))?/i', $rawcolumn->column_type, $matches)) {
$rawcolumn->data_type = $matches[1];
$rawcolumn->numeric_precision = isset($matches[3]) ? $matches[3] : null;
$rawcolumn->numeric_scale = isset($matches[4]) ? $matches[4] : null;
} else if (preg_match('/([a-z]*text)/i', $rawcolumn->column_type, $matches)) {
$rawcolumn->data_type = $matches[1];
$rawcolumn->character_maximum_length = -1; // unknown
} else if (preg_match('/([a-z]*blob)/i', $rawcolumn->column_type, $matches)) {
$rawcolumn->data_type = $matches[1];
} else if (preg_match('/([a-z]*int[a-z]*)\((\d+)\)/i', $rawcolumn->type, $matches)) {
$info->type = $matches[1];
$info->primary_key = ($rawcolumn->key === 'PRI');
if ($info->primary_key) {
$info->meta_type = 'R';
$info->max_length = $matches[2];
$info->scale = null;
$info->not_null = ($rawcolumn->null === 'NO');
$info->default_value = $rawcolumn->default;
$info->has_default = is_null($info->default_value) ? false : true;
$info->binary = false;
$info->unsigned = (stripos($rawcolumn->type, 'unsigned') !== false);
$info->auto_increment= true;
$info->unique = true;
} else {
$info->meta_type = 'I';
$info->max_length = $matches[2];
$info->scale = null;
$info->not_null = ($rawcolumn->null === 'NO');
$info->default_value = $rawcolumn->default;
$info->has_default = is_null($info->default_value) ? false : true;
$info->binary = false;
$info->unsigned = (stripos($rawcolumn->type, 'unsigned') !== false);
$info->auto_increment= false;
$info->unique = null;
$rawcolumn->data_type = $rawcolumn->column_type;
}
} else if (preg_match('/(decimal)\((\d+),(\d+)\)/i', $rawcolumn->type, $matches)) {
$info->type = $matches[1];
$info->meta_type = 'N';
$info->max_length = $matches[2];
$info->scale = $matches[3];
$info->not_null = ($rawcolumn->null === 'NO');
$info->default_value = $rawcolumn->default;
$info->has_default = is_null($info->default_value) ? false : true;
$info->primary_key = ($rawcolumn->key === 'PRI');
$info->binary = false;
$info->unsigned = (stripos($rawcolumn->type, 'unsigned') !== false);
$info->auto_increment= false;
$info->unique = null;
} else if (preg_match('/(double|float)(\((\d+),(\d+)\))?/i', $rawcolumn->type, $matches)) {
$info->type = $matches[1];
$info->meta_type = 'N';
$info->max_length = isset($matches[3]) ? $matches[3] : null;
$info->scale = isset($matches[4]) ? $matches[4] : null;
$info->not_null = ($rawcolumn->null === 'NO');
$info->default_value = $rawcolumn->default;
$info->has_default = is_null($info->default_value) ? false : true;
$info->primary_key = ($rawcolumn->key === 'PRI');
$info->binary = false;
$info->unsigned = (stripos($rawcolumn->type, 'unsigned') !== false);
$info->auto_increment= false;
$info->unique = null;
} else if (preg_match('/([a-z]*text)/i', $rawcolumn->type, $matches)) {
$info->type = $matches[1];
$info->meta_type = 'X';
$info->max_length = -1;
$info->scale = null;
$info->not_null = ($rawcolumn->null === 'NO');
$info->default_value = $rawcolumn->default;
$info->has_default = is_null($info->default_value) ? false : true;
$info->primary_key = ($rawcolumn->key === 'PRI');
$info->binary = false;
$info->unsigned = null;
$info->auto_increment= false;
$info->unique = null;
} else if (preg_match('/([a-z]*blob)/i', $rawcolumn->type, $matches)) {
$info->type = $matches[1];
$info->meta_type = 'B';
$info->max_length = -1;
$info->scale = null;
$info->not_null = ($rawcolumn->null === 'NO');
$info->default_value = $rawcolumn->default;
$info->has_default = is_null($info->default_value) ? false : true;
$info->primary_key = false;
$info->binary = true;
$info->unsigned = null;
$info->auto_increment= false;
$info->unique = null;
$info = $this->get_column_info($rawcolumn);
$this->columns[$table][$info->name] = new database_column_info($info);
}
$this->columns[$table][$info->name] = new database_column_info($info);
$result->close();
}
$result->close();
return $this->columns[$table];
}
/**
* Returns moodle column info for raw column from information schema.
* @param stdClass $rawcolumn
* @return stdClass standardised colum info
*/
private function get_column_info(stdClass $rawcolumn) {
$rawcolumn = (object)$rawcolumn;
$info = new stdClass();
$info->name = $rawcolumn->column_name;
$info->type = $rawcolumn->data_type;
$info->meta_type = $this->mysqltype2moodletype($rawcolumn->data_type);
$info->default_value = $rawcolumn->column_default;
$info->has_default = !is_null($rawcolumn->column_default);
$info->not_null = ($rawcolumn->is_nullable === 'NO');
$info->primary_key = ($rawcolumn->column_key === 'PRI');
$info->binary = false;
$info->unsigned = null;
$info->auto_increment = false;
$info->unique = null;
$info->scale = null;
if ($info->meta_type === 'C') {
$info->max_length = $rawcolumn->character_maximum_length;
} else if ($info->meta_type === 'I') {
if ($info->primary_key) {
$info->meta_type = 'R';
$info->unique = true;
}
$info->max_length = $rawcolumn->numeric_precision;
$info->unsigned = (stripos($rawcolumn->column_type, 'unsigned') !== false);
$info->auto_increment= (strpos($rawcolumn->extra, 'auto_increment') !== false);
} else if ($info->meta_type === 'N') {
$info->max_length = $rawcolumn->numeric_precision;
$info->scale = $rawcolumn->numeric_scale;
$info->unsigned = (stripos($rawcolumn->column_type, 'unsigned') !== false);
} else if ($info->meta_type === 'X') {
if ("$rawcolumn->character_maximum_length" === '4294967295') { // watch out for PHP max int limits!
// means maximum moodle size for text column, in other drivers it may also mean unknown size
$info->max_length = -1;
} else {
$info->max_length = $rawcolumn->character_maximum_length;
}
$info->primary_key = false;
} else if ($info->meta_type === 'B') {
$info->max_length = -1;
$info->primary_key = false;
$info->binary = true;
}
return $info;
}
/**
* Normalise column type.
* @param string $mysql_type
* @return string one character
* @throws dml_exception
*/
private function mysqltype2moodletype($mysql_type) {
$type = null;
switch(strtoupper($mysql_type)) {
case 'BIT':
$type = 'L';
break;
case 'TINYINT':
case 'SMALLINT':
case 'MEDIUMINT':
case 'INT':
case 'BIGINT':
$type = 'I';
break;
case 'FLOAT':
case 'DOUBLE':
case 'DECIMAL':
$type = 'N';
break;
case 'CHAR':
case 'ENUM':
case 'SET':
case 'VARCHAR':
$type = 'C';
break;
case 'TINYTEXT':
case 'TEXT':
case 'MEDIUMTEXT':
case 'LONGTEXT':
$type = 'X';
break;
case 'BINARY':
case 'VARBINARY':
case 'BLOB':
case 'TINYBLOB':
case 'MEDIUMBLOB':
case 'LONGBLOB':
$type = 'B';
break;
case 'DATE':
case 'TIME':
case 'DATETIME':
case 'TIMESTAMP':
case 'YEAR':
$type = 'D';
break;
}
if (!$type) {
throw new dml_exception('invalidmysqlnativetype', $mysql_type);
}
return $type;
}
/**
* Normalise values based in RDBMS dependencies (booleans, LOBs...)
*