Quiz answers disappear

Quiz answers disappear

by Chris David -
Number of replies: 10
I've had students take a quiz (multiple choice and short answer), click on submit/finish, and it seems that we're successful. As the teacher, I go in and view the students' answers and everything seems to work. But, then I'll go back into the quiz to view the students' again, and they have disappeared. This seems to be true for multiple choice and short answer questions. Ideas on how to fix this? Since I can see the answers the first time, I think I'm setting up the quiz correctly.
Average of ratings: -
In reply to Chris David

Re: Quiz answers disappear

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
If you saw the answers once, and then not again, the most likely explanation is that you, or someone else, deleted that student's attempt.

You don't say which verion of Moodle you are using?
In reply to Tim Hunt

Re: Quiz answers disappear

by Olli Savolainen -
Perhaps the above doesn't apply to my issue, nonetheless the subject line applies...

I've just been digging for a bug for over a week. Found out that in moodle 1.6 there seems to be a problem in penalty calculation, related to locale (using fi_FI something here, though mdl_config.locale has been empty). This appeared in shortquestion but I guess it's in multiple choice and cloze questions too. attempt.php calls question_process_responses, which calls questiontype.php of the question type:

echo $state->penalty." / ".$question->penalty." / ".$question->maxgrade."<br />";
$state->penalty = $question->penalty * $question->maxgrade;
echo $state->penalty." / ".$question->penalty." / ".$question->maxgrade;

prints out:

0 / 0.1 / 1
0,1 / 0.1 / 1

Why is the comma ending up in $state->penalty? It seems, due to locale settings. This then goes back to attempt.php which sends it as save_question_session($questions[$i], $states[$i]); and boom, the SQL query for saving the reply ends up like this:

INSERT INTO mdlvv_question_states( ATTEMPT, QUESTION, ORIGINALQUESTION, SEQ_NUMBER, ANSWER, TIMESTAMP, EVENT, GRADE, RAW_GRADE, PENALTY )
VALUES ( 413, 61, 0, 1, 'answer', 1183018653, 6, 0, 0, 0, 1 )

MySQL said:
#1136 - Column count doesn't match value count at row 1

What's worse, moodle doesn't give any error notices about this. Just returns false.
In reply to Olli Savolainen

Re: Quiz answers disappear

by Olli Savolainen -
What I'm unsure about is: should the locale-specific decimal notation always be converted to the US form, or is it okay to just quote the number in the SQL query, whatever form it is in?
In reply to Olli Savolainen

Re: Quiz answers disappear

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
That is really weird. I have never seen anything like that before, and I am pretty ignorant about PHP locales. So I don't know, but it would be really great if someone could explain.
In reply to Tim Hunt

Re: Quiz answers disappear

by Olli Savolainen -
Yeah, I'm rather puzzled, too. Even if that value was quoted I'm not sure if it would help, since the SQL field is in decimal form anyway and MySQL might not accept/understand if the decimal separator is in different form.

I found this entry on the topic. Actually, the current locale can be fetched:
string setlocale ( int $category, string $locale [, string $...] )
If locale is "0", the locale setting is not affected, only the current setting is returned.

Seems that there have been further related issues, too. It was implied here that it depends on the user's browser locale which one PHP uses, but this seems too strange. Perhaps we should use number_format()? However, the documentation doesn't mention this decimal separator changing happening at all, instead: The string will evaluate as a float if it contains any of the characters '.', 'e', or 'E'. Otherwise, it will evaluate as an integer.

I'm further puzzled since I have two installations on the same server and only the other seems affected by this, though their environment I suppose is the same. I will further investigate this though. This might have to do with it?:

Warning

The locale information is maintained per process, not per thread. If you are running PHP on a multithreaded server api like IIS or Apache on Windows you may experience sudden changes of locale settings while a script is running although the script itself never called setlocale() itself. This happens due to other scripts running in different threads of the same process at the same time changing the processwide locale using setlocale().

