--- loncom/interface/lonmysql.pm 2003/03/14 15:37:02 1.10 +++ loncom/interface/lonmysql.pm 2005/02/09 21:21:08 1.26 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # MySQL utility functions # -# $Id: lonmysql.pm,v 1.10 2003/03/14 15:37:02 matthew Exp $ +# $Id: lonmysql.pm,v 1.26 2005/02/09 21:21:08 matthew Exp $ # # Copyright Michigan State University Board of Trustees # @@ -31,7 +31,25 @@ package Apache::lonmysql; use strict; use DBI; -use Apache::lonnet(); +use POSIX qw(strftime mktime); + +my $mysqluser; +my $mysqlpassword; + +sub set_mysql_user_and_password { + # If we are running under Apache and LONCAPA, use the LON-CAPA + # user and password. Otherwise...? ? ? ? + ($mysqluser,$mysqlpassword) = @_; + if (! defined($mysqluser) || ! defined($mysqlpassword)) { + if (! eval 'require Apache::lonnet();') { + $mysqluser = 'www'; + $mysqlpassword = $Apache::lonnet::perlvar{'lonSqlAccess'}; + } else { + $mysqluser = ''; + $mysqlpassword = ''; + } + } +} ###################################################################### ###################################################################### @@ -328,8 +346,10 @@ connection is established. ############################### sub connect_to_db { return 1 if ($dbh); - if (! ($dbh = DBI->connect("DBI:mysql:loncapa","www", - $Apache::lonnet::perlvar{'lonSqlAccess'}, + if (! defined($mysqluser) || ! defined($mysqlpassword)) { + &set_mysql_user_and_password(); + } + if (! ($dbh = DBI->connect("DBI:mysql:loncapa",$mysqluser,$mysqlpassword, { RaiseError=>0,PrintError=>0}))) { $debugstring = "Unable to connect to loncapa database."; if (! defined($dbh)) { @@ -348,6 +368,36 @@ sub connect_to_db { =pod +=item &verify_sql_connection() + +Inputs: none. + +Returns: 0 (failure) or 1 (success) + +Checks to make sure the database can be connected to. It does not +initialize anything in the lonmysql package. + +=cut + +############################### +sub verify_sql_connection { + if (! defined($mysqluser) || ! defined($mysqlpassword)) { + &set_mysql_user_and_password(); + } + my $connection; + if (! ($connection = DBI->connect("DBI:mysql:loncapa", + $mysqluser,$mysqlpassword, + { RaiseError=>0,PrintError=>0}))) { + return 0; + } + undef($connection); + return 1; +} + +############################### + +=pod + =item &disconnect_from_db() Inputs: none. @@ -506,7 +556,12 @@ sub update_table_info { # my @info=$sth->fetchrow_array; for (my $i=0;$i<= $#info ; $i++) { - $Tables{$tablename}->{$tabledesc[$i]}= $info[$i]; + if ($tabledesc[$i] !~ /^(Create_|Update_|Check_)time$/) { + $Tables{$tablename}->{$tabledesc[$i]}= + &unsqltime($info[$i]); + } else { + $Tables{$tablename}->{$tabledesc[$i]}= $info[$i]; + } } # # Determine the column order @@ -535,12 +590,88 @@ sub update_table_info { =pod +=item &table_information() + +Inputs: table id + +Returns: hash with the table status + +=cut + +############################### +sub table_information { + my $table_id=shift; + if (&update_table_info($table_id)) { + return %{$Tables{$table_id}}; + } else { + return (); + } +} + +############################### + +=pod + +=item &col_order() + +Inputs: table id + +Returns: array with column order + +=cut + +############################### +sub col_order { + my $table_id=shift; + if (&update_table_info($table_id)) { + return @{$Tables{$table_id}->{'Col_order'}}; + } else { + return (); + } +} + +############################### + +=pod + =item &create_table() Inputs: - table description + table description, see &build_table_creation_request +Returns: + undef on error, table id on success. + +=cut + +############################### +sub create_table { + return undef if (!defined(&connect_to_db($dbh))); + my ($table_des)=@_; + my ($request,$table_id) = &build_table_creation_request($table_des); + # + # Execute the request to create the table + ############################################# + my $count = $dbh->do($request); + if (! defined($count)) { + $errorstring = "$dbh ATTEMPTED:\n".$request."\nRESULTING ERROR:\n". + $dbh->errstr(); + return undef; + } + my $tablename = &translate_id($table_id); + delete($Tables{$tablename}) if (exists($Tables{$tablename})); + return undef if (! defined(&update_table_info($table_id))); + $debugstring = "Created table $tablename at time ".time. + " with request\n$request"; + return $table_id; +} -Input formats: +############################### + +=pod + +=item build_table_creation_request + +Input: table description table description = { permanent => 'yes' or 'no', @@ -559,27 +690,25 @@ Input formats: }, ], 'PRIMARY KEY' => (index_col_name,...), - KEY => { name => 'idx_name', - columns => (col1,col2,..),}, - INDEX => { name => 'idx_name', - columns => (col1,col2,..),}, - UNIQUE => { index => 'yes', + KEY => [{ name => 'idx_name', + columns => (col1,col2,..),},], + INDEX => [{ name => 'idx_name', + columns => (col1,col2,..),},], + UNIQUE => [{ index => 'yes', name => 'idx_name', - columns => (col1,col2,..),}, - FULLTEXT => { index => 'yes', + columns => (col1,col2,..),},], + FULLTEXT => [{ index => 'yes', name => 'idx_name', - columns => (col1,col2,..),}, + columns => (col1,col2,..),},], } -Returns: - undef on error, table id on success. +Returns: scalar string containing mysql commands to create the table =cut ############################### -sub create_table { - return undef if (!defined(&connect_to_db($dbh))); +sub build_table_creation_request { my ($table_des)=@_; # # Build request to create table @@ -626,51 +755,41 @@ sub create_table { push (@Columns,'PRIMARY KEY ('.join(',',@{$table_des->{'PRIMARY KEY'}}) .')'); } - foreach ('KEY','INDEX') { - if (exists($table_des->{$_})) { - my $text = $_.' '; - if (exists($table_des->{$_}->{'name'})) { - $text .=$table_des->{$_}->{'name'}; + # + foreach my $indextype ('KEY','INDEX') { + next if (!exists($table_des->{$indextype})); + foreach my $indexdescription (@{$table_des->{$indextype}}) { + my $text = $indextype.' '; + if (exists($indexdescription->{'name'})) { + $text .=$indexdescription->{'name'}; } - $text .= ' ('.join(',',@{$table_des->{$_}->{'columns'}}).')'; + $text .= ' ('.join(',',@{$indexdescription->{'columns'}}).')'; push (@Columns,$text); } } - foreach ('UNIQUE','FULLTEXT') { - if (exists($table_des->{$_})) { - my $text = $_.' '; - if (exists($table_des->{$_}->{'index'}) && - $table_des->{$_}->{'index'} eq 'yes') { + # + foreach my $indextype ('UNIQUE','FULLTEXT') { + next if (! exists($table_des->{$indextype})); + foreach my $indexdescription (@{$table_des->{$indextype}}) { + my $text = $indextype.' '; + if (exists($indexdescription->{'index'}) && + $indexdescription->{'index'} eq 'yes') { $text .= 'INDEX '; } - if (exists($table_des->{$_}->{'name'})) { - $text .=$table_des->{$_}->{'name'}; + if (exists($indexdescription->{'name'})) { + $text .=$indexdescription->{'name'}; } - $text .= ' ('.join(',',@{$table_des->{$_}->{'columns'}}).')'; + $text .= ' ('.join(',',@{$indexdescription->{'columns'}}).')'; push (@Columns,$text); } } + # $request .= "(".join(", ",@Columns).") "; unless($table_des->{'permanent'} eq 'yes') { $request.="COMMENT = 'temporary' "; } $request .= "TYPE=MYISAM"; - # - # Execute the request to create the table - ############################################# - my $count = $dbh->do($request); - if (! defined($count)) { - $errorstring = "$dbh ATTEMPTED:\n".$request."\nRESULTING ERROR:\n"; - return undef; - } - # - # Set up the internal bookkeeping - ############################################# - delete($Tables{$tablename}) if (exists($Tables{$tablename})); - return undef if (! defined(&update_table_info($table_id))); - $debugstring = "Created table $tablename at time ".time. - " with request\n$request"; - return $table_id; + return $request,$table_id; } ############################### @@ -801,6 +920,58 @@ sub store_row { return 1; } + +############################### + +=pod + +=item &bulk_store_rows() + +Inputs: table id, [columns],[[row data1].[row data2],...] + +returns undef on error, 1 on success. + +=cut + +############################### +sub bulk_store_rows { + my ($table_id,$columns,$rows) = @_; + # + return undef if (! defined(&connect_to_db())); + my $dbh = &get_dbh(); + return undef if (! defined($dbh)); + 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 $request = 'INSERT IGNORE INTO '.$tablename.' '; + if (defined($columns) && ref($columns) eq 'ARRAY') { + $request .= join(',',@$columns).' '; + } + if (! defined($rows) || ref($rows) ne 'ARRAY') { + $errorstring = "no input rows given."; + return undef; + } + $request .= 'VALUES '; + foreach my $row (@$rows) { + # avoid doing row stuff here... + $request .= '('.join(',',@$row).'),'; + } + $request =~ s/,$//; + $dbh->do($request); + if ($dbh->err) { + $errorstring = 'Attempted '.$/.$request.$/.'Got error '.$dbh->errstr(); + return undef; + } + return 1; +} + + ############################### =pod @@ -878,18 +1049,20 @@ sub tables_in_db { return undef if (!defined(&connect_to_db())); my $sth=$dbh->prepare('SHOW TABLES'); $sth->execute(); - if ($sth->err) { - $errorstring = "$dbh ATTEMPTED:\n".'SHOW TABLES'. + $sth->execute(); + my $aref = $sth->fetchall_arrayref; + if ($sth->err()) { + $errorstring = + "$dbh ATTEMPTED:\n".'fetchall_arrayref after SHOW TABLES'. "\nRESULTING ERROR:\n".$sth->errstr; return undef; } - my $aref = $sth->fetchall_arrayref; - my @table_list=(); + my @table_list; foreach (@$aref) { - push @table_list,$_->[0]; + push(@table_list,$_->[0]); } - $debugstring = "Got list of tables in DB: @table_list"; - return @table_list; + $debugstring = "Got list of tables in DB: ".join(',',@table_list); + return(@table_list); } ########################################### @@ -968,18 +1141,94 @@ sub remove_from_table { return undef if (!defined(&connect_to_db())); # $table_id = &translate_id($table_id); - my $command = 'DELETE FROM '.$table_id.' WHERE '.$dbh->quote($column). + my $command = 'DELETE FROM '.$table_id.' WHERE '.$column. " LIKE BINARY ".$dbh->quote($value); my $sth = $dbh->prepare($command); - $sth->execute(); - if ($sth->err) { + unless ($sth->execute()) { $errorstring = "ERROR on execution of ".$command."\n".$sth->errstr; return undef; } + $debugstring = $command; my $rows = $sth->rows; return $rows; } +########################################### + +=pod + +=item drop_table($table_id) + +Issues a 'drop table if exists' command + +=cut + +########################################### + +sub drop_table { + my ($table_id) = @_; + return undef if (!defined(&connect_to_db())); + # + $table_id = &translate_id($table_id); + my $command = 'DROP TABLE IF EXISTS '.$table_id; + my $sth = $dbh->prepare($command); + $sth->execute(); + if ($sth->err) { + $errorstring = "ERROR on execution of ".$command."\n".$sth->errstr; + return undef; + } + $debugstring = $command; + delete($Tables{$table_id}); # remove any knowledge of the table + return 1; # if we got here there was no error, so return a 'true' value +} + +########################################## + +=pod + +=item fix_table_name + +Fixes a table name so that it will work with MySQL. + +=cut + +########################################## +sub fix_table_name { + my ($name) = @_; + $name =~ s/^(\d+e\d+)/_$1/; + return $name; +} + + +# ---------------------------- convert 'time' format into a datetime sql format +sub sqltime { + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = + localtime(&unsqltime($_[0])); + $mon++; $year+=1900; + return "$year-$mon-$mday $hour:$min:$sec"; +} + +sub maketime { + my %th=@_; + return POSIX::mktime(($th{'seconds'},$th{'minutes'},$th{'hours'}, + $th{'day'},$th{'month'}-1, + $th{'year'}-1900,0,0,$th{'dlsav'})); +} + + +######################################### +# +# Retro-fixing of un-backward-compatible time format + +sub unsqltime { + my $timestamp=shift; + if ($timestamp=~/^(\d+)\-(\d+)\-(\d+)\s+(\d+)\:(\d+)\:(\d+)$/) { + $timestamp=&maketime('year'=>$1,'month'=>$2,'day'=>$3, + 'hours'=>$4,'minutes'=>$5,'seconds'=>$6); + } + return $timestamp; +} + 1; 500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.