Using Subroutines with CGI::Session::MySQL?


L

L. D. James

Can somebody tell me why accessing the sessions will cause the mysql
driver to fail.

Please look at the follow code. I have commented out the access
line. Please notice that refreshing the page will increment the
count, because it will communicate with the session. Uncommenting
then line, and the count variable will stop incrementing.

#--------------------------- Code Begin
-------------------------------

use warnings;
use strict;
use DBI;
use CGI qw:)standard);
use Switch;
use CGI::Carp qw(fatalsToBrowser);
use CGI::Session::MySQL;

my $name;
my $count;

my $query = new CGI;
my $dbh = DBI->connect( "DBI:mysql:flightmembers:localhost",
"username", "userpass" );
my $sid = cookie('CGISESSID') || param('CGISESSID') || undef;
my $session = new CGI::Session("driver:MySQL", $sid, {Handle=>$dbh})
or die "Session Error...";

sub processdata()
{
my $username = 'No Data Yet';
print "<br>-->$name<--<br>-->$count<--<br>";
# $username = $session->param('f_name');
print "<br>Processing Data for $username.<br>";
}

print $session->header();

$name = $session->param('f_name');
$count = $session->param("count") || "0";;
$count++;
$session->param('f_name','Larry James');
$session->param('count',"$count");

&processdata();

#---------------------------- Code End
 
Ad

Advertisements

M

Mumia W.

Can somebody tell me why accessing the sessions will cause the mysql
driver to fail.

Please look at the follow code. I have commented out the access
line. Please notice that refreshing the page will increment the
count, because it will communicate with the session. Uncommenting
then line, and the count variable will stop incrementing.

#--------------------------- Code Begin
-------------------------------

use warnings;
use strict;
use DBI;
use CGI qw:)standard);
use Switch;
use CGI::Carp qw(fatalsToBrowser);
use CGI::Session::MySQL;

my $name;
my $count;

my $query = new CGI;
my $dbh = DBI->connect( "DBI:mysql:flightmembers:localhost",
"username", "userpass" );
my $sid = cookie('CGISESSID') || param('CGISESSID') || undef;
my $session = new CGI::Session("driver:MySQL", $sid, {Handle=>$dbh})
or die "Session Error...";

sub processdata()
{
my $username = 'No Data Yet';
print "<br>-->$name<--<br>-->$count<--<br>";
# $username = $session->param('f_name');
print "<br>Processing Data for $username.<br>";
}

print $session->header();

$name = $session->param('f_name');
$count = $session->param("count") || "0";;
$count++;
$session->param('f_name','Larry James');
$session->param('count',"$count");

&processdata();

#---------------------------- Code End
--------------------------------

Thanks in advance for any comments on this.

-- L. James

I'm assuming you're running under mod_perl.

This seems to have something to do with the peculiar environment that
mod_perl creates.

I got your program to update the count correctly by placing this line at
the top of the file:

package Experimental;

The idea was to make sure that the script was always evaluated in the
same package. I haven't figured out why it's necessary to do this, but I
think it has something to do with the way processdata() is defined.
 
L

L. D. James

I'm assuming you're running under mod_perl.

This seems to have something to do with the peculiar environment that
mod_perl creates.

I got your program to update the count correctly by placing this line at
the top of the file:

package Experimental;

The idea was to make sure that the script was always evaluated in the
same package. I haven't figured out why it's necessary to do this, but I
think it has something to do with the way processdata() is defined.

Thanks for the quick solution. I have mod_perl installed. I thought
the code was running the perl, v5.8.8 package that was installed and
updated via CPAN (in an effort to fix the problem).

It's working now, but I'll study more about your comments so that I
can learn how to have my scripts more portable.

Since the immediate problem that had me very perplexed for a day, it's
not as critical, but I'm curious what others are doing to define their
sub routines that would possibly work without the package Experimental
line.

By the way, when I use the File session driver it works fine (without
the package Experimental line). However, I prefer to use the MySQL
driver.

