package GT::Session::TempTable; # =============================================================== # Pragmas use strict; use vars qw| $ATTRIBS @ISA $ERRORS |; # Internal nodules use GT::Base; use GT::SQL; use GT::MD5 qw| md5_hex |; # Global variable init @ISA = qw| GT::Base |; $ATTRIBS = { id => undef, tb => undef, def_path => '', db => undef, set_name => 'Set_Sessions', create_session => undef, delete_session => undef, seconds => 60*60, sid => '' }; $ERRORS = { 'NODB' => "No GT::SQL object, need to set 'db' or 'def_path'", 'NOCS' => "No session creation hook specified", 'CSNOTCODE' => "Session creation hook is not a coderef", 'NOSID' => "No session ID", 'BADDATA' => "Invalid data in session: '%s'. Reason: '%s'", 'CLASSFUNC' => "This is a class function only.", 'INVALIDSESSION'=> "Invalid session id: '%s'.", 'BADARGS' => "Invalid arguments: %s", }; sub install { #------------------------------------------------------------------------------- # creates the controller table # my $self = shift; my $DB = $self->_db(); my $c = $DB->creator( $self->{set_name} ); $c->cols( ID => { pos => 1, type => 'INT', not_null => 1, unsigned => 1, regex => '^d+$' }, SessID => { pos => 2, type => 'CHAR', size => 100, not_null => 1 }, SessTable => { pos => 3, type => 'CHAR', size => 100, not_null => 1 }, Timestmp => { pos => 4, type => 'TIMESTAMP', time_check => 1 } ); $c->pk('ID'); $c->ai('ID'); $c->create('force'); $c->set_defaults(); $c->save_schema(); } sub uninstall { #------------------------------------------------------------------------------- # drops the controller table along with all the # my $self = shift; my $DB = $self->_db() or return; my $err = 1; # drop all the associated temp tables..., eval { my $tb = $DB->table( $self->{set_name} ); my $sth = $tb->select( [ 'SessTable' ] ); while ( my $aref = $sth->fetchrow_arrayref() ) { my $table_name = $aref->[0]; eval { my $e = $DB->editor( $table_name ); $e->drop_table("remove") or die "Can't drop table"; }; $@ and $err = undef; } # now drop the master control table my $e = $DB->editor( $self->{set_name}); $e->drop_table("remove") or die "Can't drop table"; }; return $@ ? undef : 1; } sub new_set { #------------------------------------------------------------------------------- # creates a new temp table # my $self = shift; my $create_session = ( ref $_[0] eq 'CODE' ? shift : $self->{create_session} ) or return $self->error( 'NOCS', 'WARN' ); my $sid = $self->{id} or return $self->error( 'NOSID', 'WARN' ); my $DB = $self->_db(); my $Session = $DB->table( $self->{set_name} ); # create a new sesson my $table_name = generate_session_id(); my $newid = $Session->add({ SessTable => $table_name, SessID => $sid }) or return; # create the new table, extra parameters are passed into the create_session sub procedure if ( my $result = &{$create_session}( $DB, $table_name, $newid, @_ ) ) { my $tbl = $DB->table( $table_name ); return wantarray ? ( $tbl, $newid ) : $tbl; } else { $Session->delete($newid); return; } } sub get_set { #------------------------------------------------------------------------------- # returns a table reference to the sethandle # my $self = shift; my $set_id = shift or return; my $sid = $self->{id} or return $self->error( 'NOSID', 'WARN' ); my $DB = $self->_db(); my $Session = $DB->table( $self->{set_name} ) or return; my $sth = $Session->select({ ID => $set_id, SessID => $sid }) or return undef; my $href = $sth->fetchrow_hashref() or return undef; $href->{Timestmp} = \'NOW()'; $Session->update( $href ); if ( my $table_name = $href->{'SessTable'} ) { my $tbl = $DB->table( $table_name ); return $tbl; } else { return; } } sub list_sets { #------------------------------------------------------------------------------- # returns a hashref of ID => tablenames, of tables that the current session ID owns # my $self = shift; my $DB = $self->_db(); my $sid = $self->{id} or return $self->error( 'NOSID', 'WARN' ); my $Session = $DB->table( $self->{set_name} ) or return; my $sth = $Session->select({ SessID => $sid }, [ 'ID', 'SessTable' ]); my $list = {}; while ( my $aref = $sth->fetchrow_arrayref() ) { my ( $id, $sesstable ) = @{$aref}; $list->{$id} = $sesstable; } return $list; } sub delete { #------------------------------------------------------------------------------- # deletes all sets associated with the session # my $self = shift; my $DB = $self->_db(); my $Session = $DB->table( $self->{set_name} ) or return; my $sid = ( shift || $self->{id} ) or return $self->error( 'NOSID', 'WARN' ); my $sth = $Session->select({ SessID => $sid },['SessTable']); # delete all created temp tables while ( my $aref = $sth->fetchrow_arrayref() ) { my $tbl_name = $aref->[0]; eval { my $e = $DB->editor($tbl_name); $e->drop_table( "remove" ); } } $Session->delete({ SessID => $sid }); # cheap workaround shift or $self->GT::Session::SQL::delete(); } sub delete_set { #------------------------------------------------------------------------------- # deletes a single set # my $self = shift; my $set_id = shift; my $DB = $self->_db(); my $Session = $DB->table( $self->{set_name} ) or return; my $sid = $self->{id} or return $self->error( 'NOSID', 'WARN' ); my $sth = $Session->select( { ID => $set_id, SessID => $sid }, [ 'SessTable' ] ) or return; my $aref = $sth->fetchrow_arrayref() or return; if ($aref->[0]) { my $e = $DB->editor($aref->[0]); $e->drop_table(); $Session->delete( { ID => $set_id } ); } } sub cleanup { #------------------------------------------------------------------------------- my $self = shift; my $seconds = shift || $self->{seconds}; if ($seconds == 0) { $self->debug ("Cleanup not erasing anything, seconds set to 0.") if ($self->{_debug}); return; } my $DB = $self->_db() or return; my $tb = $DB->table( $self->{set_name} ); defined $seconds or ($seconds = 3600); my $new_sec = time - $seconds; my @time = localtime ($new_sec); my $date_str = sprintf ("%4d-%02d-%02d %02d:%02d:%02d", $time[5] + 1900, $time[4] + 1, $time[3], $time[2], $time[1], $time[0]); my $sth = $tb->select( GT::SQL::Condition->new('Timestmp', '<', $date_str), [ 'SessID' ] ) or return $self->error ($GT::SQL::error); while ( my $aref = $sth->fetchrow_arrayref() ) { $self->delete( $aref->[0], 1 ); } $tb->delete (GT::SQL::Condition->new ('Timestmp', '<', $date_str)) or return $self->error ($GT::SQL::error); return 1; } sub _db { #------------------------------------------------------------------------------- # returns a database handle # my $self = shift; if ( my $db = $self->{'db'} ) { return $db; } elsif ( my $def_path = $self->{'def_path'} ) { $db = GT::SQL->new( $def_path ); return $db; } else { $self->error( 'NODB', 'FATAL' ); } } sub generate_session_id { # --------------------------------------------------------------- # Generates a session id. # return md5_hex( time . $$ . rand (16000) ); } 1; __END__ =head1 NAME GT::Session::TempTable - A session management module, subclassing GT::Session::SQL providing temp table support =head1 SYNOPSIS Create a session: my $session = new GT::Session::TempTable({ db => GT::SQL->new( '/path/to/defs' ), def_path => '/path/to/defs', create_session => \&create_table_sub }); Create temp table controller table. (do once before using this module) $session->initial_create(); Create a new temp table: my ( $GT_SQL_Table_ref, $tmp_id ) = $session->new_set(); Get the GT::SQL::Table ref to a previous table: my $GT_SQL_Table_ref = $session->get_set( $tmp_id ); List all the sets for current session: my $href = $session->list_sets(); Save data with the session: $session->data ("Save this information!"); Load a session. my $session = new GT::Session::TempTable ( $id ) or die "Can't load session: '$id'." Delete a session: $session->delete(); Delete a table set: $session->delete_set( $tmp_id ); Cleanup old sessions, takes argument of number of seconds old. $session->cleanup ( 5000 ); =cut