[LON-CAPA-cvs] cvs: loncom /interface loncoursedata.pm

matthew lon-capa-cvs@mail.lon-capa.org
Fri, 26 Sep 2003 18:31:31 -0000


This is a MIME encoded message

--matthew1064601091
Content-Type: text/plain

matthew		Fri Sep 26 14:31:31 2003 EDT

  Modified files:              
    /loncom/interface	loncoursedata.pm 
  Log:
  Implement storing of student performance data in the MySQL cache database.
  Added 3 tables: $fulldump_part_table, $fulldump_response_table, and
  $fulldump_timestamp_table.  Added &update_full_student_data to do a 
  lonnet::dump, load the data into the new tables, and then update the old
  tables used for Chart, Spreadsheet, and the current implementation of
  Statistics.  Reworked some existing code to avoid duplication.
  
  
--matthew1064601091
Content-Type: text/plain
Content-Disposition: attachment; filename="matthew-20030926143131.txt"

Index: loncom/interface/loncoursedata.pm
diff -u loncom/interface/loncoursedata.pm:1.88 loncom/interface/loncoursedata.pm:1.89
--- loncom/interface/loncoursedata.pm:1.88	Wed Sep 24 14:01:01 2003
+++ loncom/interface/loncoursedata.pm	Fri Sep 26 14:31:31 2003
@@ -1,6 +1,6 @@
 # The LearningOnline Network with CAPA
 #
-# $Id: loncoursedata.pm,v 1.88 2003/09/24 18:01:01 matthew Exp $
+# $Id: loncoursedata.pm,v 1.89 2003/09/26 18:31:31 matthew Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -371,6 +371,13 @@
 
 =over 4
 
+=item Tables used to store meta information
+
+The following tables hold data required to keep track of the current status
+of a students data in the tables or to look up the students data in the tables.
+
+=over 4
+
 =item $symb_table
 
 The symb_table has two columns.  The first is a 'symb_id' and the second
@@ -398,10 +405,20 @@
 
 =item $studentdata_table
 
-The studentdata_table has four columns.  The first is 'student_id', the unique
-id of the student.  The second is the time the students data was last updated.
-The third is the students section.  The fourth is the students current
-classification.  This table has its PRIMARY KEY on 'student_id'.
+The studentdata_table has four columns:  'student_id' (the unique id of 
+the student), 'updatetime' (the time the students data was last updated),
+'fullupdatetime' (the time the students full data was last updated),
+'section', and 'classification'( the students current classification).
+This table has its PRIMARY KEY on 'student_id'.
+
+=back 
+
+=item Tables used to store current status data
+
+The following tables store data only about the students current status on 
+a problem, meaning only the data related to the last attempt on a problem.
+
+=over 4
 
 =item $performance_table
 
@@ -425,6 +442,45 @@
 
 =back
 
+=item Tables used for storing historic data
+
+The following tables are used to store almost all of the transactions a student
+has made on a homework problem.  See loncapa/docs/homework/datastorage for 
+specific information about each of the parameters stored.  
+
+=over 4
+
+=item $fulldump_response_table
+
+The response table holds data (documented in loncapa/docs/homework/datastorage)
+associated with a particular response id which is stored when a student 
+attempts a problem.  The following are the columns of the table, in order:
+'symb_id','part_id','response_id','student_id','transaction','tries',
+'awarddetail', 'awarded','response_specific' (data particular to the response
+type), 'response_specific_value', and 'submission (the text of the students
+submission).  The primary key is based on the first five columns listed above.
+
+=item $fulldump_part_table
+
+The part table holds data (documented in loncapa/docs/homework/datastorage)
+associated with a particular part id which is stored when a student attempts
+a problem.  The following are the columns of the table, in order:
+'symb_id','part_id','student_id','transaction','tries','award','awarded',
+and 'previous'.  The primary key is based on the first five columns listed 
+above.
+
+=item $fulldump_timestamp_table
+
+The timestamp table holds the timestamps of the transactions which are
+stored in $fulldump_response_table and $fulldump_part_table.  This data is
+about both the response and part data.  Columns: 'symb_id','student_id',
+'transaction', and 'timestamp'.  
+The primary key is based on the first 3 columns.
+
+=back
+
+=back
+
 =head3 Important Subroutines
 
 Here is a brief overview of the subroutines which are likely to be of 