Thanks a lot for the rescue and input.

-- L. James
 
X

xhoster

L. D. James said:
Can somebody tell me why accessing the sessions will cause the mysql
driver to fail.

Please look at the follow code. I have commented out the access
line. Please notice that refreshing the page will increment the
count, because it will communicate with the session. Uncommenting
then line, and the count variable will stop incrementing.

#--------------------------- Code Begin
-------------------------------

use warnings;
use strict;
use DBI;
use CGI qw:)standard);
use Switch;
use CGI::Carp qw(fatalsToBrowser);
use CGI::Session::MySQL;

my $name;
my $count;

my $query = new CGI;
my $dbh = DBI->connect( "DBI:mysql:flightmembers:localhost",
"username", "userpass" );
my $sid = cookie('CGISESSID') || param('CGISESSID') || undef;
my $session = new CGI::Session("driver:MySQL", $sid, {Handle=>$dbh})
or die "Session Error...";

sub processdata()

Why use prototypes?
{
my $username = 'No Data Yet';
print "<br>-->$name<--<br>-->$count<--<br>";
# $username = $session->param('f_name');
print "<br>Processing Data for $username.<br>";
}

In a mod_perl environment, the $session that is accessible from inside
processdata is the variable allocated when the code was compiled, which
means it is the variable that was in effect the first time this
particular apache process invoked this code. So on subsequent invocation,
$session outside of processdata is a new $session, while inside of
processdata you get some earlier $session.

This is part of the "variable will not stayed shared" problem. One
fix is to pass $session into the subroutine rather than using the one
from the outer scope:

sub processdata {
my $session=shift;
#...
};



Xho
 
L

L. D. James

In a mod_perl environment, the $session that is accessible from inside
processdata is the variable allocated when the code was compiled, which
means it is the variable that was in effect the first time this
particular apache process invoked this code. So on subsequent invocation,
$session outside of processdata is a new $session, while inside of
processdata you get some earlier $session.

This is part of the "variable will not stayed shared" problem. One
fix is to pass $session into the subroutine rather than using the one
from the outer scope:

sub processdata {
my $session=shift;
#...

};

Xho

Thanks, Xho, for the input. I tested you fix and it works in the
example. I was actually in the process of changing from the File
driver to the MySQL driver. I have 10's of subroutines that update or
check the session data before exiting. Many of the subroutines have
been accumulated almost like a library of utilities that has expected
parameters, which I've been reusing (and refining) for years.

You are the second person that suggests that the mod_perl environment
might be a culprit. Is there a way to instruct the program to use the
regular perl rather than mod_perl.

Do you know why this additional parameter passing isn't required with
using the File driver? As much as I would have preferred to move over
to the mysql driver, I may have to hold off, for having to add a new
expected parameter to all my modules.

By the way, reading the data from any of the subroutines is never a
problem. The problem is that the session info can't be updated from
anywhere, not even the main program if the line:

$session->param('anyparam');

is referenced in any subroutine, even if that subroutine isn't called.

You can test that by commenting out the $session->param('f_name');
line from my example script.

Maybe I'm looking for a way to make the $session data more public. Or
maybe, possibly adding some variant of

$session = new CGI::Session("driver:MySQL", $sid, {Handle=>$dbh}) or
die "Session Error...";

to each subroutine that needs to access the session data.

Thanks again for the input.

-- L. James
 
M

Mumia W.

Thanks, Xho, for the input. I tested you fix and it works in the
example. I was actually in the process of changing from the File
driver to the MySQL driver. I have 10's of subroutines that update or
check the session data before exiting. Many of the subroutines have
been accumulated almost like a library of utilities that has expected
parameters, which I've been reusing (and refining) for years.

You are the second person that suggests that the mod_perl environment
might be a culprit. Is there a way to instruct the program to use the
regular perl rather than mod_perl.

Whether mod_perl or Perl/CGI is used is determined by the Apache
configuration.
Do you know why this additional parameter passing isn't required with
using the File driver? As much as I would have preferred to move over
to the mysql driver, I may have to hold off, for having to add a new
expected parameter to all my modules.