Should I file a bug report or how to keep this in the attention of someone who knows better? Thanks.
In reply to Olli Savolainen

Re: Quiz answers disappear

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
I guess file a report in the tracker so we don't forget about it, then start discussing this in the General Developer forum. Then post a short message in the languages forum, asking anyone who can help to read the GDF thread. Cross-posting is generally bad, but short 'please look at this thread' posts are OK, in some situations, like this one.
In reply to Tim Hunt

Re: Quiz answers disappear

by Olli Savolainen -
Actually, it seems there is more to our issue than this. Despite fixing the locales, short answers, multiple choices and cloze questions still lose their answers right after pressing the "save all and finish" button. As soon as I can see what's really wrong, I'll hold posting to any further forums.
In reply to Tim Hunt

Re: Quiz answers disappear

by Olli Savolainen -
Oh, I'm a little embarassed now. The locale was set in some code, which I include()d from another open-source software for our customized exam service's purposes. So the bug was not rooted in Moodle at all.

Still, it would be good to make sure Moodle code isn't this easy to break just by altering the locale - especially as such as these bugs related to locales are extremely difficult to trace, and understanding what's going on requires rather deep knowledge of the intricacies of PHP, too.

Perhaps quote float values when inserting them to the database? Anyway, sorry for wasting your time.
In reply to Tim Hunt

Re: Quiz answers disappear

by Olli Savolainen -
Made a small test. What makes me wonder here is that at least the decimal separator doesn't change in the middle of the operation, as it did in the above moodle source.

So here we go:

echo '<br />setlocale(LC_NUMERIC, "C"): '.setlocale(LC_NUMERIC, "C");
echo '<br />setlocale(LC_ALL, 0): '.setlocale(LC_ALL, 0);
$penalty = 0;
$qpenalty =0.1;
$qmaxgrade= 1;
echo "<br>".$penalty." / ".$qpenalty." / ".$qmaxgrade."<br />";
$penalty = $qpenalty * $qmaxgrade;
echo $penalty." / ".$qpenalty." / ".$qmaxgrade."<br />";
echo '<br />setlocale(LC_NUMERIC, "fi_FI.UTF-8"): '.setlocale(LC_NUMERIC, "fi_FI.UTF-8");
echo "<br />setlocale(LC_ALL, 0): ".setlocale(LC_ALL, 0);
$penalty = 0;
$qpenalty =0.1;
$qmaxgrade= 1;
echo "<br>".$penalty." / ".$qpenalty." / ".$qmaxgrade."<br />";
$penalty = $qpenalty * $qmaxgrade;
echo $penalty." / ".$qpenalty." / ".$qmaxgrade."<br />";
echo "<br />setlocale(LC_ALL, 0): ".setlocale(LC_ALL, 0);


prints out:
setlocale(LC_NUMERIC, "C"): C
setlocale(LC_ALL, 0): LC_CTYPE=fi_FI.UTF-8;LC_NUMERIC=C;LC_TIME=fi_FI.UTF-8;
LC_COLLATE=fi_FI.UTF-8;LC_MONETARY=C;LC_MESSAGES=C;
LC_PAPER=fi_FI.UTF-8;LC_NAME=fi_FI.UTF-8;LC_ADDRESS=fi_FI.UTF-8;
LC_TELEPHONE=fi_FI.UTF-8;LC_MEASUREMENT=fi_FI.UTF-8;
LC_IDENTIFICATION=fi_FI.UTF-8
0 / 0.1 / 1
0.1 / 0.1 / 1

setlocale(LC_NUMERIC, "fi_FI.UTF-8"): fi_FI.UTF-8
setlocale(LC_ALL, 0): LC_CTYPE=fi_FI.UTF-8;LC_NUMERIC=fi_FI.UTF-8;LC_TIME=fi_FI.UTF-8;
LC_COLLATE=fi_FI.UTF-8;LC_MONETARY=C;LC_MESSAGES=C;
LC_PAPER=fi_FI.UTF-8;LC_NAME=fi_FI.UTF-8;LC_ADDRESS=fi_FI.UTF-8;
LC_TELEPHONE=fi_FI.UTF-8;LC_MEASUREMENT=fi_FI.UTF-8;
LC_IDENTIFICATION=fi_FI.UTF-8
0 / 0,1 / 1
0,1 / 0,1 / 1