@@ -453,7 +509,7 @@
 
 ################################################
 ################################################
-{
+{ # Begin scope of table identifiers
 
 my $current_course ='';
 my $symb_table;
@@ -462,7 +518,11 @@
 my $studentdata_table;
 my $performance_table;
 my $parameters_table;
+my $fulldump_response_table;
+my $fulldump_part_table;
+my $fulldump_timestamp_table;
 
+my @Tables;
 ################################################
 ################################################
 
@@ -486,9 +546,7 @@
     &setup_table_names($courseid);
     #
     # Drop any of the existing tables
-    foreach my $table ($symb_table,$part_table,$student_table,
-                       $studentdata_table,$performance_table,
-                       $parameters_table) {
+    foreach my $table (@Tables) {
         &Apache::lonmysql::drop_table($table);
     }
     #
@@ -548,8 +606,9 @@
                       type => 'MEDIUMINT UNSIGNED',
                       restrictions => 'NOT NULL UNIQUE',},
                     { name => 'updatetime',
-                      type => 'INT UNSIGNED',
-                      restrictions => 'NOT NULL' },
+                      type => 'INT UNSIGNED'},
+                    { name => 'fullupdatetime',
+                      type => 'INT UNSIGNED'},
                     { name => 'section',
                       type => 'VARCHAR(100)'},
                     { name => 'classification',
@@ -591,6 +650,112 @@
                   { columns=>['symb_id'] },],
     };
     #
+    my $fulldump_part_table_def = {
+        id => $fulldump_part_table,
+        permanent => 'no',
+        columns => [
+                    { name => 'symb_id',
+                      type => 'MEDIUMINT UNSIGNED',
+                      restrictions => 'NOT NULL'  },
+                    { name => 'part_id',
+                      type => 'MEDIUMINT UNSIGNED',
+                      restrictions => 'NOT NULL' },
+                    { name => 'student_id',
+                      type => 'MEDIUMINT UNSIGNED',
+                      restrictions => 'NOT NULL'  },
+                    { name => 'transaction',
+                      type => 'MEDIUMINT UNSIGNED',
+                      restrictions => 'NOT NULL' },
+                    { name => 'tries',
+                      type => 'SMALLINT UNSIGNED',
+                      restrictions => 'NOT NULL' },
+                    { name => 'award',
+                      type => 'TINYTEXT' },
+                    { name => 'awarded',
+                      type => 'TINYTEXT' },
+                    { name => 'previous',
+                      type => 'SMALLINT UNSIGNED' },
+#                    { name => 'regrader',
+#                      type => 'TINYTEXT' },
+#                    { name => 'afterduedate',
+#                      type => 'TINYTEXT' },
+                    ],
+        'PRIMARY KEY' => ['symb_id','part_id','student_id','transaction'],
+        'KEY' => [
+                  { columns=>['symb_id'] },
+                  { columns=>['part_id'] },
+                  { columns=>['student_id'] },
+                  ],
+    };
+    #
+    my $fulldump_response_table_def = {
+        id => $fulldump_response_table,
+        permanent => 'no',
+        columns => [
+                    { name => 'symb_id',
+                      type => 'MEDIUMINT UNSIGNED',
+                      restrictions => 'NOT NULL'  },
+                    { name => 'part_id',
+                      type => 'MEDIUMINT UNSIGNED',
+                      restrictions => 'NOT NULL' },
+                    { name => 'response_id',
+                      type => 'MEDIUMINT UNSIGNED',
+                      restrictions => 'NOT NULL'  },
+                    { name => 'student_id',
+                      type => 'MEDIUMINT UNSIGNED',
+                      restrictions => 'NOT NULL'  },
+                    { name => 'transaction',
+                      type => 'MEDIUMINT UNSIGNED',
+                      restrictions => 'NOT NULL' },
+                    { name => 'tries',
+                      type => 'SMALLINT UNSIGNED',
+                      restrictions => 'NOT NULL' },
+                    { name => 'awarddetail',
+                      type => 'TINYTEXT' },
+                    { name => 'awarded',
+                      type => 'TINYTEXT' },
+#                    { name => 'message',
+#                      type => 'CHAR' },
+                    { name => 'response_specific',
+                      type => 'TINYTEXT' },
+                    { name => 'response_specific_value',
+                      type => 'TINYTEXT' },
+                    { name => 'submission',
+                      type => 'TEXT'},
+                    ],
+            'PRIMARY KEY' => ['symb_id','part_id','response_id','student_id',
+                              'transaction'],
+            'KEY' => [
+                      { columns=>['symb_id'] },
+                      { columns=>['part_id','response_id'] },
+                      { columns=>['student_id'] },
+                      ],
+    };
+    my $fulldump_timestamp_table_def = {
+        id => $fulldump_timestamp_table,
+        permanent => 'no',
+        columns => [
+                    { name => 'symb_id',
+                      type => 'MEDIUMINT UNSIGNED',
+                      restrictions => 'NOT NULL'  },
+                    { name => 'student_id',
+                      type => 'MEDIUMINT UNSIGNED',
+                      restrictions => 'NOT NULL'  },
+                    { name => 'transaction',
+                      type => 'MEDIUMINT UNSIGNED',
+                      restrictions => 'NOT NULL' },
+                    { name => 'timestamp',
+                      type => 'INT UNSIGNED'},
+                    ],
+        'PRIMARY KEY' => ['symb_id','student_id','transaction'],
+        'KEY' => [
+                  { columns=>['symb_id'] },
+                  { columns=>['student_id'] },
+                  { columns=>['transaction'] },
+                  ],
+    };
+
+    #
     my $parameters_table_def = {
         id => $parameters_table,
         permanent => 'no',
@@ -652,6 +817,26 @@
                                  &Apache::lonmysql::get_error());
         return 6;
     }