Xhoster got it right, and that's pretty good because the problem is
confusing. It evidently has something to do with the way that
processdata is compiled. Even this causes the bug to appear:

sub processdata()
{
my $username = 'No Data Yet';
print "<br>-->$name<--<br>-->$count<--<br>";
if (0) { $username = $session->param('f_name') }
By the way, reading the data from any of the subroutines is never a
problem. The problem is that the session info can't be updated from
anywhere, not even the main program if the line:

$session->param('anyparam');

is referenced in any subroutine, even if that subroutine isn't called.

Yes.

You can test that by commenting out the $session->param('f_name');
line from my example script.

Maybe I'm looking for a way to make the $session data more public. Or
maybe, possibly adding some variant of

Or perhaps less public (see below).
$session = new CGI::Session("driver:MySQL", $sid, {Handle=>$dbh}) or
die "Session Error...";

to each subroutine that needs to access the session data.

Thanks again for the input.

-- L. James

The problem is fixed if you "undef" the $session variable after you're
finished with it. Place this at the bottom of your program:

undef $session;

Remember that mod_perl creates persistent interpreters. The variables
and data in those interpreters can live for much longer than you expect
if you're accustomed to Perl/CGI.

I guess that any variables that you don't specifically want to remain
around until the web server shuts down should be explicitly "undef-ed."
 
Ad

Advertisements

X

xhoster

L. D. James said:
You are the second person that suggests that the mod_perl environment
might be a culprit. Is there a way to instruct the program to use the
regular perl rather than mod_perl.

That is an apache configuration issue. On the configuration that came with
my machine, scripts in /var/www/cgi-bin/ run by traditional CGI and scripts
in /var/www/perl/ run with mod_perl. Your configuration will be different.

Do you know why this additional parameter passing isn't required with
using the File driver?

I don't know. Perhaps it is a problem, and just has never presented itself
in an obvious way. Anyway, I would certainly consider it a problem waiting
to happen, and would be uneasy with just sticking with the file method
on the assumption that it is working correctly. My gut feeling is that
occasionally people are pulling data out of other people's session files,
which could be disastrous in a subtle way.
As much as I would have preferred to move over
to the mysql driver, I may have to hold off, for having to add a new
expected parameter to all my modules.

By the way, reading the data from any of the subroutines is never a
problem. The problem is that the session info can't be updated from
anywhere, not even the main program if the line:

$session->param('anyparam');

is referenced in any subroutine, even if that subroutine isn't called.

The subroutine holds an implicit reference to $session (the first $session
that existed at the time the subroutine was compiled). Because the
subroutine is not lexical, it never goes out of scope, which means the
reference it holds to $session never goes away, and hence $session itself
never goes out of scope and gets cleaned up (in this case, the mysql
connection does not get closed). This is the case whether or not the
subroutine ever gets called.

I don't understand why this leads to the exact problem you are observing
(do you see any errors in the logs?) but once you are living in a state of
sin, all bets are off on the weird things that can happen.

Anyway, you should run under warnings, and you should check your error logs
for those warnings. I get warnings that 'variable "$session" will not stay
shared' when I do things like that, and these warnings should not be
ignored.

Xho
 
L

L. D. James

The problem is fixed if you "undef" the $session variable after you're
finished with it. Place this at the bottom of your program:

undef $session;

Remember that mod_perl creates persistent interpreters. The variables
and data in those interpreters can live for much longer than you expect
if you're accustomed to Perl/CGI.

I guess that any variables that you don't specifically want to remain
around until the web server shuts down should be explicitly "undef-ed."

Bingo!

Works like a charm.

The "package Experimental" worked on the sample code, but failed when
used in conjunction with the full program that has many subroutines.
The passing of the $session couldn't be used because all the
subroutines would have to be rewritten to take a new parameter into
effect. Also, some of the routines would call some of the common
subroutines that didn't have a $session parameter to send. But the
concept gave me a lot of insight to study.

My resolution to make $sid a public variable and create a "new
CGI::Session" in each subroutine that needed to access the sessions
appeared to be workable. That's what I had been doing between looking
at your last input.

The "undef $session" worked immediately on the full program without
any changes. Your discussion about the left over garbage answered
another question that I had been trying to figure out a good way of
asking.

I had been wondering if perl leaked, and how much cleanup it did when
exiting the application from a subroutine without doing cleanup.

All my fill access programs close the file handle before exiting
perl. However, many of my mysql programs exited out the subroutine
when it finished doing its job, thereby often never reaching the $dbh-
disconnect() at the end of the code. This is especially the case
where my code reaches an error. I display a message then exits. I'm
sure, by the way, that the "die" function does some cleanup. As far
as all my other routines, I'm updating them to go to a "finish()"
subroutine to cleanup before exiting.

Thanks again for all the help and discussion. I had lost a night of
sleep trying to figure out what was going wrong.

-- L. James
 
L

L. D. James

Thanks, Xhoster. You're right about being concerned about something
that works one way and not working another being a possible game of
roulette... disaster waiting to happen. This is why I was so persistent
about finding a consistent solution and understanding as much as I
could about the functions and library.

I always use the warnings. The code using the File (or the MySQL
which failed) never produced any errors. However, I appreciate your
thoughts on doing robust checking to insure what's happening with the
data. It would be a serious security breach to pass the wrong data to
the wrong user. I'm still studying the CGI::Sessions Tutorials and
CookBook references to gain as much understanding as I can, and to be
sure to follow the examples of their models.

I'm surprised after all the reading I had been doing for a whole day I
missed the "undef $session" that's referenced in the documentation.

Looking further, I see a $session parameter in their sub routine
examples. So, as I mentioned in the previous message, I'm rewriting
my subroutines that uses the $sessions data to insure they follow the
proper design.

Thanks again for all the input and discussion.

-- L. James
 
X

xhoster

L. D. James said:
Thanks, Xhoster. You're right about being concerned about something
that works one way and not working another being a possible game of
roulette... disaster waiting to happen. This is why I was so persistent
about finding a consistent solution and understanding as much as I
could about the functions and library.

I always use the warnings. The code using the File (or the MySQL
which failed) never produced any errors.

Are you sure you are looking in the right place?
I'd add something like this, which certainly should
produce warnings, to your code:

sub sdfsadf { my $x; sub alkj { $x }};

Should produce warnings like
Variable "$x" will not stay shared at -e line 1.

If you don't see messages corresponding to that, then you may
be looking in the wrong place. On your original code, I found
these warnings on $session, $name, and $count.

Also, with your code on my system under mod_perl (I have mod_perl 1, not
mod_perl 2) I see the non-update of the counter under the default file
driver.

However, I appreciate your
thoughts on doing robust checking to insure what's happening with the
data. It would be a serious security breach to pass the wrong data to
the wrong user. I'm still studying the CGI::Sessions Tutorials and
CookBook references to gain as much understanding as I can, and to be
sure to follow the examples of their models.

Those sources make very scant reference to mod_perl. If you are going to
run under mod_perl, you definitely need to read up on that, as well. The
problems you are seeing are due to way you are using mod_perl, and
related problems may well pop up in contexts other than CGI::Session as
well. Generally I just avoid mod_perl until I know for certain that
it is necessary.

Xho
 
M

Mumia W.

[...]
I had been wondering if perl leaked, and how much cleanup it did when
exiting the application from a subroutine without doing cleanup.

Mod_perl is a strange environment. It's built for breath-taking
efficiency, but it complicates programming. This wasn't a Perl leak--it
was an effect of the additional complexity brought by mod_perl.
All my fill access programs close the file handle before exiting
perl. However, many of my mysql programs exited out the subroutine
when it finished doing its job, thereby often never reaching the $dbh-
disconnect() at the end of the code. This is especially the case
where my code reaches an error. I display a message then exits. I'm
sure, by the way, that the "die" function does some cleanup. As far
as all my other routines, I'm updating them to go to a "finish()"
subroutine to cleanup before exiting.

Thanks again for all the help and discussion. I had lost a night of
sleep trying to figure out what was going wrong.

-- L. James

You're quite welcome.

Enclosing the entire program in curly braces might also work to make
sure that variables go out of scope properly, and I think you can
configure mod_perl to compile programs in a much less persistent (and
efficient) way; I think this is called PerlRun mode.
 
Ad

Advertisements

L

L. D. James

Mod_perl is a strange environment. It's built for breath-taking
efficiency, but it complicates programming. This wasn't a Perl leak--it
was an effect of the additional complexity brought by mod_perl.

I really don't think I'm running mod_perl. I asked a few times how
can I verify weather I am or not. I would think that I'm running the
regular perl since the first line of each one of my scripts have, "#!/
usr/local/bin/perl", at the top. I just noticed that I missed
including this line in my example. This line is in my example on my
machine, I just missed, by mistake, pasting it to the forum.

If mod_perl insist on running in spite of this declaration, then I
don't know. I have learned a lot from my reading of this group and
reading the recommended books and references, however, I still have
lots of gaps. I would have never suspected that I was running
mod_perl.
Enclosing the entire program in curly braces might also work to make
sure that variables go out of scope properly, and I think you can
configure mod_perl to compile programs in a much less persistent (and
efficient) way; I think this is called PerlRun mode.

I'll study this "PerlRun" mode and the effect of using the curly
braces for the entire program. I would be more inclined to just run
perl, rather than mod_perl if I knew how to specify the difference.
I'm sure in the process of studying the reference, "PerlRun" mode
might help me to understand this better.

-- L. James
 
L

L. D. James

Are you sure you are looking in the right place?
I'd add something like this, which certainly should
produce warnings, to your code:

sub sdfsadf { my $x; sub alkj { $x }};

Should produce warnings like
Variable "$x" will not stay shared at -e line 1.

If you don't see messages corresponding to that, then you may
be looking in the wrong place. On your original code, I found
these warnings on $session, $name, and $count.

Yes. I get the error you mention when adding your line to the sample
code. But my example didn't produce errors before adding the lines.
Studying your reference to my example giving errors on your machine, I
was able to duplicate and figure out why I wasn't getting errors.
This is because there is information in the variables since having ran
the code, so I wasn't getting the uninitialized error message with
$name and $count.

A fresh load of the code from a different machine that didn't have the
any of the cookie information would initially give the warnings. I
fixed the warnings by initializing them with a default null value as:

$name = $session->param('f_name') || "";
$count = $session->param("count") || "0";;

I would have done that for the example before posting it, since I
tried to find lines that duplicated the problem I was having, but
would otherwise be clean code. I missed it because I was running
under the same session ID with the same persistent cookie.

I had mentioned in my description that there was no problem accessing
the session information. The problem was in writing, or updating the
session information. So since it was there, the variables were
initialized on my machine and didn't product those warning.
Also, with your code on my system under mod_perl (I have mod_perl 1, not
mod_perl 2) I see the non-update of the counter under the default file
driver.

I'm not sure if my code on my machine is operating under any version
of mod_perl. Do you get this same effect if you include a specifier
in the first line of the script, "#!/usr/local/bin/perl" or wherever
your normal perl is installed?
Those sources make very scant reference to mod_perl. If you are going to
run under mod_perl, you definitely need to read up on that, as well. The
problems you are seeing are due to way you are using mod_perl, and
related problems may well pop up in contexts other than CGI::Session as
well. Generally I just avoid mod_perl until I know for certain that
it is necessary.

Likewise, I have not intentionally used mod_perl and don't think I
am. Can you tell me how to insure that I am avoiding mod_perl, as you
do?

-- L. James
 
X

xhoster

L. D. James said:
I really don't think I'm running mod_perl. I asked a few times how
can I verify weather I am or not.

The *best* way is to figure out how to read your apache configuration,
or ask someone who already does know. You can also print our the
%ENV hash and see what it looks like.

## after printing the cgi/session header:
use Data::Dumper;
print pre(Dumper \%ENV);

On my machine, when running on mod_perl, I get a variable
'MOD_PERL' => 'mod_perl/1.99_09'
and it isn't there when doing straight CGI.
I would think that I'm running the
regular perl since the first line of each one of my scripts have, "#!/
usr/local/bin/perl", at the top.

That doesn't make any difference. If the process already knows that it is
perl, then the program specified on that line will not matter. (For
example, you can do "/usr/local/bin/perl foo.pl" and it will use
/usr/local/bin/perl, even if the #! line of foo.pl says something else, or
nothing at all.

If mod_perl insist on running in spite of this declaration, then I
don't know.

That would be better phrased "If I insist on configuring my apache to use
mod_perl in spite of that declaration...." (which is the normal
configuration. I've never heard of one in which apache inspects #! in
order to decide whether to use mod_perl)

mod_perl is not a sentient being. You are.

Cheers,

Xho
 
X

xhoster

L. D. James said:
Yes. I get the error you mention when adding your line to the sample
code. But my example didn't produce errors before adding the lines.
Studying your reference to my example giving errors on your machine, I
was able to duplicate and figure out why I wasn't getting errors.
This is because there is information in the variables since having ran
the code, so I wasn't getting the uninitialized error message with
$name and $count.

The uninitialized message is different from the "will not stayed shared"
message. One happens at run time, one at compile time.
A fresh load of the code from a different machine that didn't have the
any of the cookie information would initially give the warnings. I
fixed the warnings by initializing them with a default null value as:

$name = $session->param('f_name') || "";
$count = $session->param("count") || "0";;

It is the occurence of $name and $count (and $session) inside the sub
that gives rise to the will not stay shared errors. The references
outside the sub are not relevant to that matter.

....
I had mentioned in my description that there was no problem accessing
the session information. The problem was in writing, or updating the
session information.

Are you sure? On my system, running your code, the information was being
updated just fine. It didn't *look* like it was being updated, because
the information retrieved and printed did not reflect the update. That
isn't because it wasn't being updated, but rather because it was being
retrieved from the wrong session.

If I report $count both inside the sub and in the main code, I noticed
that the one printed from the main code always appeared to be updated,
while the one printed from the sub appeared not to be.

I'm not sure if my code on my machine is operating under any version
of mod_perl. Do you get this same effect if you include a specifier
in the first line of the script, "#!/usr/local/bin/perl" or wherever
your normal perl is installed?

mod_perl doesn't care about your #! line.

Likewise, I have not intentionally used mod_perl and don't think I
am. Can you tell me how to insure that I am avoiding mod_perl, as you
do?

Sorry, I'm just barely competent (if that) to configure my own apache
installation, and am in no position to help other people with theirs.
After all, I'm a Perl person, not an apache person. You might want
to seek help in an apache-specific resource.

Xho
 
L

L. D. James

The *best* way is to figure out how to read your apache configuration,
or ask someone who already does know. You can also print our the
%ENV hash and see what it looks like.

## after printing the cgi/session header:
use Data::Dumper;
print pre(Dumper \%ENV);

Checking the environment hash, mod_perl isn't in the picture in my
programs and scripts.
On my machine, when running on mod_perl, I get a variable
'MOD_PERL' => 'mod_perl/1.99_09'
and it isn't there when doing straight CGI.


That doesn't make any difference. If the process already knows that it is
perl, then the program specified on that line will not matter. (For
example, you can do "/usr/local/bin/perl foo.pl" and it will use
/usr/local/bin/perl, even if the #! line of foo.pl says something else, or
nothing at all.

Thanks for the information on this.
That would be better phrased "If I insist on configuring my apache to use
mod_perl in spite of that declaration...." (which is the normal
configuration. I've never heard of one in which apache inspects #! in
order to decide whether to use mod_perl)

Since it doesn't inspect the configuration, it will (insist/ persist
to) use mod_perl or whatever it chooses to use based on other elements
(of which are currently beyond my immediate knowledge, though I'm
learning fast).
mod_perl is not a sentient being. You are.

