version 1.9, 2003/03/13 19:08:52
|
version 1.30, 2005/04/11 15:33:46
|
Line 31 package Apache::lonmysql;
|
Line 31 package Apache::lonmysql;
|
|
|
use strict; |
use strict; |
use DBI; |
use DBI; |
use Apache::lonnet(); |
use POSIX qw(strftime mktime); |
|
use Apache::lonnet; |
|
|
|
my $mysqluser; |
|
my $mysqlpassword; |
|
my $mysqldatabase; |
|
|
|
sub set_mysql_user_and_password { |
|
# If we are running under Apache and LONCAPA, use the LON-CAPA |
|
# user and password. Otherwise...? ? ? ? |
|
my ($input_mysqluser,$input_mysqlpassword,$input_mysqldatabase) = @_; |
|
if (! defined($mysqldatabase)) { |
|
$mysqldatabase = 'loncapa'; |
|
} |
|
if (defined($input_mysqldatabase)) { |
|
$mysqldatabase = $input_mysqldatabase; |
|
} |
|
if (! defined($mysqluser) || ! defined($mysqlpassword)) { |
|
if (! eval 'require Apache::lonnet();') { |
|
$mysqluser = 'www'; |
|
$mysqlpassword = $Apache::lonnet::perlvar{'lonSqlAccess'}; |
|
} else { |
|
$mysqluser = ''; |
|
$mysqlpassword = ''; |
|
} |
|
} |
|
if (defined($input_mysqluser)) { |
|
$mysqluser = $input_mysqluser; |
|
} |
|
if (defined($input_mysqlpassword)) { |
|
$mysqlpassword = $input_mysqlpassword; |
|
} |
|
} |
|
|
###################################################################### |
###################################################################### |
###################################################################### |
###################################################################### |
Line 58 Each table has a numeric ID that is a pa
|
Line 90 Each table has a numeric ID that is a pa
|
The table id is returned by &create_table. |
The table id is returned by &create_table. |
If you lose the table id, it is lost forever. |
If you lose the table id, it is lost forever. |
The table names in MySQL correspond to |
The table names in MySQL correspond to |
$ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'.$table_id. If the table id |
$env{'user.name'}.'_'.$env{'user.domain'}.'_'.$table_id. If the table id |
is non-numeric, it is assumed to be the full name of a table. If you pass |
is non-numeric, it is assumed to be the full name of a table. If you pass |
the table id in a form, you MUST ensure that what you send to lonmysql is |
the table id in a form, you MUST ensure that what you send to lonmysql is |
numeric, otherwise you are opening up all the tables in the MySQL database. |
numeric, otherwise you are opening up all the tables in the MySQL database. |
Line 328 connection is established.
|
Line 360 connection is established.
|
############################### |
############################### |
sub connect_to_db { |
sub connect_to_db { |
return 1 if ($dbh); |
return 1 if ($dbh); |
if (! ($dbh = DBI->connect("DBI:mysql:loncapa","www", |
if (! defined($mysqluser) || ! defined($mysqlpassword)) { |
$Apache::lonnet::perlvar{'lonSqlAccess'}, |
&set_mysql_user_and_password(); |
|
} |
|
if (! ($dbh = DBI->connect("DBI:mysql:$mysqldatabase",$mysqluser,$mysqlpassword, |
{ RaiseError=>0,PrintError=>0}))) { |
{ RaiseError=>0,PrintError=>0}))) { |
$debugstring = "Unable to connect to loncapa database."; |
$debugstring = "Unable to connect to loncapa database."; |
if (! defined($dbh)) { |
if (! defined($dbh)) { |
Line 348 sub connect_to_db {
|
Line 382 sub connect_to_db {
|
|
|
=pod |
=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() |
=item &disconnect_from_db() |
|
|
Inputs: none. |
Inputs: none. |
Line 396 sub number_of_rows {
|
Line 460 sub number_of_rows {
|
return undef if (! defined(&update_table_info($table_id))); |
return undef if (! defined(&update_table_info($table_id))); |
return $Tables{&translate_id($table_id)}->{'Rows'}; |
return $Tables{&translate_id($table_id)}->{'Rows'}; |
} |
} |
|
############################### |
|
|
|
=pod |
|
|
|
=item &get_dbh() |
|
|
|
Input: nothing |
|
|
|
Returns: the database handler, or undef on error. |
|
|
|
This routine allows the programmer to gain access to the database handler. |
|
Be careful. |
|
|
|
=cut |
|
|
|
############################### |
|
sub get_dbh { |
|
return undef if (! defined(&connect_to_db())); |
|
&Apache::lonnet::logthis("reconnect set to ".$dbh->{mysql_auto_reconnect}); |
|
return $dbh; |
|
} |
|
|
############################### |
############################### |
|
|
Line 486 sub update_table_info {
|
Line 571 sub update_table_info {
|
# |
# |
my @info=$sth->fetchrow_array; |
my @info=$sth->fetchrow_array; |
for (my $i=0;$i<= $#info ; $i++) { |
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 |
# Determine the column order |
Line 515 sub update_table_info {
|
Line 605 sub update_table_info {
|
|
|
=pod |
=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() |
=item &create_table() |
|
|
Inputs: |
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; |
|
} |
|
|
|
############################### |
|
|
|
=pod |
|
|
|
=item build_table_creation_request |
|
|
Input formats: |
Input: table description |
|
|
table description = { |
table description = { |
permanent => 'yes' or 'no', |
permanent => 'yes' or 'no', |
Line 539 Input formats:
|
Line 705 Input formats:
|
}, |
}, |
], |
], |
'PRIMARY KEY' => (index_col_name,...), |
'PRIMARY KEY' => (index_col_name,...), |
KEY => { name => 'idx_name', |
KEY => [{ name => 'idx_name', |
columns => (col1,col2,..),}, |
columns => (col1,col2,..),},], |
INDEX => { name => 'idx_name', |
INDEX => [{ name => 'idx_name', |
columns => (col1,col2,..),}, |
columns => (col1,col2,..),},], |
UNIQUE => { index => 'yes', |
UNIQUE => [{ index => 'yes', |
name => 'idx_name', |
name => 'idx_name', |
columns => (col1,col2,..),}, |
columns => (col1,col2,..),},], |
FULLTEXT => { index => 'yes', |
FULLTEXT => [{ index => 'yes', |
name => 'idx_name', |
name => 'idx_name', |
columns => (col1,col2,..),}, |
columns => (col1,col2,..),},], |
|
|
} |
} |
|
|
Returns: |
Returns: scalar string containing mysql commands to create the table |
undef on error, table id on success. |
|
|
|
=cut |
=cut |
|
|
############################### |
############################### |
sub create_table { |
sub build_table_creation_request { |
return undef if (!defined(&connect_to_db($dbh))); |
|
my ($table_des)=@_; |
my ($table_des)=@_; |
# |
# |
# Build request to create table |
# Build request to create table |
Line 606 sub create_table {
|
Line 770 sub create_table {
|
push (@Columns,'PRIMARY KEY ('.join(',',@{$table_des->{'PRIMARY KEY'}}) |
push (@Columns,'PRIMARY KEY ('.join(',',@{$table_des->{'PRIMARY KEY'}}) |
.')'); |
.')'); |
} |
} |
foreach ('KEY','INDEX') { |
# |
if (exists($table_des->{$_})) { |
foreach my $indextype ('KEY','INDEX') { |
my $text = $_.' '; |
next if (!exists($table_des->{$indextype})); |
if (exists($table_des->{$_}->{'name'})) { |
foreach my $indexdescription (@{$table_des->{$indextype}}) { |
$text .=$table_des->{$_}->{'name'}; |
my $text = $indextype.' '; |
|
if (exists($indexdescription->{'name'})) { |
|
$text .=$indexdescription->{'name'}; |
} |
} |
$text .= ' ('.join(',',@{$table_des->{$_}->{'columns'}}).')'; |
$text .= ' ('.join(',',@{$indexdescription->{'columns'}}).')'; |
push (@Columns,$text); |
push (@Columns,$text); |
} |
} |
} |
} |
foreach ('UNIQUE','FULLTEXT') { |
# |
if (exists($table_des->{$_})) { |
foreach my $indextype ('UNIQUE','FULLTEXT') { |
my $text = $_.' '; |
next if (! exists($table_des->{$indextype})); |
if (exists($table_des->{$_}->{'index'}) && |
foreach my $indexdescription (@{$table_des->{$indextype}}) { |
$table_des->{$_}->{'index'} eq 'yes') { |
my $text = $indextype.' '; |
|
if (exists($indexdescription->{'index'}) && |
|
$indexdescription->{'index'} eq 'yes') { |
$text .= 'INDEX '; |
$text .= 'INDEX '; |
} |
} |
if (exists($table_des->{$_}->{'name'})) { |
if (exists($indexdescription->{'name'})) { |
$text .=$table_des->{$_}->{'name'}; |
$text .=$indexdescription->{'name'}; |
} |
} |
$text .= ' ('.join(',',@{$table_des->{$_}->{'columns'}}).')'; |
$text .= ' ('.join(',',@{$indexdescription->{'columns'}}).')'; |
push (@Columns,$text); |
push (@Columns,$text); |
} |
} |
} |
} |
|
# |
$request .= "(".join(", ",@Columns).") "; |
$request .= "(".join(", ",@Columns).") "; |
unless($table_des->{'permanent'} eq 'yes') { |
unless($table_des->{'permanent'} eq 'yes') { |
$request.="COMMENT = 'temporary' "; |
$request.="COMMENT = 'temporary' "; |
} |
} |
$request .= "TYPE=MYISAM"; |
$request .= "TYPE=MYISAM"; |
# |
return $request,$table_id; |
# 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; |
|
} |
} |
|
|
############################### |
############################### |
Line 668 sub get_new_table_id {
|
Line 822 sub get_new_table_id {
|
my $newid = 0; |
my $newid = 0; |
my @tables = &tables_in_db(); |
my @tables = &tables_in_db(); |
foreach (@tables) { |
foreach (@tables) { |
if (/^$ENV{'user.name'}_$ENV{'user.domain'}_(\d+)$/) { |
if (/^$env{'user.name'}_$env{'user.domain'}_(\d+)$/) { |
$newid = $1 if ($1 > $newid); |
$newid = $1 if ($1 > $newid); |
} |
} |
} |
} |
Line 781 sub store_row {
|
Line 935 sub store_row {
|
return 1; |
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 |
=pod |
Line 858 sub tables_in_db {
|
Line 1064 sub tables_in_db {
|
return undef if (!defined(&connect_to_db())); |
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) { |
$sth->execute(); |
$errorstring = "$dbh ATTEMPTED:\n".'SHOW TABLES'. |
my $aref = $sth->fetchall_arrayref; |
|
if ($sth->err()) { |
|
$errorstring = |
|
"$dbh ATTEMPTED:\n".'fetchall_arrayref after SHOW TABLES'. |
"\nRESULTING ERROR:\n".$sth->errstr; |
"\nRESULTING ERROR:\n".$sth->errstr; |
return undef; |
return undef; |
} |
} |
my $aref = $sth->fetchall_arrayref; |
my @table_list; |
my @table_list=(); |
|
foreach (@$aref) { |
foreach (@$aref) { |
push @table_list,$_->[0]; |
push(@table_list,$_->[0]); |
} |
} |
$debugstring = "Got list of tables in DB: @table_list"; |
$debugstring = "Got list of tables in DB: ".join(',',@table_list); |
return @table_list; |
return(@table_list); |
} |
} |
|
|
########################################### |
########################################### |
Line 892 sub translate_id {
|
Line 1100 sub translate_id {
|
# id should be a digit. If it is not a digit we assume the given id |
# id should be a digit. If it is not a digit we assume the given id |
# is complete and does not need to be translated. |
# is complete and does not need to be translated. |
return $id if ($id =~ /\D/); |
return $id if ($id =~ /\D/); |
return $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'.$id; |
return $env{'user.name'}.'_'.$env{'user.domain'}.'_'.$id; |
} |
} |
|
|
########################################### |
########################################### |
Line 948 sub remove_from_table {
|
Line 1156 sub remove_from_table {
|
return undef if (!defined(&connect_to_db())); |
return undef if (!defined(&connect_to_db())); |
# |
# |
$table_id = &translate_id($table_id); |
$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); |
" LIKE BINARY ".$dbh->quote($value); |
my $sth = $dbh->prepare($command); |
my $sth = $dbh->prepare($command); |
$sth->execute(); |
unless ($sth->execute()) { |
if ($sth->err) { |
|
$errorstring = "ERROR on execution of ".$command."\n".$sth->errstr; |
$errorstring = "ERROR on execution of ".$command."\n".$sth->errstr; |
return undef; |
return undef; |
} |
} |
|
$debugstring = $command; |
my $rows = $sth->rows; |
my $rows = $sth->rows; |
return $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+[eE]\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; |
1; |
|
|