@Apache::Session::DBI::ISA
=
qw(Apache::Session)
;
$Apache::Session::DBI::VERSION
=
'0.02'
;
use
constant
DSN
=>
$ENV
{
'SESSION_DBI_DATASOURCE'
} || croak
"SESSION_DBI_DATASOURCE not set"
;
use
constant
USER
=>
$ENV
{
'SESSION_DBI_USERNAME'
} ||
undef
;
use
constant
PASS
=>
$ENV
{
'SESSION_DBI_PASSWORD'
} ||
undef
;
my
$db_ac
= ( DSN =~ /mSQL/ || DSN =~ /mysql/) ? 1 : 0;
my
$dbh
= DBI->
connect
(DSN, USER, PASS, {
PrintError
=> 1,
AutoCommit
=>
$db_ac
}) ||
die
$DBI::errstr
;
my
$sth_lock
=
$dbh
->prepare(
"INSERT INTO locks (id) VALUES (?)"
) ||
die
$DBI::errstr
;
my
$sth_unlock
=
$dbh
->prepare(
"DELETE FROM locks WHERE id = ?"
) ||
die
$DBI::errstr
;
my
$sth_get
=
$dbh
->prepare(
"SELECT id, a_session FROM sessions WHERE id = ?"
) ||
die
$DBI::errstr
;
my
$sth_destroy
=
$dbh
->prepare(
"DELETE FROM sessions WHERE id = ?"
) ||
die
$DBI::errstr
;
my
$sth_create
=
$dbh
->prepare(
"INSERT INTO sessions (id, a_session) VALUES ( ?, ? )"
) ||
die
$DBI::errstr
;
my
$sth_update
=
$dbh
->prepare(
"UPDATE sessions SET a_session = ? WHERE id = ?"
) ||
die
$DBI::errstr
;
sub
glock {
my
$id
=
shift
;
return
undef
unless
$id
;
$sth_lock
->bind_param( 1,
$id
,
$DBI::SQL_STRING
);
eval
{
local
$SIG
{__DIE__};
$sth_lock
->execute() ||
die
$DBI::errstr
;
};
if
($@) {
warn
"Lock for $id failed: $@"
;
$dbh
->rollback()
unless
$db_ac
;
return
undef
;
}
$dbh
->commit()
unless
$db_ac
;
return
1;
}
sub
gunlock {
my
$id
=
shift
;
$sth_unlock
->bind_param( 1,
$id
,
$DBI::SQL_STRING
);
eval
{
local
$SIG
{__DIE__};
$sth_unlock
->execute() ||
die
$DBI::errstr
;
};
if
($@) {
warn
"unlock for $id failed: $@"
;
$dbh
->rollback()
unless
$db_ac
;
return
undef
;
}
$dbh
->commit()
unless
$db_ac
;
return
1;
}
sub
safe_connect {
my
$dbh
;
eval
{
local
$SIG
{__DIE__};
$dbh
= DBI->
connect
(DSN, USER, PASS, {
PrintError
=> 1,
AutoCommit
=>
$db_ac
}) ||
die
$DBI::errstr
;
};
if
($@) {
warn
"Database not connected: $@"
;
return
undef
;
}
return
$dbh
;
}
sub
safe_thaw {
my
$frozen
=
shift
;
return
undef
unless
(
$frozen
=~ /FrT/ );
return
thaw(
$frozen
);
}
sub
options {
{
autocommit
=> 0,
lifetime
=>
$ENV
{
'SESSION_LIFETIME'
}
};
}
sub
create {
my
$class
=
shift
;
my
$id
=
shift
;
return
undef
unless
glock(
$id
);
$sth_get
->bind_param( 1,
$id
,
$DBI::SQL_STRING
);
eval
{
local
$SIG
{__DIE__};
$sth_get
->execute() ||
die
$DBI::errstr
;
};
if
( $@ ) {
warn
"Database error in create: $@"
;
gunlock(
$id
);
return
undef
;
}
my
(
$old_id
,
$old_data
);
$sth_get
->bind_columns(
undef
, \
$old_id
, \
$old_data
);
$sth_get
->fetch;
if
(
$old_id
) {
my
$oldhash
= safe_thaw(
$old_data
);
unless
(
$oldhash
=~ /HASH/ ) {
gunlock(
$id
);
return
undef
;
}
if
(
$oldhash
->{
'_EXPIRES'
} <
time
() ) {
$sth_destroy
->bind_param( 1,
$id
,
$DBI::SQL_STRING
);
eval
{
local
$SIG
{__DIE__};
$sth_destroy
->execute() ||
die
$DBI::errstr
;
};
if
( $@ ) {
gunlock(
$id
);
$dbh
->rollback()
unless
$db_ac
;
return
undef
;
}
$dbh
->commit()
unless
$db_ac
;
}
else
{
gunlock(
$id
);
return
undef
;
}
}
my
$rv
= {};
my
$frozen
= freeze(
$rv
);
$sth_create
->bind_param( 1,
$id
,
$DBI::SQL_STRING
);
$sth_create
->bind_param( 2,
$frozen
,
$DBI::SQL_STRING
);
eval
{
local
$SIG
{__DIE__};
$sth_create
->execute() ||
die
$DBI::errstr
;
};
if
($@) {
gunlock(
$id
);
$dbh
->rollback()
unless
$db_ac
;
return
undef
;
}
$dbh
->commit()
unless
$db_ac
;
return
$rv
;
}
sub
fetch {
my
$class
=
shift
;
my
$id
=
shift
;
return
undef
unless
glock(
$id
);
$sth_get
->bind_param( 1,
$id
,
$DBI::SQL_STRING
);
eval
{
local
$SIG
{__DIE__};
$sth_get
->execute() ||
die
$DBI::errstr
;
};
if
( $@ ) {
warn
"Fetch failed for session $id: $@"
;
gunlock(
$id
);
return
undef
;
}
my
(
$db_id
,
$db_data
);
$sth_get
->bind_columns(
undef
, \
$db_id
, \
$db_data
);
$sth_get
->fetch;
my
(
$oldhash
) = safe_thaw(
$db_data
);
if
( ! (
$oldhash
=~ /HASH/ ) ) {
gunlock(
$id
);
return
undef
;
}
return
$oldhash
;
}
sub
commit {
my
$class
=
shift
;
my
$hashref
=
shift
;
my
$id
=
$hashref
->{
'_ID'
};
my
$frozen_self
= freeze (
$hashref
);
$sth_update
->bind_param( 1,
$frozen_self
,
$DBI::SQL_STRING
);
$sth_update
->bind_param( 2,
$id
,
$DBI::SQL_STRING
);
eval
{
local
$SIG
{__DIE__};
$sth_update
->execute() ||
die
$DBI::errstr
;
};
if
( $@ ) {
$dbh
->rollback()
unless
$db_ac
;
return
undef
;
}
$dbh
->commit()
unless
$db_ac
;
return
1;
}
sub
destroy {
my
$self
=
shift
;
my
$id
=
$self
->{
'_ID'
};
$sth_destroy
->bind_param( 1,
$id
,
$DBI::SQL_STRING
);
eval
{
local
$SIG
{__DIE__};
$sth_destroy
->execute() ||
die
$DBI::errstr
;
};
if
($@) {
gunlock(
$id
);
$dbh
->rollback()
unless
$db_ac
;
return
undef
;
}
$dbh
->commit()
unless
$db_ac
;
gunlock(
$id
);
return
1;
}
sub
DESTROY {
my
$self
=
shift
;
my
$id
=
$self
->{
'_ID'
};
gunlock(
$id
);
}
sub
dump_to_html {
my
$self
=
shift
;
my
$s
;
my
$key
;
$s
=
$s
.
"<table border=1>\n\t<tr>\n\t\t<td>Variable Name</td>\n\t\t<td>Scalar Value</td>\n\t</tr>"
;
foreach
$key
(
sort
(
keys
(% {
$self
}))) {
$s
=
$s
.
"\n\t<tr>\n\t\t<td>$key</td>\n\t\t<td>$self->{$key}</td>"
;
}
$s
=
$s
.
"\n</table>\n"
;
return
$s
;
}
1;