Of course it isn't. There are times when people describe insentient
elements such as storms, automobiles, ships, computers, etc... as if
they where doing something. When someone says, the computer did... I
realize they really mean the computer programmer or operator did...

-- L. James
 
Ad

Advertisements

L

L. D. James

The uninitialized message is different from the "will not stayed shared"
message. One happens at run time, one at compile time.



It is the occurence of $name and $count (and $session) inside the sub
that gives rise to the will not stay shared errors. The references
outside the sub are not relevant to that matter.

After studying the results environment hash, I'm sure this explains
why you and I see some things differently. You mentioned that
mod_perl behave different from straight perl. I don't run mod_perl.
Are you sure? On my system, running your code, the information was being
updated just fine. It didn't *look* like it was being updated, because
the information retrieved and printed did not reflect the update. That
isn't because it wasn't being updated, but rather because it was being
retrieved from the wrong session.

If I report $count both inside the sub and in the main code, I noticed
that the one printed from the main code always appeared to be updated,
while the one printed from the sub appeared not to be.

On mine, it would be updated, subsequently upon calling the data, it
would read the data, and display what had been placed in the cookie
session. The display of the data would function equally whether being
called from the sub routine or from the main program. When it appears
in the variable would depend on when it was placed in the session and
read from the session.

Again, session reads are never a problem on my system, only updating
the session.
Sorry, I'm just barely competent (if that) to configure my own apache
installation, and am in no position to help other people with theirs.

