mirror of
https://github.com/moodle/moodle.git
synced 2025-01-19 06:18:28 +01:00
Merge branch 'wip-MDL-29332-master-3' of git://github.com/marinaglancy/moodle
This commit is contained in:
commit
cecba1d92e
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="lib/db" VERSION="20160404" COMMENT="XMLDB file for core Moodle tables"
|
||||
<XMLDB PATH="lib/db" VERSION="20160804" COMMENT="XMLDB file for core Moodle tables"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
@ -1353,9 +1353,6 @@
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
<KEY NAME="attemptstepid" TYPE="foreign" FIELDS="attemptstepid" REFTABLE="question_attempt_steps" REFFIELDS="id"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="attemptstepid-name" UNIQUE="true" FIELDS="attemptstepid, name"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="question_statistics" COMMENT="Statistics for individual questions used in an activity.">
|
||||
<FIELDS>
|
||||
|
@ -2223,5 +2223,20 @@ function xmldb_main_upgrade($oldversion) {
|
||||
upgrade_main_savepoint(true, 2016091900.00);
|
||||
}
|
||||
|
||||
if ($oldversion < 2016091900.02) {
|
||||
|
||||
// Define index attemptstepid-name (unique) to be dropped from question_attempt_step_data.
|
||||
$table = new xmldb_table('question_attempt_step_data');
|
||||
$index = new xmldb_index('attemptstepid-name', XMLDB_INDEX_UNIQUE, array('attemptstepid', 'name'));
|
||||
|
||||
// Conditionally launch drop index attemptstepid-name.
|
||||
if ($dbman->index_exists($table, $index)) {
|
||||
$dbman->drop_index($table, $index);
|
||||
}
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2016091900.02);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -2050,6 +2050,33 @@ abstract class moodle_database {
|
||||
return $this->sql_order_by_text($fieldname, $numchars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an equal (=) or not equal (<>) part of a query.
|
||||
*
|
||||
* Note the use of this method may lead to slower queries (full scans) so
|
||||
* use it only when needed and against already reduced data sets.
|
||||
*
|
||||
* @since Moodle 3.2
|
||||
*
|
||||
* @param string $fieldname Usually the name of the table column.
|
||||
* @param string $param Usually the bound query parameter (?, :named).
|
||||
* @param bool $casesensitive Use case sensitive search when set to true (default).
|
||||
* @param bool $accentsensitive Use accent sensitive search when set to true (default). (not all databases support accent insensitive)
|
||||
* @param bool $notequal True means not equal (<>)
|
||||
* @return string The SQL code fragment.
|
||||
*/
|
||||
public function sql_equal($fieldname, $param, $casesensitive = true, $accentsensitive = true, $notequal = false) {
|
||||
// Note that, by default, it's assumed that the correct sql equal operations are
|
||||
// case sensitive. Only databases not observing this behavior must override the method.
|
||||
// Also, accent sensitiveness only will be handled by databases supporting it.
|
||||
$equalop = $notequal ? '<>' : '=';
|
||||
if ($casesensitive) {
|
||||
return "$fieldname $equalop $param";
|
||||
} else {
|
||||
return "LOWER($fieldname) $equalop LOWER($param)";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 'LIKE' part of a query.
|
||||
*
|
||||
|
@ -1221,6 +1221,24 @@ class mssql_native_moodle_database extends moodle_database {
|
||||
return $this->collation;
|
||||
}
|
||||
|
||||
public function sql_equal($fieldname, $param, $casesensitive = true, $accentsensitive = true, $notequal = false) {
|
||||
$equalop = $notequal ? '<>' : '=';
|
||||
$collation = $this->get_collation();
|
||||
|
||||
if ($casesensitive) {
|
||||
$collation = str_replace('_CI', '_CS', $collation);
|
||||
} else {
|
||||
$collation = str_replace('_CS', '_CI', $collation);
|
||||
}
|
||||
if ($accentsensitive) {
|
||||
$collation = str_replace('_AI', '_AS', $collation);
|
||||
} else {
|
||||
$collation = str_replace('_AS', '_AI', $collation);
|
||||
}
|
||||
|
||||
return "$fieldname COLLATE $collation $equalop $param";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 'LIKE' part of a query.
|
||||
*
|
||||
|
@ -1511,6 +1511,24 @@ class mysqli_native_moodle_database extends moodle_database {
|
||||
return ' CAST(' . $fieldname . ' AS DECIMAL(65,7)) ';
|
||||
}
|
||||
|
||||
public function sql_equal($fieldname, $param, $casesensitive = true, $accentsensitive = true, $notequal = false) {
|
||||
$equalop = $notequal ? '<>' : '=';
|
||||
if ($casesensitive) {
|
||||
// Current MySQL versions do not support case sensitive and accent insensitive.
|
||||
return "$fieldname COLLATE utf8_bin $equalop $param";
|
||||
} else if ($accentsensitive) {
|
||||
// Case insensitive and accent sensitive, we can force a binary comparison once all texts are using the same case.
|
||||
return "LOWER($fieldname) COLLATE utf8_bin $equalop LOWER($param)";
|
||||
} else {
|
||||
// Case insensitive and accent insensitive. All collations are that way, but utf8_bin.
|
||||
$collation = '';
|
||||
if ($this->get_dbcollation() == 'utf8_bin') {
|
||||
$collation = 'COLLATE utf8_unicode_ci';
|
||||
}
|
||||
return "$fieldname $collation $equalop $param";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 'LIKE' part of a query.
|
||||
*
|
||||
|
@ -1288,6 +1288,24 @@ class sqlsrv_native_moodle_database extends moodle_database {
|
||||
return $this->collation;
|
||||
}
|
||||
|
||||
public function sql_equal($fieldname, $param, $casesensitive = true, $accentsensitive = true, $notequal = false) {
|
||||
$equalop = $notequal ? '<>' : '=';
|
||||
$collation = $this->get_collation();
|
||||
|
||||
if ($casesensitive) {
|
||||
$collation = str_replace('_CI', '_CS', $collation);
|
||||
} else {
|
||||
$collation = str_replace('_CS', '_CI', $collation);
|
||||
}
|
||||
if ($accentsensitive) {
|
||||
$collation = str_replace('_AI', '_AS', $collation);
|
||||
} else {
|
||||
$collation = str_replace('_AS', '_AI', $collation);
|
||||
}
|
||||
|
||||
return "$fieldname COLLATE $collation $equalop $param";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 'LIKE' part of a query.
|
||||
*
|
||||
|
@ -3829,7 +3829,7 @@ class core_dml_testcase extends database_driver_testcase {
|
||||
}
|
||||
}
|
||||
|
||||
public function test_sql_binary_equal() {
|
||||
public function test_sql_equal() {
|
||||
$DB = $this->tdb;
|
||||
$dbman = $DB->get_manager();
|
||||
|
||||
@ -3838,20 +3838,51 @@ class core_dml_testcase extends database_driver_testcase {
|
||||
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
$table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
|
||||
$table->add_field('name2', XMLDB_TYPE_CHAR, '255', null, null, null, null);
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
$dbman->create_table($table);
|
||||
|
||||
$DB->insert_record($tablename, array('name'=>'aaa'));
|
||||
$DB->insert_record($tablename, array('name'=>'aáa'));
|
||||
$DB->insert_record($tablename, array('name'=>'aäa'));
|
||||
$DB->insert_record($tablename, array('name'=>'bbb'));
|
||||
$DB->insert_record($tablename, array('name'=>'BBB'));
|
||||
$DB->insert_record($tablename, array('name' => 'one', 'name2' => 'one'));
|
||||
$DB->insert_record($tablename, array('name' => 'ONE', 'name2' => 'ONE'));
|
||||
$DB->insert_record($tablename, array('name' => 'two', 'name2' => 'TWO'));
|
||||
$DB->insert_record($tablename, array('name' => 'öne', 'name2' => 'one'));
|
||||
$DB->insert_record($tablename, array('name' => 'öne', 'name2' => 'ÖNE'));
|
||||
|
||||
$records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE name = ?", array('bbb'));
|
||||
$this->assertEquals(1, count($records), 'SQL operator "=" is expected to be case sensitive');
|
||||
// Case sensitive and accent sensitive (equal and not equal).
|
||||
$sql = "SELECT * FROM {{$tablename}} WHERE " . $DB->sql_equal('name', '?', true, true, false);
|
||||
$records = $DB->get_records_sql($sql, array('one'));
|
||||
$this->assertCount(1, $records);
|
||||
$sql = "SELECT * FROM {{$tablename}} WHERE " . $DB->sql_equal('name', ':name', true, true, true);
|
||||
$records = $DB->get_records_sql($sql, array('name' => 'one'));
|
||||
$this->assertCount(4, $records);
|
||||
// And with column comparison instead of params.
|
||||
$sql = "SELECT * FROM {{$tablename}} WHERE " . $DB->sql_equal('name', 'name2', true, true, false);
|
||||
$records = $DB->get_records_sql($sql);
|
||||
$this->assertCount(2, $records);
|
||||
|
||||
$records = $DB->get_records_sql("SELECT * FROM {{$tablename}} WHERE name = ?", array('aaa'));
|
||||
$this->assertEquals(1, count($records), 'SQL operator "=" is expected to be accent sensitive');
|
||||
// Case insensitive and accent sensitive (equal and not equal).
|
||||
$sql = "SELECT * FROM {{$tablename}} WHERE " . $DB->sql_equal('name', '?', false, true, false);
|
||||
$records = $DB->get_records_sql($sql, array('one'));
|
||||
$this->assertCount(2, $records);
|
||||
$sql = "SELECT * FROM {{$tablename}} WHERE " . $DB->sql_equal('name', ':name', false, true, true);
|
||||
$records = $DB->get_records_sql($sql, array('name' => 'one'));
|
||||
$this->assertCount(3, $records);
|
||||
// And with column comparison instead of params.
|
||||
$sql = "SELECT * FROM {{$tablename}} WHERE " . $DB->sql_equal('name', 'name2', false, true, false);
|
||||
$records = $DB->get_records_sql($sql);
|
||||
$this->assertCount(4, $records);
|
||||
|
||||
// TODO: Accent insensitive is not cross-db, only some drivers support it, so just verify the queries work.
|
||||
$sql = "SELECT * FROM {{$tablename}} WHERE " . $DB->sql_equal('name', '?', true, false);
|
||||
$records = $DB->get_records_sql($sql, array('one'));
|
||||
$this->assertGreaterThanOrEqual(1, count($records)); // At very least, there is 1 record with CS/AI "one".
|
||||
$sql = "SELECT * FROM {{$tablename}} WHERE " . $DB->sql_equal('name', '?', false, false);
|
||||
$records = $DB->get_records_sql($sql, array('one'));
|
||||
$this->assertGreaterThanOrEqual(2, count($records)); // At very least, there are 2 records with CI/AI "one".
|
||||
// And with column comparison instead of params.
|
||||
$sql = "SELECT * FROM {{$tablename}} WHERE " . $DB->sql_equal('name', 'name2', false, false);
|
||||
$records = $DB->get_records_sql($sql);
|
||||
$this->assertGreaterThanOrEqual(4, count($records)); // At very least, there are 4 records with CI/AI names matching.
|
||||
}
|
||||
|
||||
public function test_sql_like() {
|
||||
|
@ -78,6 +78,8 @@ information provided here is intended especially for developers.
|
||||
- $CFG->wwwroot: http://example.com/moodle
|
||||
- $CFG->alternateloginurl : /my/super/login.php
|
||||
- Login url will be: http://example.com/moodle/my/super/login.php (moodle root based)
|
||||
* Database (DML) layer:
|
||||
- new sql_equal() method available for places where case sensitive/insensitive varchar comparisons are required.
|
||||
|
||||
=== 3.1 ===
|
||||
|
||||
|
@ -287,10 +287,19 @@ class question_engine_data_mapper {
|
||||
*/
|
||||
public function update_question_attempt_metadata(question_attempt $qa, array $names) {
|
||||
global $DB;
|
||||
list($condition, $params) = $DB->get_in_or_equal($names);
|
||||
$params[] = $qa->get_step(0)->get_id();
|
||||
if (!$names) {
|
||||
return [];
|
||||
}
|
||||
// Use case-sensitive function sql_equal() and not get_in_or_equal().
|
||||
// Some databases may use case-insensitive collation, we don't want to delete 'X' instead of 'x'.
|
||||
$sqls = [];
|
||||
$params = [$qa->get_step(0)->get_id()];
|
||||
foreach ($names as $name) {
|
||||
$sqls[] = $DB->sql_equal('name', '?');
|
||||
$params[] = $name;
|
||||
}
|
||||
$DB->delete_records_select('question_attempt_step_data',
|
||||
'name ' . $condition . ' AND attemptstepid = ?', $params);
|
||||
'attemptstepid = ? AND (' . join(' OR ', $sqls) . ')', $params);
|
||||
return $this->insert_question_attempt_metadata($qa, $names);
|
||||
}
|
||||
|
||||
|
@ -281,7 +281,7 @@ class qtype_calculated extends question_type {
|
||||
if ($sharedatasetdefs = $DB->get_records_select(
|
||||
'question_dataset_definitions',
|
||||
"type = '1'
|
||||
AND name = ?
|
||||
AND " . $DB->sql_equal('name', '?') . "
|
||||
AND category = ?
|
||||
ORDER BY id DESC ", array($dataset->name, $question->category)
|
||||
)) { // So there is at least one.
|
||||
@ -1400,7 +1400,7 @@ class qtype_calculated extends question_type {
|
||||
// can manage to automatically take care of
|
||||
// some possible realtime concurrence.
|
||||
if ($olderdatasetdefs = $DB->get_records_select('question_dataset_definitions',
|
||||
"type = ? AND name = ? AND category = ? AND id < ?
|
||||
"type = ? AND " . $DB->sql_equal('name', '?') . " AND category = ? AND id < ?
|
||||
ORDER BY id DESC",
|
||||
array($datasetdef->type, $datasetdef->name,
|
||||
$datasetdef->category, $datasetdef->id))) {
|
||||
@ -1484,7 +1484,7 @@ class qtype_calculated extends question_type {
|
||||
// Construct question local options.
|
||||
$sql = "SELECT a.*
|
||||
FROM {question_dataset_definitions} a, {question_datasets} b
|
||||
WHERE a.id = b.datasetdefinition AND a.type = '1' AND b.question = ? AND a.name = ?";
|
||||
WHERE a.id = b.datasetdefinition AND a.type = '1' AND b.question = ? AND " . $DB->sql_equal('a.name', '?');
|
||||
$currentdatasetdef = $DB->get_record_sql($sql, array($form->id, $name));
|
||||
if (!$currentdatasetdef) {
|
||||
$currentdatasetdef = new stdClass();
|
||||
@ -1506,7 +1506,7 @@ class qtype_calculated extends question_type {
|
||||
WHERE a.id = b.datasetdefinition
|
||||
AND a.type = '1'
|
||||
AND a.category = ?
|
||||
AND a.name = ?", array($form->category, $name));
|
||||
AND " . $DB->sql_equal('a.name', '?'), array($form->category, $name));
|
||||
$type = 1;
|
||||
$key = "{$type}-{$form->category}-{$name}";
|
||||
if (!empty($categorydatasetdefs)) {
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2016091900.01; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2016091900.02; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user