public static function fetch_all_helper($table, $classname, $params) {
        global $DB; // Need to introspect DB here.

        $instance = new $classname();

        $classvars = (array)$instance;
        $params    = (array)$params;

        $wheresql = array();
        $newparams = array();

        $columns = $DB->get_columns($table); // Cached, no worries.

        foreach ($params as $var=>$value) {
            if (!in_array($var, $instance->required_fields) and !array_key_exists($var, $instance->optional_fields)) {
                continue;
            }
            if (!array_key_exists($var, $columns)) {
                continue;
            }
            if (is_null($value)) {
                $wheresql[] = " $var IS NULL ";
            } else {
                if ($columns[$var]->meta_type === 'X') {
                    // We have a text/clob column, use the cross-db method for its comparison.
                    $wheresql[] = ' ' . $DB->sql_compare_text($var) . ' = ' . $DB->sql_compare_text('?') . ' ';
                } else {
                    // Other columns (varchar, integers...).
                    $wheresql[] = " $var = ? ";
                }
                $newparams[] = $value;
            }
        }

        if (empty($wheresql)) {
            $wheresql = '';
        } else {
            $wheresql = implode("AND", $wheresql);
        }

        global $DB;
        $rs = $DB->get_recordset_select($table, $wheresql, $newparams);
        //returning false rather than empty array if nothing found
        if (!$rs->valid()) {
            $rs->close();
            return false;
        }

        $result = array();
        foreach($rs as $data) {
            $instance = new $classname();
            grade_object::set_properties($instance, $data);
            $result[$instance->id] = $instance;
        }
        $rs->close();
        return $result;
    }