Diff for /loncom/interface/lonmysql.pm between versions 1.2 and 1.3

version 1.2, 2002/07/28 18:21:13 version 1.3, 2002/07/30 18:26:40
Line 79  for &create_table for a description of w Line 79  for &create_table for a description of w
                     auto_inc    => 'yes'                      auto_inc    => 'yes'
                     }                      }
                 verbage => { type => 'TEXT' },                  verbage => { type => 'TEXT' },
                 idx_verbage => { type => 'FULLTEXT',  
                                  target => 'verbage'  
                                  }  
             },              },
             column_order => [qw/id verbage idx_verbage/]              column_order => [qw/id verbage idx_verbage/],
             });              fulltext => [qw/verbage/],
           });
   
 The above command will create a table with two columns, 'id' and 'verbage'.  The above command will create a table with two columns, 'id' and 'verbage'.
   
Line 94  The above command will create a table wi Line 92  The above command will create a table wi
 text string to be stored.  Depending on your intentions for this database,  text string to be stored.  Depending on your intentions for this database,
 setting restrictions => 'NOT NULL' may help you avoid storing empty data.  setting restrictions => 'NOT NULL' may help you avoid storing empty data.
   
 'idx_verbage' sets up the 'verbage' column for 'FULLTEXT' searching.  the fulltext element sets up the 'verbage' column for 'FULLTEXT' searching.
   
   
   
Line 120  Since the above table was created with t Line 118  Since the above table was created with t
 autoincrement, providing a value is unnecessary even though the column was  autoincrement, providing a value is unnecessary even though the column was
 marked as 'NOT NULL'.  marked as 'NOT NULL'.
   
 In the future an array of arrays or hashes may be supported, but currently  
 the system only performs one insert at a time.  Given the nature of this   
 interface, transactions (locking of the table) are not supported.  
   
   
   
 =item Retrieving rows  =item Retrieving rows
Line 168  The following entries are allowed in the Line 162  The following entries are allowed in the
   
 =over 4  =over 4
   
 =item columns   =item Name
   
   Table name.
   
   =item Type            
   
   The type of table, typically MyISAM.
   
   =item Row_format
   
   Describes how rows should be stored in the table.  DYNAMIC or STATIC.
   
   =item Create_time
   
   The date of the tables creation.
   
   =item Update_time
   
   The date of the last modification of the table.
   
   =item Check_time
   
   Usually NULL. 
   
   =item Avg_row_length
   
   The average length of the rows.
   
   =item Data_length
   
   The length of the data stored in the table (bytes)
   
   =item Max_data_length
   
   The maximum possible size of the table (bytes).
   
 The columns information required by &create_table.  =item Index_length
   
 =item column_order  The length of the index for the table (bytes)
   
 Reference to an array containing the order of columns in the table.  =item Data_free
   
 =item table_info  I have no idea what this is.
   
 Set to the results of &get_table_info.  =item Comment 
   
 =item row_insert_sth  The comment associated with the table.
   
   =item Rows
   
   The number of rows in the table.
   
   =item Auto_increment
   
   The value of the next auto_increment field.
   
   =item Create_options
   
   I have no idea.
   
   =item Col_order
   
   an array reference which holds the order of columns in the table.
   
   =item row_insert_sth 
   
 The statement handler for row inserts.  The statement handler for row inserts.
   
 =back  =back
   
   Col_order and row_insert_sth are kept internally by lonmysql and are not
   part of the usual MySQL table information.
   
 =cut  =cut
   
 ##################################################  ##################################################
Line 283  sub connect_to_db { Line 332  sub connect_to_db {
         }          }
         return undef;          return undef;
     }      }
     # The code below will let us switch to a different database.  
     # my $db_command = "USE $db;";  
     # my $sth = $dbh->prepare($db_command);  
     # $sth->execute();  
     # if ($sth->err) {  
     #     # Unable to use the database.  Interesting...  
     #     $dbh->disconnect;  
     #     return undef;  
     # }  
     $debugstring = "Successfully connected to loncapa database.";          $debugstring = "Successfully connected to loncapa database.";    
     return 1;      return 1;
 }  }
