Diff for /loncom/metadata_database/parse_activity_log.pl between versions 1.13 and 1.14

version 1.13, 2005/02/09 21:54:15 version 1.14, 2005/03/31 22:09:40
Line 61  use Getopt::Long(); Line 61  use Getopt::Long();
 use IO::File;  use IO::File;
 use File::Copy;  use File::Copy;
 use Fcntl qw(:flock);  use Fcntl qw(:flock);
   use HTML::TokeParser;
   
 #  #
 # Determine parameters  # Determine parameters
Line 141  if ($log) { Line 142  if ($log) {
 ##  ##
 my $sourcefilename;   # activity log data  my $sourcefilename;   # activity log data
 my $newfilename;      # $sourcefilename will be renamed to this  my $newfilename;      # $sourcefilename will be renamed to this
 my $gz_sql_filename;  # the gzipped mysql backup data file name.  
 my $error_filename;   # Errors in parsing the activity log will be written here  my $error_filename;   # Errors in parsing the activity log will be written here
 if ($srcfile) {  if ($srcfile) {
     $sourcefilename = $srcfile;      $sourcefilename = $srcfile;
Line 150  if ($srcfile) { Line 150  if ($srcfile) {
 }  }
 my $sql_filename = $sourcefilename;  my $sql_filename = $sourcefilename;
 $sql_filename =~ s|[^/]*$|activity.log.sql|;  $sql_filename =~ s|[^/]*$|activity.log.sql|;
 $gz_sql_filename = $sql_filename.'.gz';  my $gz_sql_filename = $sql_filename.'.gz';
   #
   my $xml_filename = $sourcefilename;
   $xml_filename =~ s|[^/]*$|activity.log.xml|;
   my $gz_xml_filename = $xml_filename.'.gz';
   #
 $error_filename = $sourcefilename;  $error_filename = $sourcefilename;
 $error_filename =~ s|[^/]*$|activity.log.errors|;  $error_filename =~ s|[^/]*$|activity.log.errors|;
 $logthis->('Beginning logging '.time);  $logthis->('Beginning logging '.time);
   
   
 #  #
 # Wait for a lock on the lockfile to avoid collisions  # Wait for a lock on the lockfile to avoid collisions
 my $lockfilename = $sourcefilename.'.lock';  my $lockfilename = $sourcefilename.'.lock';
Line 192  close(LOCKFILE); Line 196  close(LOCKFILE);
 ##  ##
 ## Table definitions  ## Table definitions
 ##  ##
 my $prefix = $course.'_'.$domain.'_';  my %tables = &table_names($course,$domain);
 my $student_table = &Apache::lonmysql::fix_table_name($prefix.'students');  
 my $student_table_def =   my $student_table_def = 
 { id => $student_table,  { id => $tables{'student'},
   permanent => 'no',    permanent => 'no',
   columns => [    columns => [
               { name => 'student_id',                { name => 'student_id',
Line 209  my $student_table_def = Line 212  my $student_table_def =
       'PRIMARY KEY' => ['student_id',],        'PRIMARY KEY' => ['student_id',],
           };            };
   
 my $res_table = &Apache::lonmysql::fix_table_name($prefix.'resource');  
 my $res_table_def =   my $res_table_def = 
 { id => $res_table,  { id => $tables{'res'},
   permanent => 'no',    permanent => 'no',
   columns => [{ name => 'res_id',    columns => [{ name => 'res_id',
                 type => 'MEDIUMINT UNSIGNED',                  type => 'MEDIUMINT UNSIGNED',
Line 224  my $res_table_def = Line 226  my $res_table_def =
   'PRIMARY KEY' => ['res_id'],    'PRIMARY KEY' => ['res_id'],
 };  };
   
 #my $action_table = &Apache::lonmysql::fix_table_name($prefix.'actions');  
 #my $action_table_def =  #my $action_table_def =
 #{ id => $action_table,  #{ id => $action_table,
 #  permanent => 'no',  #  permanent => 'no',
Line 239  my $res_table_def = Line 240  my $res_table_def =
 #  'PRIMARY KEY' => ['action_id',],   #  'PRIMARY KEY' => ['action_id',], 
 #};  #};
   
 my $machine_table = &Apache::lonmysql::fix_table_name($prefix.'machine_table');  
 my $machine_table_def =  my $machine_table_def =
 { id => $machine_table,  { id => $tables{'machine'},
   permanent => 'no',    permanent => 'no',
   columns => [{ name => 'machine_id',    columns => [{ name => 'machine_id',
                 type => 'MEDIUMINT UNSIGNED',                  type => 'MEDIUMINT UNSIGNED',
Line 254  my $machine_table_def = Line 254  my $machine_table_def =
   'PRIMARY KEY' => ['machine_id',],    'PRIMARY KEY' => ['machine_id',],
  };   };
   
 my $activity_table = &Apache::lonmysql::fix_table_name($prefix.'activity');  
 my $activity_table_def =   my $activity_table_def = 
 { id => $activity_table,  { id => $tables{'activity'},
   permanent => 'no',    permanent => 'no',
   columns => [    columns => [
               { name => 'res_id',                { name => 'res_id',
Line 288  my $activity_table_def = Line 287  my $activity_table_def =
   
 my @Activity_Table = ($activity_table_def);  my @Activity_Table = ($activity_table_def);
 my @ID_Tables = ($student_table_def,$res_table_def,$machine_table_def);  my @ID_Tables = ($student_table_def,$res_table_def,$machine_table_def);
                  
 ##  ##
 ## End of table definitions  ## End of table definitions
 ##  ##
   $logthis->('tables = '.join(',',keys(%tables)));
   
 $logthis->('Connectiong to mysql');  $logthis->('Connectiong to mysql');
 &Apache::lonmysql::set_mysql_user_and_password('www',  &Apache::lonmysql::set_mysql_user_and_password('www',
Line 302  if (!&Apache::lonmysql::verify_sql_conne Line 303  if (!&Apache::lonmysql::verify_sql_conne
 }  }
 $logthis->('SQL connection is up');  $logthis->('SQL connection is up');
   
 if (-s $gz_sql_filename) {  my $missing_table = &check_for_missing_tables(values(%tables));
   if (-s $gz_sql_filename && ! -s $gz_xml_filename) {
     my $backup_modification_time = (stat($gz_sql_filename))[9];      my $backup_modification_time = (stat($gz_sql_filename))[9];
     $logthis->($gz_sql_filename.' was last modified '.      $logthis->($gz_sql_filename.' was last modified '.
                localtime($backup_modification_time).                 localtime($backup_modification_time).
                '('.$backup_modification_time.')');                 '('.$backup_modification_time.')');
     # Check for missing tables      if ($missing_table) {
     my @Current_Tables = &Apache::lonmysql::tables_in_db();          # If the backup happened prior to the last table modification,
     $logthis->(join(',',@Current_Tables));          # we need to save the tables.
     my %Found;          if (&latest_table_modification_time() > $backup_modification_time) {
     foreach my $tablename (@Current_Tables) {              # Save the current tables in case we need them another time.
         foreach my $table (@Activity_Table,@ID_Tables) {              $logthis->('Backing existing tables up');
             if ($tablename eq  $table->{'id'}) {              &backup_tables_as_xml($gz_xml_filename.'.save_'.time,\%tables);
                 $Found{$tablename}++;  
             }  
         }  
     }  
     $logthis->('Found tables '.join(',',keys(%Found)));  
     my $missing_a_table = 0;  
     foreach my $table (@Activity_Table,@ID_Tables) {      
         # Hmmm, should I dump the tables?  
         if (! $Found{$table->{'id'}}) {  
             $logthis->('Missing table '.$table->{'id'});  
             $missing_a_table = 1;  
             last;  
         }          }
           $time_this->();
           &load_backup_sql_tables($gz_sql_filename);
           &backup_tables_as_xml($gz_xml_filename,\%tables);
           $time_this->('load backup tables');
     }      }
     if ($missing_a_table) {  } elsif (-s $gz_xml_filename) {
       my $backup_modification_time = (stat($gz_xml_filename))[9];
       $logthis->($gz_xml_filename.' was last modified '.
                  localtime($backup_modification_time).
                  '('.$backup_modification_time.')');
       if ($missing_table) {
         my $table_modification_time = $backup_modification_time;          my $table_modification_time = $backup_modification_time;
         # If the backup happened prior to the last table modification,          # If the backup happened prior to the last table modification,
         foreach my $table (@Activity_Table,@ID_Tables) {              # we need to save the tables.
             my %tabledata = &Apache::lonmysql::table_information($table->{'id'});          if (&latest_table_modification_time() > $backup_modification_time) {
             next if (! scalar(keys(%tabledata))); # table does not exist  
             if ($table_modification_time < $tabledata{'Update_time'}) {  
                 $table_modification_time = $tabledata{'Update_time'};  
             }  
         }  
         $logthis->("Table modification time = ".$table_modification_time);  
         if ($table_modification_time > $backup_modification_time) {  
             # Save the current tables in case we need them another time.              # Save the current tables in case we need them another time.
             my $backup_name = $gz_sql_filename.'.'.time;              $logthis->('Backing existing tables up');
             $logthis->('Backing existing tables up in '.$backup_name);              &backup_tables_as_xml($gz_xml_filename.'.save_'.time,\%tables);
             &backup_tables($backup_name);  
         }          }
         $time_this->();          $time_this->();
         &load_backup_tables($gz_sql_filename);          # We have to make our own tables for the xml format
           &drop_tables();
           &create_tables();
           &load_backup_xml_tables($gz_xml_filename,\%tables);
         $time_this->('load backup tables');          $time_this->('load backup tables');
     }      }    
 }  }
   
 ##  ##
Line 375  my $error_fh = IO::File->new(">>$error_f Line 369  my $error_fh = IO::File->new(">>$error_f
 ## Parse the course log  ## Parse the course log
 $logthis->('processing course log');  $logthis->('processing course log');
 if (-s $newfilename) {  if (-s $newfilename) {
     my $result = &process_courselog($newfilename,$error_fh);      my $result = &process_courselog($newfilename,$error_fh,\%tables);
     if (! defined($result)) {      if (! defined($result)) {
         # Something went wrong along the way...          # Something went wrong along the way...
         $logthis->('process_courselog returned undef');          $logthis->('process_courselog returned undef');
Line 383  if (-s $newfilename) { Line 377  if (-s $newfilename) {
     } elsif ($result > 0) {      } elsif ($result > 0) {
         $time_this->();          $time_this->();
         $logthis->('process_courselog returned '.$result.' backing up tables');          $logthis->('process_courselog returned '.$result.' backing up tables');
         &backup_tables($gz_sql_filename);          &backup_tables_as_xml($gz_xml_filename,\%tables);
         $time_this->('write backup tables');          $time_this->('write backup tables');
     }      }
     if ($drop_when_done) { &drop_tables(); $logthis->('dropped tables'); }      if ($drop_when_done) { &drop_tables(); $logthis->('dropped tables'); }
Line 416  foreach my $file ($lockfilename, $error_ Line 410  foreach my $file ($lockfilename, $error_
     }      }
 }  }
   
   
 exit 0;   # Everything is okay, so end here before it gets worse.  exit 0;   # Everything is okay, so end here before it gets worse.
   
 ########################################################  ########################################################
 ########################################################  ########################################################
   sub table_names {
       my ($course,$domain) = @_;
       my $prefix = $course.'_'.$domain.'_';
       #
       my %tables = 
           ( student =>&Apache::lonmysql::fix_table_name($prefix.'students'),
             res     =>&Apache::lonmysql::fix_table_name($prefix.'resource'),
             machine =>&Apache::lonmysql::fix_table_name($prefix.'machine_table'),
             activity=>&Apache::lonmysql::fix_table_name($prefix.'activity'),
             );
       return %tables;
   }
   
   ########################################################
   ########################################################
 ##  ##
 ##                 Process Course Log  ##                 Process Course Log
 ##  ##
Line 429  exit 0;   # Everything is okay, so end h Line 437  exit 0;   # Everything is okay, so end h
 #  #
 # Returns the number of lines in the activity.log file that were processed.  # Returns the number of lines in the activity.log file that were processed.
 sub process_courselog {  sub process_courselog {
     my ($inputfile,$error_fh) = @_;      my ($inputfile,$error_fh,$tables) = @_;
     if (! open(IN,$inputfile)) {      if (! open(IN,$inputfile)) {
         warn "Unable to open '$inputfile' for reading";          warn "Unable to open '$inputfile' for reading";
         $logthis->("Unable to open '$inputfile' for reading");          $logthis->("Unable to open '$inputfile' for reading");
Line 438  sub process_courselog { Line 446  sub process_courselog {
     my ($linecount,$insertcount);      my ($linecount,$insertcount);
     my $dbh = &Apache::lonmysql::get_dbh();      my $dbh = &Apache::lonmysql::get_dbh();
     #      #
     # Timing variables      &store_entry();
     my @RowData;  
     while (my $line=<IN>){      while (my $line=<IN>){
         # last if ($linecount > 1000);          # last if ($linecount > 1000);
         #          #
Line 449  sub process_courselog { Line 456  sub process_courselog {
         $linecount++;          $linecount++;
         # print $linecount++.$/;          # print $linecount++.$/;
         my ($timestamp,$host,$log)=split(/\:/,$line,3);          my ($timestamp,$host,$log)=split(/\:/,$line,3);
         $time_this->('splitline');  
         #          #
         # $log has the actual log entries; currently still escaped, and          # $log has the actual log entries; currently still escaped, and
         # %26(timestamp)%3a(url)%3a(user)%3a(domain)          # %26(timestamp)%3a(url)%3a(user)%3a(domain)
Line 461  sub process_courselog { Line 467  sub process_courselog {
         # get delimiter between timestamped entries to be &&&          # get delimiter between timestamped entries to be &&&
         $log=~s/\%26(\d{9,10})\%3a/\&\&\&$1\%3a/g;          $log=~s/\%26(\d{9,10})\%3a/\&\&\&$1\%3a/g;
         $log = &unescape($log);          $log = &unescape($log);
         $time_this->('translate_and_unescape');  
         # now go over all log entries           # now go over all log entries 
         if (! defined($host)) { $host = 'unknown'; }          if (! defined($host)) { $host = 'unknown'; }
         my $machine_id = &get_id($machine_table,'machine',$host);  
         my $prevchunk = 'none';          my $prevchunk = 'none';
         foreach my $chunk (split(/\&\&\&/,$log)) {          foreach my $chunk (split(/\&\&\&/,$log)) {
             my $warningflag = '';              my $warningflag = '';
             $time_this->();  
     my ($time,$res,$uname,$udom,$action,@values)= split(/:/,$chunk);      my ($time,$res,$uname,$udom,$action,@values)= split(/:/,$chunk);
             my $student = $uname.':'.$udom;  
             if (! defined($res) || $res =~ /^\s*$/) {              if (! defined($res) || $res =~ /^\s*$/) {
                 $res = '/adm/roles';                  $res = '/adm/roles';
                 $action = 'LOGIN';                  $action = 'LOGIN';
Line 495  sub process_courselog { Line 497  sub process_courselog {
                          '@values = '.join('&',@values));                           '@values = '.join('&',@values));
                 next; #skip it if we cannot understand what is happening.                  next; #skip it if we cannot understand what is happening.
             }              }
             if (! defined($student) || $student eq ':') {  
                 $student = 'unknown';  
                 $warningflag .= 'student';  
             }  
             if (! defined($res) || $res =~ /^\s*$/) {  
                 $res = 'unknown';  
                 $warningflag .= 'res';  
             }  
             if (! defined($action) || $action =~ /^\s*$/) {  
                 $action = 'unknown';  
                 $warningflag .= 'action';  
             }  
             if (! defined($time) || $time !~ /^\d+$/) {  
                 $time = 0;  
                 $warningflag .= 'time';  
             }  
             #  
             $time_this->('split_and_error_check');  
             my $student_id = &get_id($student_table,'student',$student);  
             my $res_id     = &get_id($res_table,'resource',$res);  
 #            my $action_id  = &get_id($action_table,'action',$action);  
             my $sql_time   = &Apache::lonmysql::sqltime($time);  
             #  
             if (! defined($student_id) || $student_id eq '') {   
                 $warningflag.='student_id';   
             }  
             if (! defined($res_id) || $res_id eq '') {   
                 $warningflag.='res_id';   
             }  
 #            if (! defined($action_id) || $action_id eq '') {   
 #                $warningflag.='action_id';   
 #            }  
             if ($warningflag ne '') {  
                 print $error_fh 'full log entry:'.$log.$/;  
                 print $error_fh 'error on chunk:'.$chunk.$/;  
                 $logthis->('warningflag ('.$warningflag.') on chunk '.  
                            $/.$chunk.$/.'prevchunk = '.$/.$prevchunk);  
                 $prevchunk .= $chunk;  
                 next; # skip this chunk  
             }  
             #              #
             my $store_values;              my %data = (student  => $uname.':'.$udom,
                           resource => $res,
                           machine  => $host,
                           action   => $action,
                           time => &Apache::lonmysql::sqltime($time));
             if ($action eq 'POST') {              if ($action eq 'POST') {
                 $store_values =                   $data{'action_values'} =
                     $dbh->quote(join('&',map { &escape($_); } @values));                      $dbh->quote(join('&',map { &escape($_); } @values));
             } else {              } else {
                 $store_values = $dbh->quote(join('&',@values));                  $data{'action_values'} = $dbh->quote(join('&',@values));
             }              }
             $time_this->('get_ids');              my $error = &store_entry($dbh,$tables,\%data);
             #              if ($error) {
             my $row = [$res_id,                  $logthis->('error store_entry:'.$error." on %data");
                        qq{'$sql_time'},  
                        $student_id,  
                        "'".$action."'",  
 #                       $action_id,  
                        qq{''},        # idx  
                        $machine_id,  
                        $store_values];  
             push(@RowData,$row);  
             $time_this->('push_row');  
             $prevchunk = $chunk;  
             #  
         }  
         $time_this->();  
         if ((scalar(@RowData) > 0) && ($linecount % 100 == 0)) {  
             my $result = &Apache::lonmysql::bulk_store_rows($activity_table,  
                                                             undef,  
                                                             \@RowData);  
             # $logthis->('result = '.$result);  
             $time_this->('bulk_store_rows');  
             if (! defined($result)) {  
                 my $error = &Apache::lonmysql::get_error();  
                 warn "Error occured during insert.".$error;  
                 $logthis->('error = '.$error);  
             }              }
             undef(@RowData);              $prevchunk = $chunk;
         }          }
     }      }
     if (@RowData) {      my $result = &store_entry($dbh,$tables);
         $time_this->();      if (! defined($result)) {
         $logthis->('storing '.$linecount);          my $error = &Apache::lonmysql::get_error();
         my $result = &Apache::lonmysql::bulk_store_rows($activity_table,          warn "Error occured during insert.".$error;
                                                         undef,          $logthis->('error = '.$error);
                                                         \@RowData);  
         $logthis->('result = '.$result);  
         $time_this->('bulk_store_rows');  
         if (! defined($result)) {  
             my $error = &Apache::lonmysql::get_error();  
             warn "Error occured during insert.".$error;  
             $logthis->('error = '.$error);  
         }  
         undef(@RowData);  
     }      }
     close IN;      close IN;
 #    print "Number of lines: ".$linecount.$/;  
 #    print "Number of inserts: ".$insertcount.$/;  
     return $linecount;      return $linecount;
 }  }
   
   
 ##  ##
 ## Somtimes, instead of doing something, doing nothing is appropriate.  ## default value for $logthis and $time_this
 sub nothing {  sub nothing {
     return;      return;
 }  }
   
 ##  ##
 ## Logging routine  ## Logging routine (look for $log)
 ##  ##
 sub log_to_file {  sub log_to_file {
     my ($input)=@_;      my ($input)=@_;
Line 643  sub outputtimes { Line 575  sub outputtimes {
   
 }  }
   
   sub latest_table_modification_time {
       my $latest_time;
       foreach my $table (@Activity_Table,@ID_Tables) {    
           my %tabledata = &Apache::lonmysql::table_information($table->{'id'});
           next if (! scalar(keys(%tabledata))); # table does not exist
           if (! defined($latest_time) ||
               $latest_time < $tabledata{'Update_time'}) {
               $latest_time = $tabledata{'Update_time'};
           }
       }
       return $latest_time;
   }
   
   sub check_for_missing_tables {
       my @wanted_tables = @_;
       # Check for missing tables
       my @Current_Tables = &Apache::lonmysql::tables_in_db();
       my %Found;
       foreach my $tablename (@Current_Tables) {
           foreach my $table (@wanted_tables) {
               if ($tablename eq  $table) {
                   $Found{$tablename}++;
               }
           }
       }
       $logthis->('Found tables '.join(',',keys(%Found)));
       my $missing_a_table = 0;
       foreach my $table (@wanted_tables) {
           if (! $Found{$table}) {
               $logthis->('Missing table '.$table);
               $missing_a_table = 1;
               last;
           }
       }
       return $missing_a_table;
   }
   
 ##  ##
 ## Use mysqldump to store backups of the tables  ## Use mysqldump to store backups of the tables
 ##  ##
 sub backup_tables {  sub backup_tables_as_sql {
     my ($gz_sql_filename) = @_;      my ($gz_sql_filename) = @_;
     my $command = qq{mysqldump --quote-names --opt loncapa };      my $command = qq{mysqldump --quote-names --opt loncapa };
     foreach my $table (@ID_Tables,@Activity_Table) {      foreach my $table (@ID_Tables,@Activity_Table) {
Line 663  sub backup_tables { Line 631  sub backup_tables {
 ##  ##
 ## Load in mysqldumped files  ## Load in mysqldumped files
 ##  ##
 sub load_backup_tables {  sub load_backup_sql_tables {
     my ($gz_sql_filename) = @_;      my ($gz_sql_filename) = @_;
     if (-s $gz_sql_filename) {      if (-s $gz_sql_filename) {
         $logthis->('loading data from gzipped sql file');          $logthis->('loading data from gzipped sql file');
Line 756  sub get_id { Line 724  sub get_id {
   
 } # End of ID scoping  } # End of ID scoping
   
   ###############################################################
   ###############################################################
   ##
   ##   Save as XML
   ##
   ###############################################################
   ###############################################################
   sub backup_tables_as_xml {
       my ($filename,$tables) = @_;
       open(XMLFILE,"|gzip - > $filename") || return ('error:unable to write '.$filename);
       my $query = qq{
           SELECT B.resource,
                  A.time,
                  A.idx,
                  C.student,
                  A.action,
                  E.machine,
                  A.action_values 
               FROM $tables->{'activity'} AS A
               LEFT JOIN $tables->{'res'}      AS B ON B.res_id=A.res_id 
               LEFT JOIN $tables->{'student'}  AS C ON C.student_id=A.student_id 
               LEFT JOIN $tables->{'machine'}  AS E ON E.machine_id=A.machine_id
               ORDER BY A.time DESC
           };
       $query =~ s/\s+/ /g;
       my $dbh = &Apache::lonmysql::get_dbh();
       my $sth = $dbh->prepare($query);
       if (! $sth->execute()) {
           $logthis->('<font color="blue">'.
                      'WARNING: Could not retrieve from database:'.
                      $sth->errstr().'</font>');
           return undef;
       } else {
           my ($res,$sqltime,$idx,$student,$action,$machine,$action_values);
           if ($sth->bind_columns(\$res,\$sqltime,\$idx,\$student,\$action,
                                  \$machine,\$action_values)) {
               
               while ($sth->fetch) {
                   print XMLFILE '<row>'.
                       qq{<resource>$res</resource>}.
                       qq{<time>$sqltime</time>}.
                       qq{<idx>$idx</idx>}.
                       qq{<student>$student</student>}.
                       qq{<action>$action</action>}.
                       qq{<machine>$machine</machine>}.
                       qq{<action_values>$action_values</action_values>}.
                       '</row>'.$/;
               }
           } else {
               warn "Unable to bind to columns.\n";
               return undef;
           }
       }
       close XMLFILE;
       return;
   }
   
   ###############################################################
   ###############################################################
   ##
   ##   load as xml
   ##
   ###############################################################
   ###############################################################
   sub load_backup_xml_tables {
       my ($filename,$tables) = @_;
       my $xmlfh;
       open($xmlfh,"cat $filename | gzip -d - |");
       if (! defined($xmlfh)) {
           return ('error:unable to read '.$filename);
       }
       my $dbh = &Apache::lonmysql::get_dbh();
       my $parser = HTML::TokeParser->new($xmlfh);
       $parser->xml_mode('1');
       &store_entry();
       my %data;
       while (my $token = $parser->get_token()) {
           if ($token->[0] eq 'S' && $token->[1] eq 'row') {
               undef(%data);
           }
           foreach my $tag ('resource','time','idx',
                            'student','action','machine','action_values') {
               if ($token->[0] eq 'S' && $token->[1] eq $tag) {
                   my $text = $parser->get_text("/$tag");
                   $data{$tag} = $text;
               }
           }
           if ($token->[0] eq 'E' && $token->[1] eq 'row') {
               $data{'action_values'} =qq{'$data{'action_values'}'};
               my $error = &store_entry($dbh,$tables,\%data);
           }
       }
       &store_entry($dbh,$tables);
       return;
   }
   
   
   #######################################################################
   #######################################################################
   ##
   ## store_entry - accumulate data to be inserted into the database
   ## 
   ## Pass no values in to clear accumulator
   ## Pass ($dbh,\%tables) to initiate storage of values
   ## Pass ($dbh,\%tables,\%data) to use normally
   ##
   #######################################################################
   #######################################################################
   
   {
       my @rows;
       my $max_row_count = 100;
   
   sub store_entry {
       if (! @_) {
           undef(@rows);
           return '';
       }
       my ($dbh,$tables,$data) = @_;
       return if (! defined($tables));
       if (defined($data)) {
           my $error;
           foreach my $field ('student','resource','action','time') {
               if (! defined($data->{$field}) || $data->{$field} eq ':' ||
                   $data->{$field}=~ /^\s*$/) {
                   $error.=$field.',';
               }
           }
           if ($error) { $error=~s/,$//; return $error; }
           #
           my $student_id = &get_id($tables->{'student'},'student',
                                    $data->{'student'});
           my $res_id     = &get_id($tables->{'res'},
                                    'resource',$data->{'resource'});
           my $machine_id = &get_id($tables->{'machine'},
                                    'machine',$data->{'machine'});
           my $idx = $data->{'idx'}; if (! $idx) { $idx = "''"; }
           #
           push(@rows,[$res_id,
                       qq{'$data->{'time'}'},
                       $student_id,
                       qq{'$data->{'action'}'},
                       $idx,
                       $machine_id,
                       $data->{'action_values'}]);
       }
       if (defined($tables) && 
           ( (! defined($data) && scalar(@rows)) || scalar(@rows)>$max_row_count)
           ){
           # Store the rows
           my $result = 
               &Apache::lonmysql::bulk_store_rows($tables->{'activity'},
                                                  undef,
                                                  \@rows);
           if (! defined($result)) {
               my $error = &Apache::lonmysql::get_error();
               warn "Error occured during insert.".$error;
               return $error;
           }
           undef(@rows);
           return $result if (! defined($data));
       }
   
       return '';
   }
   
   } # end of scope for &store_entry
   
 ###############################################################  ###############################################################
 ###############################################################  ###############################################################

Removed from v.1.13  
changed lines
  Added in v.1.14


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>