setlocale(LC_ALL, 0): LC_CTYPE=fi_FI.UTF-8;LC_NUMERIC=fi_FI.UTF-8;LC_TIME=fi_FI.UTF-8;
LC_COLLATE=fi_FI.UTF-8;LC_MONETARY=C;LC_MESSAGES=C;
LC_PAPER=fi_FI.UTF-8;LC_NAME=fi_FI.UTF-8;LC_ADDRESS=fi_FI.UTF-8;
LC_TELEPHONE=fi_FI.UTF-8;LC_MEASUREMENT=fi_FI.UTF-8;
LC_IDENTIFICATION=fi_FI.UTF-8
In reply to Olli Savolainen

Re: Quiz answers disappear

by Olli Savolainen -
The mistake that my external code was related to a strange (in my opinion) thing that PHP does. If you set a locale for LC_ALL, the locale string becomes just what you set, instead of replacing each of the individual locale strings inside the entire locale string. It isn't obvious what would be the right behavior, though. Anyway, the below is just for information in case someone else stumbles upon this issue, too.

If we first have:
LC_CTYPE=fi_FI.UTF-8;LC_NUMERIC=C;LC_TIME=fi_FI.UTF-8;
LC_COLLATE=fi_FI.UTF-8;LC_MONETARY=C;LC_MESSAGES=C;
LC_PAPER=fi_FI.UTF-8;LC_NAME=fi_FI.UTF-8;LC_ADDRESS=fi_FI.UTF-8;
LC_TELEPHONE=fi_FI.UTF-8;LC_MEASUREMENT=fi_FI.UTF-8;
LC_IDENTIFICATION=fi_FI.UTF-8

then we do:
setlocale(LC_NUMERIC, "fi_FI.UTF-8") returns: "fi_FI.UTF-8"

we will have:
LC_CTYPE=fi_FI.UTF-8;LC_NUMERIC=fi_FI.UTF-8;LC_TIME=fi_FI.UTF-8;
LC_COLLATE=fi_FI.UTF-8;LC_MONETARY=C;LC_MESSAGES=C;
LC_PAPER=fi_FI.UTF-8;LC_NAME=fi_FI.UTF-8;LC_ADDRESS=fi_FI.UTF-8;
LC_TELEPHONE=fi_FI.UTF-8;LC_MEASUREMENT=fi_FI.UTF-8;
LC_IDENTIFICATION=fi_FI.UTF-8 (as returned by setlocale(LC_ALL, 0))

But if we do:
setlocale(LC_ALL, "fi_FI.UTF-8"), it again returns: "fi_FI.UTF-8"

But the value of the entire locale will be just:
fi_FI.UTF-8 (as returned by setlocale(LC_ALL, 0))

which doesn't seem to make sense, methinks it should be
LC_CTYPE=fi_FI.UTF-8;LC_NUMERIC=fi_FI.UTF-8;LC_TIME=fi_FI.UTF-8;
LC_COLLATE=fi_FI.UTF-8;LC_MONETARY=fi_FI.UTF-8;LC_MESSAGES=fi_FI.UTF-8;
LC_PAPER=fi_FI.UTF-8;LC_NAME=fi_FI.UTF-8;LC_ADDRESS=fi_FI.UTF-8;
LC_TELEPHONE=fi_FI.UTF-8;LC_MEASUREMENT=fi_FI.UTF-8;
LC_IDENTIFICATION=fi_FI.UTF-8

But of course this is a PHP issue and you might at times need to set the string to something custom, I guess, so it might need to be this way.