CAM-SQLManager
view release on metacpan or search on metacpan
lib/CAM/SQLManager.pm view on Meta::CPAN
dbh => undef,
dir => $global_directory,
# Internal parameters:
filename => "",
filetime => 0,
tableName => "",
keyName => "",
queries => {},
defaultquery => undef,
}, $pkg);
# pick up default arguments, if any
$self->{cmd} = shift if (@_ > 0 && $_[0] !~ /^\-[a-z]+$/);
# process switched arguments
while (@_ > 0 && $_[0] =~ /^\-[a-z]+$/)
{
my $key = shift;
my $value = shift;
$key =~ s/^\-//;
$self->{$key} = $value;
}
if (@_ > 0)
{
&carp("Too many arguments");
return undef;
}
# Validate "dbh"
if (!$self->getDBH()) {
&carp("The DBH object is undefined");
return undef;
}
if (ref($self->getDBH()) !~ /^DBI\b/ && ref($self->getDBH()) !~ /^DBD\b/) {
&carp("The DBH object is not a valid DBI/DBD connection: " . ref($self->getDBH()));
return undef;
}
# Validate "cmd"
if ($self->{cmd} !~ /^(\w+[\/\\])*\w+(|\.\w+)$/)
{
&carp("Command keyword is not alphanumeric: $$self{cmd}");
return undef;
}
# Use "dir" and "cmd" to get the SQL template
$self->{filename} = File::Spec->catfile($self->{dir}, $self->{cmd});
local *FILE;
if (!open(FILE, $self->{filename}))
{
&carp("Cannot open sql command '$$self{filename}': $!");
return undef;
}
local $/ = undef;
$self->{sql} = <FILE>;
close(FILE);
# Record the last-mod time of the file so we can notice if it changes
$self->{filetime} = (stat($self->{filename}))[9];
# Set up the statistics data structures
if (!exists $global_stats{cmds}->{$self->{cmd}})
{
# Any changes to this data structure should be propagated into
# _incrStats() and the documentation for statistics()
$global_stats{cmds}->{$self->{cmd}} = {
queries => 0,
time => 0,
query => {},
};
}
my $struct = CAM::XML->parse($self->{sql});
if ((!$struct) || $struct->{name} ne "sqlxml")
{
&carp("XML parsing of the SQL query failed");
return undef;
}
# Read the table data
my ($tabledata) = $struct->getNodes(-path => "/sqlxml/table");
if ($tabledata)
{
if ($tabledata->getAttribute("name"))
{
$self->{tableName} = $tabledata->getAttribute("name");
}
if ($tabledata->getAttribute("primarykey"))
{
$self->{keyName} = $tabledata->getAttribute("primarykey");
}
}
# Extract all of the queries
my @queries = $struct->getNodes(-path => "/sqlxml/query");
if (@queries < 1)
{
&carp("There are no query tags in $$self{filename}");
return undef;
}
foreach my $query (@queries)
{
my $name = $query->getAttribute("name");
$name = "_default" if (!$name);
if (exists $self->{queries}->{$name})
{
&carp("Multiple queries named $name in $$self{filename}");
return undef;
}
# Throw away whitespace elements in the query body
my $queryarray = [grep({$_->isa("CAM::XML") || $_->{text} =~ /\S/} $query->getChildren())];
$self->{queries}->{$name} = $queryarray;
if ((!$self->{defaultquery}) || $name eq "_default")
{
$self->{defaultquery} = $queryarray;
}
}
# Set up statistics data structure
foreach my $queryname ("retrieveByKey", keys %{$self->{queries}})
{
# Any changes to this data structure should be propagated into
# _incrStats() and the documentation for statistics()
$global_stats{cmds}->{$self->{cmd}}->{query}->{$queryname} = {
queries => 0,
time => 0,
};
}
return $self;
}
#------------------
=item getMgr CMD, CMD, ...
=item getMgr -dbh => DBH, CMD, CMD, ...
Like new() above, but caches the manager objects for later
re-requests. Unlike new(), the database handle and SQL file directory
must already be set. Use this function like:
CAM::SQLManager->getMgr("foo.xml");
If more than one command is specified, the first one that results in a
real file is used.
=cut
sub getMgr
{
my $pkg = shift;
my @args = ();
if ($_[0] && $_[0] eq "-dbh")
{
push @args, shift, shift;
}
my @cmds = (@_);
foreach my $cmd (@cmds)
{
if (-e File::Spec->catfile($global_directory, $cmd))
{
if (exists $global_cache{$cmd})
{
# Check to make sure the SQL file has not changed
if ($global_cache{$cmd}->{filetime} < (stat($global_cache{$cmd}->{filename}))[9])
{
$global_cache{$cmd} = $pkg->new($cmd, @args);
}
}
else
{
$global_cache{$cmd} = $pkg->new($cmd, @args);
}
return $global_cache{$cmd};
}
}
return undef;
}
#------------------
=item getAllCmds
Search the SQL directory for all command files. This is mostly just
useful for the testCommands() method.
=cut
sub getAllCmds
{
my $pkg = shift;
my @files;
my $regex = join("|", map {quotemeta} @global_extensions);
my @dirs = ($global_directory);
my %seendirs;
while (@dirs > 0)
{
local *DIR;
my $dir = shift @dirs;
next if ($seendirs{$dir}++);
if (!opendir(DIR, $dir))
{
if ($dir eq $global_directory)
{
&carp("Failed to read the SQL library directory '$dir': $!");
return ();
}
}
else
{
my @entries = readdir(DIR);
closedir(DIR);
@entries = map {File::Spec->catfile($dir, $_)} grep !/^\.\.?$/, @entries;
push @files, grep /($regex)$/, @entries;
push @dirs, grep {-d $_} @entries;
}
}
return @files;
}
#------------------
=item setDirectory DIRECTORY
( run in 1.782 second using v1.01-cache-2.11-cpan-d7f47b0818f )