Without trying, you inadvertently showed me by way of the environment
hash code you mentioned in the previous message.
After all, I'm a Perl person, not an apache person. You might want
to seek help in an apache-specific resource.

I didn't know that mod_perl was in the picture. I had intentionally
tried to leave it out. It seems as if I actually succeeded. I'm very
concerned about the consistent behavior of my programs, that's why I
put so much into knowing as much about the environment as I can.
That's why I endeavored to use straight perl, of which I hoped had
some consistency with the reference manuals I was studying.

-- L. James
 
M

Mumia W.

After studying the results environment hash, I'm sure this explains
why you and I see some things differently. You mentioned that
mod_perl behave different from straight perl. I don't run mod_perl.


On mine, it would be updated, subsequently upon calling the data, it
would read the data, and display what had been placed in the cookie
session. The display of the data would function equally whether being
called from the sub routine or from the main program. When it appears
in the variable would depend on when it was placed in the session and
read from the session.

Again, session reads are never a problem on my system, only updating
the session.


Without trying, you inadvertently showed me by way of the environment
hash code you mentioned in the previous message.


I didn't know that mod_perl was in the picture. I had intentionally
tried to leave it out. It seems as if I actually succeeded. I'm very
concerned about the consistent behavior of my programs, that's why I
put so much into knowing as much about the environment as I can.
That's why I endeavored to use straight perl, of which I hoped had
some consistency with the reference manuals I was studying.

