Index: lib/dml/moodle_database.php =================================================================== RCS file: /cvsroot/moodle/moodle/lib/dml/moodle_database.php,v retrieving revision 1.75 diff -u -r1.75 moodle_database.php --- lib/dml/moodle_database.php 5 Dec 2008 00:10:27 -0000 1.75 +++ lib/dml/moodle_database.php 10 Dec 2008 10:00:25 -0000 @@ -420,6 +420,31 @@ } /** + * Get the SQL condition for something containing, or not containing, a + * certain word. The generated SQL is only approximately right on DBs taht + * do not support regexps. + * + * @param string $searchterm the word we want to search for. + * @param bool $positivematch if true, return the operator for things matching the regexp, otherwise + * return the operator for things not matching. Defaults to true. + * @param $placeholder the placeholder we want to use in this test. + * @return array with two elemnts, the SQL fragment and the parameter. + * + * TODO may not work for non latin languages, but that is really up to DBs supporting [[:<:]] and [[:>:]] properly. + */ + public function string_contains_word($searchterm, $positivematch = true, $placeholder = '?') { + if ($this->sql_regex_supported()) { + $param = '[[:<:]]' . preg_quote($searchterm, '|') . '[[:>:]]'; + $test = $this->sql_regex(true) . ' ' . $placeholder; + } else { + // Do the best we can. + $param = '%' . $searchterm . '%'; // Should probably do something about % in $searchterm. + $test = $this->sql_ilike(true) . ' ' . $placeholder; + } + return array($test, $param); + } + + /** * Converts short table name {tablename} to real table name * @param string sql * @return string sql @@ -1493,10 +1518,16 @@ * the caseinsensitive search using regexp_like() or NLS_COMP=LINGUISTIC :-( * See http://docs.moodle.org/en/XMLDB_Problems#Case-insensitive_searches * - * @return string - */ - public function sql_ilike() { - return 'LIKE'; + * @param bool $positivematch if true, return the operator for things matching the regexp, otherwise + * return the operator for things not matching. Defaults to true. + * @return string the operator. + */ + public function sql_ilike($positivematch = true) { + if ($positivematch) { + return 'LIKE'; + } else { + return 'NOT LIKE'; + } } /** @@ -1659,8 +1690,9 @@ /** * Return regex positive or negative match sql - * @param bool $positivematch - * @return string or empty if not supported + * @param bool $positivematch if true, return the operator for things matching the regexp, otherwise + * return the operator for things not matching. Defaults to true. + * @return string the operator, or empty if not supported */ public function sql_regex($positivematch=true) { return ''; Index: lib/datalib.php =================================================================== RCS file: /cvsroot/moodle/moodle/lib/datalib.php,v retrieving revision 1.493 diff -u -r1.493 datalib.php --- lib/datalib.php 4 Dec 2008 08:53:11 -0000 1.493 +++ lib/datalib.php 10 Dec 2008 10:00:24 -0000 @@ -1003,50 +1003,30 @@ function get_courses_search($searchterms, $sort='fullname ASC', $page=0, $recordsperpage=50, &$totalcount) { global $CFG, $DB; - if ($DB->sql_regex_supported()) { - $REGEXP = $DB->sql_regex(true); - $NOTREGEXP = $DB->sql_regex(false); - } - $LIKE = $DB->sql_ilike(); // case-insensitive - $searchcond = array(); - $params = array(); - $i = 0; + $params = array(); + $paramindex = 0; $concat = $DB->sql_concat('c.summary', "' '", 'c.fullname'); foreach ($searchterms as $searchterm) { - $i++; - - $NOT = ''; /// Initially we aren't going to perform NOT LIKE searches, only MSSQL and Oracle - /// will use it to simulate the "-" operator with LIKE clause - - /// Under Oracle and MSSQL, trim the + and - operators and perform - /// simpler LIKE (or NOT LIKE) queries - if (!$DB->sql_regex_supported()) { - if (substr($searchterm, 0, 1) == '-') { - $NOT = ' NOT '; - } - $searchterm = trim($searchterm, '+-'); - } - - // TODO: +- may not work for non latin languages + $paramindex++; if (substr($searchterm,0,1) == '+') { $searchterm = trim($searchterm, '+-'); - $searchterm = preg_quote($searchterm, '|'); - $searchcond[] = "$concat $REGEXP :ss$i"; - $params['ss'.$i] = "(^|[^a-zA-Z0-9])$searchterm([^a-zA-Z0-9]|$)"; + list($test, $param) = $DB->string_contains_word($searchterm, true, 'ss'.$paramindex); + $searchcond[] = $concat . ' ' . $test; + $params['ss'.$paramindex] = $param; } else if (substr($searchterm,0,1) == "-") { $searchterm = trim($searchterm, '+-'); - $searchterm = preg_quote($searchterm, '|'); - $searchcond[] = "$concat $NOTREGEXP :ss$i"; - $params['ss'.$i] = "(^|[^a-zA-Z0-9])$searchterm([^a-zA-Z0-9]|$)"; + list($test, $param) = $DB->string_contains_word($searchterm, false, 'ss'.$paramindex); + $searchcond[] = $concat . ' ' . $test; + $params['ss'.$paramindex] = $param; } else { - $searchcond[] = "$concat $NOT $LIKE :ss$i"; - $params['ss'.$i] = "%$searchterm%"; + $searchcond[] = $concat . ' ' . $DB->sql_ilike() . ':ss$paramindex'; + $params['ss'.$paramindex] = "%$searchterm%"; } } @@ -1055,7 +1035,7 @@ return array(); } - $searchcond = implode(" AND ", $searchcond); + $searchcond = implode(' AND ', $searchcond); $sql = "SELECT c.*, ctx.id AS ctxid, ctx.path AS ctxpath, @@ -1066,31 +1046,29 @@ WHERE $searchcond AND c.id <> ".SITEID." ORDER BY $sort"; $courses = array(); - $c = 0; // counts how many visible courses we've seen + $resultcount = 0; // counts how many visible courses we've seen if ($rs = $DB->get_recordset_sql($sql, $params)) { - // Tiki pagination + // Manual pagination, becuase it is too hard to do in SQL. $limitfrom = $page * $recordsperpage; $limitto = $limitfrom + $recordsperpage; foreach($rs as $course) { $course = make_context_subobj($course); if ($course->visible || has_capability('moodle/course:viewhiddencourses', $course->context)) { - // Don't exit this loop till the end - // we need to count all the visible courses - // to update $totalcount - if ($c >= $limitfrom && $c < $limitto) { + // Don't exit this loop until the end. We need to count all the + // visible courses to update $totalcount + if ($resultcount >= $limitfrom && $resultcount < $limitto) { $courses[$course->id] = $course; } - $c++; + $resultcount += 1; } } $rs->close(); } - // our caller expects 2 bits of data - our return - // array, and an updated $totalcount - $totalcount = $c; + // The caller expects 2 bits of data: the returned array and an updated $totalcount. + $totalcount = $resultcount; return $courses; }