passing a reference to a hash to another page

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Threaded View
This is a web front end to a database, served via Apache using SQLite
using CGI.

The key requirement is that the app displays the data to the user and
prints it at the user's request, which happens infrequently.

I can print a document by:
 - running a query to get a hash ref
 - processing the hashref to get an appropriate data structure
 - opening a file
 - printing the data structure to a file
 - closing the file, and
 - returning a link to the file to the user

I can also display the data by:
 - running a query to get a hash ref
 - processing the hashref to get an appropriate data structure, and
 - printing the data structure to the screen

What I need is a button on the display that will allow the user to
print a document using the same hashref. I don't want to run the query
again, and don't particularly want to store the data (using Storable,
perhaps), but to pass the hashref to another page via an HTTP request,
and have the second page open a file, print to the file, close the
file, and return a link to the user.

Unfortunately, the hashref doesn't persist between invocations of the
script and new HTTP requests. For example, I can do this:
<a href="mydata?what=printcsv&data=HASH(0xDEADBEEF)"
target="_blank">Print a file</a>

But all I get is the value 'HASH(0xDEADBEEF)". I can't dereference it
to get at the data.

Seems like I should be able to tell the program to hold onto the
hashref between invocations of the script, but I can't seen to figure
out how. Ideas?

Thanks, CC.

Re: passing a reference to a hash to another page


Quoted text here. Click to load it

This is impossible except if you're using a persistent perl
interpreter (eg mod_perl) and the next request of the user happens to
be processed by the same process and the hashref hasn't been
deallocated in the meantime, say, because an entry in a 'global' hash
table points to it. You'll either have to store it locally, possibly,
using some module which provides session support or send it to the
user and have him send it back, for instance, putting a textual
representation of the hashref in a hidden form field.

Possibly helpful:
NB: I haven't used the module myself.


Re: passing a reference to a hash to another page

Quoted text here. Click to load it

Thanks, Ranier and Ben.

I've decided to hit the database every time a user requests data,
regardless of the purpose.

I'm sending the search parameters via a form, and I have modularized
both the presentation of the form and the response to the form.
Instead of printing the output back to Apache, I'll just open a file
and send it to the file.

Lest you think that I was confused, let me assure you that I was
indeed confused. The idea that I had was that, since the data resided
somewhere in memory, and since I had the address of that memory,
instead of losing the reference to the hash I would reuse it. I do
this routinely with scripts that I have written for the purpose of
printing reports, i.e., printing them directly without displaying them
to the user, and thought I could both print the data to HTML output
and print the data to a file afterward with an intervening HTTP
request, but just couldn't think it through.

Thanks for your time and help -- I appreciate it.


Re: passing a reference to a hash to another page

Quoted text here. Click to load it

This is the same problem as that addressed by perldoc -q 'reference as a
hash key', with (as Rainer pointed out) the added problem that you have
no guarantee that the second request will be handled by the same process
as the first. Even if you set up some sort of persistent perl process,
and (somehow) arrange for a given user to always talk to the same
instance, you have to assume the server might crash and restart between
one response and the next, at which point all in-memory data is lost.

Given that, you *have* to serialise the hash somewhere between requests.
Sending it down to the client, as a hidden form field or a cookie, seems
like an attractive option; but it is only practical for small amounts of
data. For large amounts, or for data the client shouldn't be able to
change in arbitrary ways, you need to serialise it server-side.

Unless your query takes a long time to run, re-running the query is
probably the simplest option. (You should seriously consider whether you
can make this possible.) If that takes too long, all the other options
basically boil down to some sort of cache:

    - You may be able to change your database schema to make the query
      run faster: probably this means denormalising it in some way. Can
      you arrange to store the results you need in another table or
      tables, possibly with triggers or stored procedures or something
      inside the database to keep it up to date?

    - Otherwise, you will need to serialise the Perl data structure and
      store it somewhere. The simple-minded way of doing this would be
      to use Storable, and either put it in plain files or in some sort
      of DBM file. You would then need to pass the filename or the key
      down to the client, and retrieve the data when the client passes
      it back. You would also need to think *carefully* about
      concurrency and locking, unless you use something like the later
      versions of BDB (with the BerkeleyDB module, rather than with
      DB_File) which will handle this for you.

    - This only works if all your requests are handled by one machine,
      or at least if they all have access to the same filesystem (and
      that filesystem is completely reliable wrt multiple concurrent
      writes from different machines, which most network filesystems
      aren't). A good cross-machine solution is memcached; the
      Cache::Memcached module will handle the Storing for you
      transparently, though of course you do have to make sure your data
      structure is suitable for Storing.

You could of course also just serialise the data into a blob in a
database column, but that always seems like a bad idea to me. The whole
point of an SQL database is that it can see inside the structure of your
data and make intelligent decisions about how to plan queries based on
that; if all you need is a key-value store, something like BDB or
memcached which was designed to be that and no more will be both faster
and cleaner.

Quoted text here. Click to load it

Only because you haven't yet understood that HTTP is a stateless
protocol. This is what that means: that keeping data across requests has
to be done explicitly.


Site Timeline