-- L. James

You've helped to demonstrate that this is not a mod_perl-related
problem. When I create a Perl/CGI program that doesn't unclude the
"undef $session;" at the bottom, the bug returns.

BTW, I was wrong about putting the program in curly braces and using the
PerlRun Apache Perl handler. Neither solves the problem.

This might be a bug in CGI::Session::MySQL (3.2.4.2). When a code block
is exited, lexical variables within that block are supposed to become
undefined; however, in CGI::Session::MySQL, this does not result in the
session data being flushed back to the database.

PS.
As alternatives to "undef $session" for fixing the problem, one can use
"$session->flush()" or "$session->close()" (at the end of the program).
 
L

L. D. James

This might be a bug in CGI::Session::MySQL (3.2.4.2). When a code block
is exited, lexical variables within that block are supposed to become
undefined; however, in CGI::Session::MySQL, this does not result in the
session data being flushed back to the database.

PS.
As alternatives to "undef $session" for fixing the problem, one can use
"$session->flush()" or "$session->close()" (at the end of the program).

Mumia, thanks again for all the research and discussion. There's a
definite difference between the behavior of the MySQL and File
driver. I was inclined to believe it was a bug in the MySQL driver.
I'm sure the File driver works properly.

I've been using MySQL for a long time with lots of applications.
MySQL doesn't normally act the way it does in CGI::Sessions:MySQL.
Neither does any of the other IO that I've use work that way.