+    #
+    $tableid = &Apache::lonmysql::create_table($fulldump_part_table_def);
+    if (! defined($tableid)) {
+        &Apache::lonnet::logthis("error creating fulldump_part_table: ".
+                                 &Apache::lonmysql::get_error());
+        return 7;
+    }
+    #
+    $tableid = &Apache::lonmysql::create_table($fulldump_response_table_def);
+    if (! defined($tableid)) {
+        &Apache::lonnet::logthis("error creating fulldump_response_table: ".
+                                 &Apache::lonmysql::get_error());
+        return 8;
+    }
+    $tableid = &Apache::lonmysql::create_table($fulldump_timestamp_table_def);
+    if (! defined($tableid)) {
+        &Apache::lonnet::logthis("error creating fulldump_timestamp_table: ".
+                                 &Apache::lonmysql::get_error());
+        return 9;
+    }
     return 0;
 }
 
@@ -673,9 +858,7 @@
     &setup_table_names($courseid);
     #
     my $dbh = &Apache::lonmysql::get_dbh();
-    foreach my $table ($symb_table,$part_table,$student_table,
-                       $studentdata_table,$performance_table,
-                       $parameters_table ){
+    foreach my $table (@Tables) {
         my $command = 'DROP TABLE '.$table.';';
         $dbh->do($command);
         if ($dbh->err) {
@@ -887,6 +1070,210 @@
 
 =pod
 
+=item &update_full_student_data($sname,$sdom,$courseid)
+
+Does a lonnet::dump on a student to populate the courses tables.
+
+Input: $sname, $sdom, $courseid
+
+Output: $returnstatus
+
+$returnstatus is a string describing any errors that occured.  'okay' is the
+default.
+
+This subroutine loads a students data using lonnet::dump and inserts
+it into the MySQL database.  The inserts are done on three tables, 
+$fulldump_response_table, $fulldump_part_table, and $fulldump_timestamp_table.
+The INSERT calls are made directly by this subroutine, not through lonmysql 
+because we do a 'bulk'insert which takes advantage of MySQLs non-SQL 
+compliant INSERT command to insert multiple rows at a time.  
+If anything has gone wrong during this process, $returnstatus is updated with 
+a description of the error.
+
+Once the "fulldump" tables are updated, the tables used for chart and
+spreadsheet (which hold only the current state of the student on their
+homework, not historical data) are updated.  If all updates have occured 
+successfully, the studentdata table is updated to reflect the time of the
+update.
+
+Notice we do not insert the data and immediately query it.  This means it
+is possible for there to be data returned this first time that is not 
+available the second time.  CYA.
+
+=cut
+
+################################################
+################################################
+sub update_full_student_data {
+    my ($sname,$sdom,$courseid) = @_;
+    #
+    # Set up database names
+    &setup_table_names($courseid);
+    #
+    my $student_id = &get_student_id($sname,$sdom);
+    my $student = $sname.':'.$sdom;
+    #
+    my $returnstatus = 'okay';
+    #
+    # Download students data
+    my $time_of_retrieval = time;
+    my @tmp = &Apache::lonnet::dump($courseid,$sdom,$sname);
+    if (@tmp && $tmp[0] =~ /^error/) {
+        $returnstatus = 'error retrieving full student data';
+        return $returnstatus;
+    } elsif (! @tmp) {
+        $returnstatus = 'okay: no student data';
+        return $returnstatus;
+    }
+    my %studentdata = @tmp;
+    #
+    # Get database handle and clean out the tables 
+    my $dbh = &Apache::lonmysql::get_dbh();
+    $dbh->do('DELETE FROM '.$fulldump_response_table.' WHERE student_id='.
+             $student_id);
+    $dbh->do('DELETE FROM '.$fulldump_part_table.' WHERE student_id='.
+             $student_id);
+    $dbh->do('DELETE FROM '.$fulldump_timestamp_table.' WHERE student_id='.
+             $student_id);
+    #
+    # Parse and store the data into a form we can handle
+    my $partdata;
+    my $respdata;
+    while (my ($key,$value) = each(%studentdata)) {
+        next if ($key =~ /^(\d+):(resource$|subnum$|keys:)/);
+        my ($transaction,$symb,$parameter) = split(':',$key);
+        my $symb_id = &get_symb_id($symb);
+        if ($parameter eq 'timestamp') {
+            # We can deal with 'timestamp' right away
+            my @timestamp_storage = ($symb_id,$student_id,
+                                     $transaction,$value);
+            my $store_command = 'INSERT INTO '.$fulldump_timestamp_table.
+                " VALUES ('".join("','",@timestamp_storage)."');";
+            $dbh->do($store_command);
+            if ($dbh->err()) {
+                &Apache::lonnet::logthis('unable to execute '.$store_command);
+                &Apache::lonnet::logthis($dbh->errstr());
+            }
+            next;
+        } elsif ($parameter eq 'version') {
+            next;
+        } elsif ($parameter =~ /^resource\.(.*)\.(tries|award|awarded|previous|solved|awarddetail|submission)\s*$/){
+            # we do not have enough information to store an 
+            # entire row, so we save it up until later.
+            my ($part_and_resp_id,$field) = ($1,$2);
+            my ($part,$part_id,$resp,$resp_id);
+            if ($part_and_resp_id =~ /\./) {
+                ($part,$resp) = split(/\./,$part_and_resp_id);
+                $part_id = &get_part_id($part);
+                $resp_id = &get_part_id($resp);
+            } else {
+                $part_id = &get_part_id($part_and_resp_id);
+            }
+            if ($field =~ /^(tries|award|awarded|previous)$/) {
+                $partdata->{$symb_id}->{$part_id}->{$transaction}->{$field}=$value;
+            }
+            if (defined($resp_id) &&
+                $field =~ /^(tries|awarddetail|awarded|submission)$/) {
+                if ($field eq 'submission') {
+                    # We have to be careful with user supplied input.
+                    # most of the time we are okay because it is escaped.
+                    # However, there is one wrinkle: submissions which end in
+                    # and odd number of '\' cause insert errors to occur.  
+                    # Best trap this somehow...
+                    my ($offensive_string) = ($value =~ /(\\+)$/);
+                    if (length($offensive_string) % 2) {
+                        $value =~ s/\\$/\\\\/;
+                    }
+                }
+                $respdata->{$symb_id}->{$part_id}->{$resp_id}->{$transaction}->{$field}=$value;
+            }
+        }
+    }
+    ##
+    ## Store the part data
+    my $store_command = 'INSERT INTO '.$fulldump_part_table.
+        ' VALUES '."\n";
+    my $store_rows = 0;
+    while (my ($symb_id,$hash1) = each (%$partdata)) {
+        while (my ($part_id,$hash2) = each (%$hash1)) {
+            while (my ($transaction,$data) = each (%$hash2)) {
+                $store_command .= "('".join("','",$symb_id,$part_id,
+                                            $student_id,
+                                            $transaction,
+                                            $data->{'tries'},
+                                            $data->{'award'},
+                                            $data->{'awarded'},
+                                            $data->{'previous'})."'),";
+                $store_rows++;
+            }
+        }
+    }
+    if ($store_rows) {
+        chop($store_command);
+        $dbh->do($store_command);
+        if ($dbh->err) {
+            $returnstatus = 'error storing part data';
+            &Apache::lonnet::logthis('insert error '.$dbh->errstr());
+            &Apache::lonnet::logthis("While attempting\n".$store_command);
+        }
+    }
+    ##
+    ## Store the response data
+    $store_command = 'INSERT INTO '.$fulldump_response_table.
+        ' VALUES '."\n";
+    $store_rows = 0;
+    while (my ($symb_id,$hash1) = each (%$respdata)) {
+        while (my ($part_id,$hash2) = each (%$hash1)) {
+            while (my ($resp_id,$hash3) = each (%$hash2)) {
+                while (my ($transaction,$data) = each (%$hash3)) {
+                    $store_command .= "('".join("','",$symb_id,$part_id,
+                                                $resp_id,$student_id,
+                                                $transaction,
+                                                $data->{'tries'},
+                                                $data->{'awarddetail'},
+                                                $data->{'awarded'},
+                                                '','',
+                                                $data->{'submission'})."'),";
+                    $store_rows++;
+                }
+            }
+        }
+    }
+    if ($store_rows) {
+        chop($store_command);
+        $dbh->do($store_command);
+        if ($dbh->err) {
+            $returnstatus = 'error storing response data';
+            &Apache::lonnet::logthis('insert error '.$dbh->errstr());
+            &Apache::lonnet::logthis("While attempting\n".$store_command);
+        }
+    }
+    ##
+    ## Update the students "current" data in the performance 
+    ## and parameters tables.
+    my ($status,undef) = &store_student_data
+        ($sname,$sdom,$courseid,
+         &Apache::lonnet::convert_dump_to_currentdump(\%studentdata));
+    if ($returnstatus eq 'okay' && $status ne 'okay') {
+        $returnstatus = 'error storing current data:'.$status;
+    } elsif ($status ne 'okay') {
+        $returnstatus .= ' error storing current data:'.$status;
+    }        
+    ##
+    ## Update the students time......
+    if ($returnstatus eq 'okay') {
+        &Apache::lonmysql::replace_row
+            ($studentdata_table,
+             [$student_id,$time_of_retrieval,$time_of_retrieval,undef,undef]);
+    }
+    return $returnstatus;
+}
+
+################################################
+################################################
+
+=pod
+
 =item &update_student_data()
 
 Input: $sname, $sdom, $courseid
@@ -941,6 +1328,22 @@
         return ('no data',undef);
     }
     my %student_data = @tmp;
+    my @Results = &store_student_data($sname,$sdom,$courseid,\%student_data);
+    #
+    # Set the students update time
+    &Apache::lonmysql::replace_row($studentdata_table,
+                         [$student_id,$time_of_retrieval,undef,undef,undef]);
+    #
+    return @Results;
+}
+
+sub store_student_data {
+    my ($sname,$sdom,$courseid,$student_data) = @_;
+    #
+    my $student_id = &get_student_id($sname,$sdom);
+    my $student = $sname.':'.$sdom;
+    #
+    my $returnstatus = 'okay';
     #
     # Remove all of the students data from the table
     my $dbh = &Apache::lonmysql::get_dbh();
@@ -960,7 +1363,7 @@
     my $store_performance_command = 'INSERT INTO '.$performance_table.
         ' VALUES '."\n";
     return ('error',undef) if (! defined($dbh));
-    while (my ($current_symb,$param_hash) = each(%student_data)) {
+    while (my ($current_symb,$param_hash) = each(%{$student_data})) {
         #
         # make sure the symb is set up properly
         my $symb_id = &get_symb_id($current_symb);
@@ -1015,48 +1418,37 @@
         &Apache::lonnet::logthis('rows_stored = '.$rows_stored);
         &Apache::lonnet::logthis('student_id = '.$student_id);
         $returnstatus = 'error: unable to insert parameters into database';
-        return ($returnstatus,\%student_data);
+        return ($returnstatus,$student_data);
     }
     $dbh->do($store_performance_command);
     if ($dbh->err()) {
         &Apache::lonnet::logthis(' bigass insert error:'.$dbh->errstr());
         &Apache::lonnet::logthis('command = '.$store_performance_command);
         $returnstatus = 'error: unable to insert performance into database';
-        return ($returnstatus,\%student_data);
+        return ($returnstatus,$student_data);
     }
     $elapsed += Time::HiRes::time - $start;
-    #
-    # Set the students update time
-    &Apache::lonmysql::replace_row($studentdata_table,
-                                   [$student_id,$time_of_retrieval,undef,undef]);
-    return ($returnstatus,\%student_data);
+    return ($returnstatus,$student_data);
 }
 
-################################################
-################################################
+######################################
+######################################
 
 =pod
 
-=item &ensure_current_data()
+=item &ensure_tables_are_set_up($courseid)
 
-Input: $sname, $sdom, $courseid
+Checks to be sure the MySQL tables for the given class are set up.
+If $courseid is omitted it will be obtained from the environment.
 
-Output: $status, $data
-
-This routine ensures the data for a given student is up to date.  It calls
-&init_dbs() if the tables do not exist.  The $studentdata_table is queried
-to determine the time of the last update.  If the students data is out of
-date, &update_student_data() is called.  The return values from the call
-to &update_student_data() are returned.
+Returns nothing on success and 'error' on failure
 
 =cut
 
-################################################
-################################################
-sub ensure_current_data {
-    my ($sname,$sdom,$courseid) = @_;
-    my $status = 'okay';   # return value
-    #
+######################################
+######################################
+sub ensure_tables_are_set_up {
+    my ($courseid) = @_;
     $courseid = $ENV{'request.course.id'} if (! defined($courseid));
     # 
     # Clean out package variables
@@ -1065,7 +1457,8 @@
     # if the tables do not exist, make them
     my @CurrentTable = &Apache::lonmysql::tables_in_db();
     my ($found_symb,$found_student,$found_part,$found_studentdata,
-        $found_performance,$found_parameters);
+        $found_performance,$found_parameters,$found_fulldump_part,
+        $found_fulldump_response,$found_fulldump_timestamp);
     foreach (@CurrentTable) {
         $found_symb        = 1 if ($_ eq $symb_table);
         $found_student     = 1 if ($_ eq $student_table);
@@ -1073,14 +1466,47 @@
         $found_studentdata = 1 if ($_ eq $studentdata_table);
         $found_performance = 1 if ($_ eq $performance_table);
         $found_parameters  = 1 if ($_ eq $parameters_table);
+        $found_fulldump_part      = 1 if ($_ eq $fulldump_part_table);
+        $found_fulldump_response  = 1 if ($_ eq $fulldump_response_table);
+        $found_fulldump_timestamp = 1 if ($_ eq $fulldump_timestamp_table);
     }
     if (!$found_symb        || !$found_studentdata || 
         !$found_student     || !$found_part   ||
-        !$found_performance || !$found_parameters) {
+        !$found_performance || !$found_parameters ||
+        !$found_fulldump_part || !$found_fulldump_response ||
+        !$found_fulldump_timestamp ) {
         if (&init_dbs($courseid)) {
-            return ('error',undef);
+            return 'error';
         }
     }
+}
+
+################################################
+################################################
+
+=pod
+
+=item &ensure_current_data()
+
+Input: $sname, $sdom, $courseid
+
+Output: $status, $data
+
+This routine ensures the data for a given student is up to date.
+The $studentdata_table is queried to determine the time of the last update.  
+If the students data is out of date, &update_student_data() is called.  
+The return values from the call to &update_student_data() are returned.
+
+=cut
+
+################################################
+################################################
+sub ensure_current_data {
+    my ($sname,$sdom,$courseid) = @_;
+    my $status = 'okay';   # return value
+    #
+    $courseid = $ENV{'request.course.id'} if (! defined($courseid));
+    &ensure_tables_are_set_up($courseid);
     #
     # Get the update time for the user
     my $updatetime = 0;
@@ -1106,6 +1532,54 @@
 
 =pod
 
+=item &ensure_current_full_data($sname,$sdom,$courseid)
+
+Input: $sname, $sdom, $courseid
+
+Output: $status
+
+This routine ensures the fulldata (the data from a lonnet::dump, not a
+lonnet::currentdump) for a given student is up to date.
+The $studentdata_table is queried to determine the time of the last update.  
+If the students fulldata is out of date, &update_full_student_data() is
+called.  
+
+The return value from the call to &update_full_student_data() is returned.
+
+=cut
+
+################################################
+################################################
+sub ensure_current_full_data {
+    my ($sname,$sdom,$courseid) = @_;
+    my $status = 'okay';   # return value
+    #
+    $courseid = $ENV{'request.course.id'} if (! defined($courseid));
+    &ensure_tables_are_set_up($courseid);
+    #
+    # Get the update time for the user
+    my $modifiedtime = &Apache::lonnet::GetFileTimestamp
+        ($sdom,$sname,$courseid.'.db',
+         $Apache::lonnet::perlvar{'lonUsersDir'});
+    #
+    my $student_id = &get_student_id($sname,$sdom);
+    my @Result = &Apache::lonmysql::get_rows($studentdata_table,
+                                             "student_id ='$student_id'");
+    my $updatetime;
+    if (@Result && ref($Result[0]) eq 'ARRAY') {
+        $updatetime = $Result[0]->[2];
+    }
+    if (! defined($updatetime) || $modifiedtime > $updatetime) {
+        $status = &update_full_student_data($sname,$sdom,$courseid);
+    }
+    return $status;
+}
+
+################################################
+################################################
+
+=pod
+
 =item &get_student_data_from_performance_cache()
 
 Input: $sname, $sdom, $symb, $courseid
@@ -1482,6 +1956,21 @@
     $studentdata_table = $base_id.'_'.'studentdata';
     $performance_table = $base_id.'_'.'performance';
     $parameters_table  = $base_id.'_'.'parameters';
+    $fulldump_part_table      = $base_id.'_'.'partdata';
+    $fulldump_response_table  = $base_id.'_'.'responsedata';
+    $fulldump_timestamp_table = $base_id.'_'.'timestampdata';
+    #
+    @Tables = (
+               $symb_table,
+               $part_table,
+               $student_table,
+               $studentdata_table,
+               $performance_table,
+               $parameters_table,
+               $fulldump_part_table,
+               $fulldump_response_table,
+               $fulldump_timestamp_table,
+               );
     return;
 }
 
@@ -1499,8 +1988,8 @@
 ################################################
 ################################################
 
+} # End scope of table identifiers
 
-}
 ################################################
 ################################################
 

--matthew1064601091--