Line 334  sub disconnect_from_db { Line 374  sub disconnect_from_db {
   
 Input: table identifier  Input: table identifier
   
 Returns: the number of rows in the given table.  Returns: the number of rows in the given table, undef on error.
   
 =cut  =cut
   
 ###############################  ###############################
 sub number_of_rows {   sub number_of_rows { 
     my ($table_id) = @_;      my ($table_id) = @_;
     # Update the table information      return undef if (! defined(&connect_to_db()));
     my %Table_Info = %{&get_table_info($table_id)};      return undef if (! defined(&update_table_info($table_id)));
     # return the number of rows.      return $Tables{&translate_id($table_id)}->{'Rows'};
     if (defined(%Table_Info)) {  
         return $Table_Info{'Rows'};  
     }  
     return undef;  
 }  }
   
 ###############################  ###############################
Line 388  sub get_debug { Line 424  sub get_debug {
   
 =pod  =pod
   
 =item &get_table_info($table_id)  =item &update_table_info($table_id)
   
 Inputs: table id  Inputs: table id
   
 Returns: undef or a pointer to a hash of data about a table.  Returns: undef on error, 1 on success.
   
 &get_table_info returns all of the information it can about a table in the  &update_table_info updates the %Tables hash with current information about
 form of a hash.  Currently the fields in the hash are:  the given table.  
   
   The default MySQL table status fields are:
   
    Name             Type            Row_format     Name             Type            Row_format
    Max_data_length  Index_length    Data_free     Max_data_length  Index_length    Data_free
Line 403  form of a hash.  Currently the fields in Line 441  form of a hash.  Currently the fields in
    Avg_row_length   Data_length     Comment      Avg_row_length   Data_length     Comment 
    Rows             Auto_increment  Create_options     Rows             Auto_increment  Create_options
   
   Additionally, "Col_order" is updated as well.
   
 =cut  =cut
   
 ###############################  ###############################
 sub get_table_info {   sub update_table_info { 
     my ($table_id) = @_;      my ($table_id) = @_;
       return undef if (! defined(&connect_to_db()));
       my $table_status = &check_table($table_id);
       return undef if (! defined($table_status));
       if (! $table_status) {
           $errorstring = "table $table_id does not exist.";
           return undef;
       }
     my $tablename = &translate_id($table_id);      my $tablename = &translate_id($table_id);
     return undef if (! &check_table($table_id));      #
     my %tableinfo;      # Get MySQLs table status information.
       #
     my @tabledesc = qw/      my @tabledesc = qw/
         Name Type Row_format Rows Avg_row_length Data_length          Name Type Row_format Rows Avg_row_length Data_length
             Max_data_length Index_length Data_free Auto_increment               Max_data_length Index_length Data_free Auto_increment 
Line 419  sub get_table_info { Line 467  sub get_table_info {
     my $sth = $dbh->prepare($db_command);      my $sth = $dbh->prepare($db_command);
     $sth->execute();      $sth->execute();
     if ($sth->err) {      if ($sth->err) {
         # Unable to use the database.  Interesting...  
         $errorstring = "$dbh ATTEMPTED:\n".$db_command."\nRESULTING ERROR:\n".          $errorstring = "$dbh ATTEMPTED:\n".$db_command."\nRESULTING ERROR:\n".
             $sth->errstr;              $sth->errstr;
         $dbh->disconnect;          &disconnect_from_db();
         return undef;          return undef;
     }      }
     #      #
     my @info=$sth->fetchrow_array;      my @info=$sth->fetchrow_array;
     for (my $i=0;$i<= $#info ; $i++) {      for (my $i=0;$i<= $#info ; $i++) {
         $tableinfo{$tabledesc[$i]}= $info[$i];          $Tables{$tablename}->{$tabledesc[$i]}= $info[$i];
       }
       #
       # Determine the column order
       #
       $db_command = "DESCRIBE $tablename";
       my $sth = $dbh->prepare($db_command);
       $sth->execute();
       if ($sth->err) {
           $errorstring = "$dbh ATTEMPTED:\n".$db_command."\nRESULTING ERROR:\n".
               $sth->errstr;
           &disconnect_from_db();
           return undef;
       }
       my $aref=$sth->fetchall_arrayref;
       $Tables{$tablename}->{'Col_order'}=[]; # Clear values.
       # The values we want are the 'Field' entries, the first column.
       for (my $i=0;$i< @$aref ; $i++) {
           push @{$Tables{$tablename}->{'Col_order'}},$aref->[$i]->[0];
     }      }
     #      #
     $debugstring = "Retrieved table info for $tablename";      $debugstring = "Retrieved table info for $tablename";
     return \%tableinfo;      return 1;
 }  }
   
 ###############################  ###############################
Line 454  Input formats: Line 519  Input formats:
                 restrictions => 'NOT NULL' or empty,                  restrictions => 'NOT NULL' or empty,
                 primary_key  => 'yes' or empty,                  primary_key  => 'yes' or empty,
                 auto_inc     => 'yes' or empty,                  auto_inc     => 'yes' or empty,
                 target       => 'colB' (only if type eq 'FULLTEXT'),  
             }              }
             colB  => { .. }              colB  => { .. }
             colZ  => { .. }              colZ  => { .. }
Line 469  Returns: Line 533  Returns:
   
 ###############################  ###############################
 sub create_table {  sub create_table {
     return undef if (!&connect_to_db($dbh));      return undef if (!defined(&connect_to_db($dbh)));
     my ($table_des)=@_;      my ($table_des)=@_;
     #      #
     # Build request to create table      # Build request to create table
     ##################################      ##################################
     my @Columns;      my @Columns;
     my $col_des;      my $col_des;
     my $tableid = &get_new_table_id();      my $table_id = &get_new_table_id();
     my $tablename = &translate_id($tableid);      my $tablename = &translate_id($table_id);
     my $request = "CREATE TABLE IF NOT EXISTS ".$tablename." ";      my $request = "CREATE TABLE IF NOT EXISTS ".$tablename." ";
     foreach my $column (@{$table_des->{'column_order'}}) {      foreach my $column (@{$table_des->{'column_order'}}) {
         $col_des = '';          $col_des = '';
         my $coldata = $table_des->{'columns'}->{$column};          my $coldata = $table_des->{'columns'}->{$column};
         if (lc($coldata->{'type'}) eq 'fulltext') {          if (lc($coldata->{'type'}) =~ /(enum|set)/) { # 'enum' or 'set'
             $col_des.='FULLTEXT '.$column." (".$coldata->{'target'}.")";  
             next; # Skip to the continue block and store the column data  
         } elsif (lc($coldata->{'type'}) =~ /(enum|set)/) { # 'enum' or 'set'  
             $col_des.=$column." ".$coldata->{'type'}."('".              $col_des.=$column." ".$coldata->{'type'}."('".
                 join("', '",@{$coldata->{'values'}})."')";                  join("', '",@{$coldata->{'values'}})."')";
         } else {          } else {
Line 501  sub create_table { Line 562  sub create_table {
         if (exists($coldata->{'default'})) {          if (exists($coldata->{'default'})) {
             $col_des.=" DEFAULT '".$coldata->{'default'}."'";              $col_des.=" DEFAULT '".$coldata->{'default'}."'";
         }          }
         $col_des.=' AUTO_INCREMENT' if (exists($coldata->{'auto_inc'}));          $col_des.=' AUTO_INCREMENT' if (exists($coldata->{'auto_inc'}) &&
         $col_des.=' PRIMARY KEY'    if (exists($coldata->{'primary_key'}));                                          ($coldata->{'auto_inc'} eq 'yes'));
           $col_des.=' PRIMARY KEY'    if (exists($coldata->{'primary_key'}) &&
                                           ($coldata->{'primary_key'} eq 'yes'));
     } continue {      } continue {
         # skip blank items.          # skip blank items.
         push (@Columns,$col_des) if ($col_des ne '');          push (@Columns,$col_des) if ($col_des ne '');
     }      }
       if (exists($table_des->{'fulltext'})) {
           push (@Columns,'FULLTEXT ('.join(',',@{$table_des->{'fulltext'}}).')');
       }
     $request .= "(".join(", ",@Columns).") ";      $request .= "(".join(", ",@Columns).") ";
     unless($table_des->{'permanent'} eq 'yes') {      unless($table_des->{'permanent'} eq 'yes') {
         $request.="COMMENT = 'temporary' ";          $request.="COMMENT = 'temporary' ";
Line 517  sub create_table { Line 583  sub create_table {
     #############################################      #############################################
     my $count = $dbh->do($request);      my $count = $dbh->do($request);
     if (! defined($count)) {      if (! defined($count)) {
         $errorstring = "$dbh ATTEMPTED:\n".$request."\nRESULTING ERROR:\n".          $errorstring = "$dbh ATTEMPTED:\n".$request."\nRESULTING ERROR:\n";
         return undef;          return undef;
     }      }
     #      #
     # Set up the internal bookkeeping      # Set up the internal bookkeeping
     #############################################      #############################################
     delete($Tables{$tablename}) if (exists($Tables{$tablename}));      delete($Tables{$tablename}) if (exists($Tables{$tablename}));
     my @column_order_copy = @{$table_des->{'column_order'}};      return undef if (! defined(&update_table_info($table_id)));
     $Tables{$tablename} = {       $debugstring = "Created table $tablename at time ".time.
         columns      => $table_des->{'columns'},  
         column_order => $table_des->{'column_order'},  
         table_info   => &get_table_info($tableid),  
     };  
     $debugstring = "$dbh Created table $tablename at time ".time.  
         " with request\n$request";          " with request\n$request";
     return $tableid;      return $table_id;
 }  }
   
 ###############################  ###############################
Line 562  sub get_new_table_id { Line 623  sub get_new_table_id {
   
 =pod  =pod
   
 =item &execute_db_command  
   
 Currently unimplemented  
   
 =cut  
   
 ###############################  
 sub execute_db_command {  
     my ($tablename,$command) = @_;  
     return 1;  
 }  
   
 ###############################  
   
 =pod  
   
 =item &get_rows  =item &get_rows
   
 Inputs: $table_id,$condition  Inputs: $table_id,$condition
Line 593  greater than 0 being returned. Line 638  greater than 0 being returned.
 ###############################  ###############################
 sub get_rows {  sub get_rows {
     my ($table_id,$condition) = @_;      my ($table_id,$condition) = @_;
       return undef if (! defined(&connect_to_db()));
       my $table_status = &check_table($table_id);
       return undef if (! defined($table_status));
       if (! $table_status) {
           $errorstring = "table $table_id does not exist.";
           return undef;
       }
     my $tablename = &translate_id($table_id);      my $tablename = &translate_id($table_id);
     my $request = 'SELECT * FROM '.$tablename.' WHERE '.$condition;      my $request = 'SELECT * FROM '.$tablename.' WHERE '.$condition;
     my $sth=$dbh->prepare($request);      my $sth=$dbh->prepare($request);
Line 628  returns undef on error, 1 on success. Line 680  returns undef on error, 1 on success.
 ###############################  ###############################
 sub store_row {  sub store_row {
     my ($table_id,$rowdata) = @_;      my ($table_id,$rowdata) = @_;
       # 
       return undef if (! defined(&connect_to_db()));
       my $table_status = &check_table($table_id);
       return undef if (! defined($table_status));
       if (! $table_status) {
           $errorstring = "table $table_id does not exist.";
           return undef;
       }
       #
     my $tablename = &translate_id($table_id);      my $tablename = &translate_id($table_id);
     my $table = $Tables{$tablename};      #
     my $sth;      my $sth;
     if (exists($table->{'row_insert_sth'})) {      if (exists($Tables{$tablename}->{'row_insert_sth'})) {
         $sth = $table->{'row_insert_sth'};          $sth = $Tables{$tablename}->{'row_insert_sth'};
     } else {      } else {
         # We need to build a statement handler          # Build the insert statement handler
           return undef if (! defined(&update_table_info($table_id)));
         my $insert_request = 'INSERT INTO '.$tablename.' VALUES(';          my $insert_request = 'INSERT INTO '.$tablename.' VALUES(';
         foreach (@{$table->{'column_order'}}) {          foreach (@{$Tables{$tablename}->{'Col_order'}}) {
             # Skip the 'fulltext' columns.  
             next if (lc($table->{'columns'}->{$_}->{'type'}) eq 'fulltext');  
             $insert_request.="?,";              $insert_request.="?,";
         }          }
         chop $insert_request;          chop $insert_request;
         $insert_request.=")";          $insert_request.=")";
         $sth=$dbh->prepare($insert_request);          $sth=$dbh->prepare($insert_request);
           $Tables{$tablename}->{'row_insert_sth'}=$sth;
     }      }
     my @Parameters;       my @Parameters; 
     if (ref($rowdata) eq 'ARRAY') {      if (ref($rowdata) eq 'ARRAY') {
         @Parameters = @$rowdata;          @Parameters = @$rowdata;
     } elsif (ref($rowdata) eq 'HASH') {      } elsif (ref($rowdata) eq 'HASH') {
         foreach (@{$table->{'column_order'}}) {          foreach (@{$Tables{$tablename}->{'Col_order'}}) {
             # Is this appropriate?  Am I being presumptious? ACK!!!!!  
             next if (lc($table->{'columns'}->{$_}->{'type'}) eq 'fulltext');  
             push(@Parameters,&Apache::lonnet::escape($rowdata->{$_}));              push(@Parameters,&Apache::lonnet::escape($rowdata->{$_}));
         }          }
     }       } 
Line 678  Returns undef on error. Line 737  Returns undef on error.
   
 ###########################################  ###########################################
 sub tables_in_db {  sub tables_in_db {
     return undef if (! &connect_to_db()); # bail out if we cannot connect      return undef if (!defined(&connect_to_db()));
     my $sth=$dbh->prepare('SHOW TABLES;');      my $sth=$dbh->prepare('SHOW TABLES;');
     $sth->execute();      $sth->execute();
     if ($sth->err) {      if ($sth->err) {
         $errorstring = "$dbh ATTEMPTED:\n".'SHOW TABLES'."\nRESULTING ERROR:\n".          $errorstring = "$dbh ATTEMPTED:\n".'SHOW TABLES'.
             $sth->errstr;              "\nRESULTING ERROR:\n".$sth->errstr;
         return undef;          return undef;
     }      }
     my $aref = $sth->fetchall_arrayref;      my $aref = $sth->fetchall_arrayref;
Line 732  undef (error). Line 791  undef (error).
 ###########################################  ###########################################
 sub check_table {  sub check_table {
     my $table_id = shift;      my $table_id = shift;
       return undef if (!defined(&connect_to_db()));
       #
     $table_id = &translate_id($table_id);      $table_id = &translate_id($table_id);
     return undef if (! &connect_to_db());  
     my @Table_list = &tables_in_db();      my @Table_list = &tables_in_db();
     my $result = 0;      my $result = 0;
     foreach (@Table_list) {      foreach (@Table_list) {
Line 751  sub check_table { Line 811  sub check_table {
 1;  1;
   
 __END__;  __END__;
   

Removed from v.1.2  
changed lines
  Added in v.1.3


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