I'm glad to have found some consistency. Now I have confidence in my
application. The bug is consistent and the workarounds works.

Reading the document, it says the "undef $session" isn't normally
necessary. However, from our studies it seems that it is always
necessary to undef, flush, or close the sessions.

It's been my experience (and reading the docs, you would expect it
would be consistent in this case) that the cleanup would be done upon
exit.

By the way, take a look at this code and tell me if you see anything
wrong with it. I don't see anything wrong with it. It works
perfectly on my machine and doesn't produce any errors. This is an
example of the way the many subroutines are called from my main
program.

With the workarounds that we have learned to overcome the bug, my
MySQL driver works like the File driver and like this fileio example.

Most of my actual programs use the BEGIN and use vars procedures at
the beginning of my main script. That is where the MySQL file is
actually open. Then all the other work is done by calling the various
subroutines.

I always run with Strict and warnings turned on and to insure the
integrity of my programs.

I appreciate all the discussion and suggestions from Xhoster. But at
present I can't produce an error that would suggest that my routines
request passing the public initialized variable to the subroutines.
The subroutines already have access.

The jury is still out, and I'm still taking my routines through very
stringent test.

Again, do you see a problem with the following code? If you don't see
a problem with it, how would you say it differs from the previous
code?

# ----- Code -----
#!/usr/local/bin/perl

use warnings;
use strict;
use CGI qw:)standard);
use Switch;
use CGI::Carp qw(fatalsToBrowser);

print header;

my $count;

if ( open (FILEIN,"testio.out") )
{
$count = <FILEIN> || "0";
close ( FILEIN );
}

open (FILEOUT,">testio.out") || die "Can't open output file...";

sub testio()
{
&menu1();
$count++;
print "<br>The Count: $count";
print FILEOUT "$count";
}

sub menu1()
{
print "<a href=testio.pl?cmd=testio>Testio<a>";
}

my $s = param('cmd') || $ARGV[0];

switch($s)
{
case "testio" { testio() }
else { menu1() }
}

close FILEOUT;
exit;

# ----- Code End -----

-- L. James
 
Ad

Advertisements

X

xhoster

L. D. James said:
It's been my experience (and reading the docs, you would expect it
would be consistent in this case) that the cleanup would be done upon
exit.

Sorry about that little digression/obsession with mod_perl. New theory,
same song, second verse. It is still based on your sub grabbing onto
lexicals which are outside of its scope. Since your sub is a global and it
holds a closure-like reference to the $session object, this prevents the
$session object from going out of scope, and hence from getting
its DESTROY method invoked, during the ref-counting part of perl's
shut-down. Instead, DESTROY gets invoked during "global destruction". The
problem is that during global destruction, DESTROY routines get called in
arbitrary order. So the $session's DESTROY invokes $session->flush, which
in turn invokes ->store on the underlying Session::Driver module, which
in turn tries to do the store with the mysql handle. However, that
mysql handle may have already been DESTROYed, and so the flush cannot
succeed. Why this doesn't give warning/error messages, I don't know.

If you do everything cleanly, meaning that named subs don't access lexicals
defined outside their scopes, then $session will be DESTROYed during the
ref-counting stage of shut-down. That means that anything which
DESTROY needs in order to operate correctly will still exist.

Or just add "undef $session" at the end.

Xho
 

Top