App-Framework
view release on metacpan or search on metacpan
lib/App/Framework/Feature/Sql.pm view on Meta::CPAN
# [ORDER BY {col_name | expr | position}
# [ASC | DESC], ...]
# [LIMIT {[offset,] row_count | row_count OFFSET offset}]
# [PROCEDURE procedure_name(argument_list)]
# [INTO OUTFILE 'file_name' export_options
# | INTO DUMPFILE 'file_name'
# | INTO var_name [, var_name]]
# [FOR UPDATE | LOCK IN SHARE MODE]]
#
#"SELECT `title` FROM `$table` WHERE `pid`=? AND `channel`=? LIMIT 1;"
#
#
#* UPDATE
#
#UPDATE [LOW_PRIORITY] [IGNORE]
# tbl_name
# SET col_name1=expr1 [, col_name2=expr2] ...
# [WHERE where_condition]
# [ORDER BY ... ASC|DESC]
# [LIMIT row_count]
#
#"UPDATE `$table` SET `title`=?, `date`=?, `start`=?, `duration`=?, `text`=?, `episode`=?, `num_episodes`=?, `repeat`=? ".
#'WHERE `pid`=? AND `channel`=? LIMIT 1 ;'
#
# where order limit setlist
#delete Y Y Y -
#insert - - - Y
#replace - - - Y
#select Y Y Y -
#update Y Y Y Y
#
#setlist => [SET] `var`=?, `var`=? ..
#andlist => [WHERE] `var`=? AND `var`=? ..
#varlist => [SELECT|ORDER BY] `var`, `var`
#
my %CMDS = (
'(sel|check)' => 'select',
'(del|rm)' => 'delete',
'ins' => 'insert',
'rep' => 'replace',
'upd' => 'update',
) ;
#=back
#
#=head2 %CMD_SQL - Parse control hash
#
#Variables get created with the name
#
# * $sqlvar_<context>
#
#where <context> is the hash key. This created variable contains the sql for this command or option.
#
#If the control hash entry contains a 'vals' entry, then the following variable is created:
#
# * @sqlvar_<context>
#
#This will be a text string containing something like "@sqlvar_select_vals,@sqlvar_where_vals" i.e. a comma
#seperated list of references to other arrays. These values will be expanded into a real array before use in the
#sql prepare.
#
#Also, as each entry is processed, extra variables are created:
#
# * $sqlvar_<context>_prefix - Prefix string for this entry
# * $sqlvar_<context>_format - Just the same as sqlvar_<context>
#
#
#=head2 Specification variables
#
#This control hash is used to direct processing of the SQL specification passed to sth_create(). If the spec
#contains a 'vars' field then these additional variables are created in the context:
#
# * $sqlvar_<context>_varlist - List of the 'vars' in the format `var`, `var` ..
# * $sqlvar_<context>_andlist - List of the 'vars' in the format `var` AND `var` ..
# * $sqlvar_<context>_varlist - List of the 'vars' in the format `var`=?, `var`=? ..
#
#If the spec has a 'vals' entry, then these are pushed on to an ARRAY ref and stored in:
#
# * @sqlvar_<context>_vals
#
#@sqlvar_<context>_vals = Real ARRAY ref (provided by the spec)
#@sqlvar_<context> = String in the format "@sqlvar_select_vals,@sqlvar_where_vals" (provided by parse control hash)
#
#
#=cut
my %CMD_SQL = (
## Overall query
'query' => {
'format' => '$sqlvar_select$sqlvar_delete$sqlvar_insert$sqlvar_replace$sqlvar_update',
'vals' => '@sqlvar_select,@sqlvar_delete,@sqlvar_insert,@sqlvar_replace,@sqlvar_update',
},
## Specific SQL commands
'select' => {
'prefix' => 'SELECT $sqlvar_select_varlist FROM `$sqlvar_table`',
'format' => 'SELECT $sqlvar_select_varlist FROM `$sqlvar_table` $sqlvar_where $sqlvar_group $sqlvar_order $sqlvar_limit',
'vals' => '@sqlvar_select_vals,@sqlvar_where_vals,@sqlvar_order_vals',
},
'delete' => {
'prefix' => 'DELETE FROM `$sqlvar_table`',
'format' => 'DELETE FROM `$sqlvar_table` $sqlvar_where $sqlvar_group $sqlvar_order $sqlvar_limit',
'vals' => '@sqlvar_where_vals,@sqlvar_order_vals',
},
'insert' => {
'prefix' => 'INSERT INTO `$sqlvar_table`',
'format' => 'INSERT INTO `$sqlvar_table` SET $sqlvar_insert_setlist',
'vals' => '@sqlvar_insert_vals',
},
'replace' => {
'prefix' => 'REPLACE INTO `$sqlvar_table`',
'format' => 'REPLACE INTO `$sqlvar_table` SET $sqlvar_replace_setlist',
'vals' => '@sqlvar_replace_vals',
},
'update' => {
lib/App/Framework/Feature/Sql.pm view on Meta::CPAN
They are then used as:
$sql->sth_query('check') ; # already given it's parameters
$sql->sth_query('check2', $pid, $channel) ;
$sql->sth_query('check3', $pid, $channel) ;
$sql->sth_query('select', $pid, $channel) ;
=cut
sub sth_create
{
my $this = shift ;
my ($name, $spec) = @_ ;
my @vals ;
## Set up vars
my %vars = $this->vars() ;
$vars{'sqlvar_select_varlist'} = '*' ;
$vars{'sqlvar_query'} = $CMD_SQL{'query'}{'format'} ;
$vars{'@sqlvar_query'} = $CMD_SQL{'query'}{'vals'} ;
# Default table name
$vars{'sqlvar_table'} = $vars{'table'} ;
$this->_dbg_prt(["sth_create($name)\n"], 2) ;
## Guess command based on name
my $cmd = $this->_sql_cmd($name) ;
$this->_dbg_prt([" + cmd=$cmd\n"], 2) ;
## Handle hash
if (ref($spec) eq 'HASH')
{
my %spec = (%{$spec}) ;
# Set table if specified
$vars{'sqlvar_table'} = delete $spec{'table'} if (exists($spec{'table'})) ;
# see if command specified
$cmd = delete $spec{'cmd'} if (exists($spec{'cmd'})) ;
$cmd = lc $cmd ;
# error check
$this->throw_fatal("No valid sql command") unless $cmd ;
# Process spec - set vars
$this->_sql_setvars($cmd, \%spec, \%vars) ;
}
elsif (!ref($spec))
{
# Process spec - set vars
$this->_sql_setvars($cmd || 'query', $spec, \%vars) ;
}
$this->_dbg_prt(["Vars=", \%vars], 2) ;
$this->_dbg_prt(["+ expand vars\n"], 2) ;
## Run through all vars and expand them
$this->_sql_expand_vars(\%vars) ;
## Run through all vars and expand arrays them
$this->_sql_expand_arrays(\%vars) ;
# query should now be in variable 'sqlvar_query'
my $sql = $vars{'sqlvar_query'} ;
# values should now be in variable '@sqlvar_query'
my $values_aref = $vars{'@sqlvar_query'} ;
if ($this->debug())
{
print "\n------------------------------------\n" ;
print "PREPARE SQL($name): $sql\n----------\n" ;
$this->prt_data("Values=", $values_aref) ;
}
#$this->prt_data("Values=", $values_aref, "\n--------------------\nVars=", \%vars) ;
## Use given/created command sql
my $dbh = $this->connect() ;
$this->throw_fatal("No database created", 1) unless $dbh ;
my $sth ;
eval
{
$sth = $dbh->prepare($sql) ;
};
$this->throw_fatal("STH prepare error $@\nQuery=$sql", 1) if $@ ;
my $sth_href = $this->_sth() ;
$sth_href->{$name} = {
'sth' => $sth,
'vals' => $values_aref,
'query' => $sql, # For debug
} ;
}
#----------------------------------------------------------------------------
=item B<sth_query($name, [@vals])>
Use a pre-prepared named sql query to return results. If the query has already been
given a set of values, then use them; otherwise use the values specified in this call
(or append the values to an insufficient list of values given when the sth was created)
=cut
sub sth_query
{
my $this = shift ;
my ($name, @vals) = @_ ;
my $sth_href = $this->_sth_record($name) ;
if ($sth_href)
{
my ($sth, $vals_aref, $query) = @$sth_href{qw/sth vals query/} ;
# TODO: expand vars?
my @args ;
foreach my $arg (@$vals_aref)
{
## process each value
if (ref($arg) eq 'SCALAR')
{
## Ref to scalar
push @args, $$arg ;
}
elsif (ref($arg) eq 'HASH')
{
## Special case handling where STH was created with an ARRAY ref or HASH ref
if ($arg->{'type'} eq 'HASH')
{
## get latest value from hash ref
push @args, $arg->{'hash'}{$arg->{'var'}} ;
}
elsif ($arg->{'type'} eq 'ARRAY')
{
## get latest value from array ref
push @args, $arg->{'array'}[$arg->{'index'}] ;
}
}
elsif (!ref($arg))
{
## Standard scalar
push @args, $arg ;
}
}
$this->_dbg_prt(["Sql::sth_query($query) : args=", \@args, "vals=", \@vals], 2) ;
# execute
eval
{
$sth->execute(@args, @vals) ;
};
if ($@)
{
my $vals = join(', ', @args, @vals) ;
$this->throw_fatal("STH \"$name\"execute error $@\nQuery=$query\nValues=$vals", 1) if $@ ;
}
}
return $this ;
}
#----------------------------------------------------------------------------
=item B<sth_query_all($name, [@vals])>
Use a pre-prepared named sql query to return results. Return all results in array.
=cut
sub sth_query_all
{
my $this = shift ;
lib/App/Framework/Feature/Sql.pm view on Meta::CPAN
'var' => $var,
} ;
}
}
}
## If sql specified, use it
if (exists($spec{'sql'}))
{
# create set of lists within this context namespace
$format = delete $spec{'sql'} ;
}
$this->_dbg_prt([" > + processing hash ...\n"], 2) ;
#$this->prt_data("spec=", \%spec) ;
## cycle through the other hash keys to produce other variables
foreach my $var (keys %spec)
{
$this->_dbg_prt([" > + + $var = $spec{$var}\n"], 2) ;
$this->_sql_setvars($var, $spec{$var}, $vars_href) ;
}
#$this->prt_data("done hash : spec=", \%spec) ;
}
elsif (!ref($spec))
{
## String
$format = $spec ;
$this->_dbg_prt([" > + spec is string : format=$format\n"], 2) ;
}
$this->_dbg_prt([" > Now: prefix=$prefix , format=$format\n"], 2) ;
## Ensure prefix is present
if ($format && $prefix)
{
# Use prefix if necessary
unless ($format =~ m/^\s*$context/i)
{
$this->_dbg_prt([" > + + Adding prefix=$prefix to format=$format\n"], 2) ;
$format = "$prefix $format" ;
}
}
# Set var
$vars_href->{$var} = $format ;
$this->_dbg_prt([" > _sql_setvars($context) - END [format=$format]\n"], 2) ;
}
#----------------------------------------------------------------------------
=item B<_sql_expand_vars($vars_href)>
Expand all the variables in the HASH ref
=cut
sub _sql_expand_vars
{
my $this = shift ;
my ($vars_href) = @_ ;
$this->_dbg_prt(["_sql_expand_vars()\n"], 2) ;
$this->_dbg_prt(["vars", \$vars_href], 2) ;
# do all vars in HASH
foreach my $var (keys %$vars_href)
{
# skip non SCALAR
next if ref($vars_href->{$var}) ;
# skip if empty
next unless $vars_href->{$var} ;
$this->_dbg_prt([" + $var\n"], 2) ;
# Keep replacing until all variables have been expanded
my $ix = index $vars_href->{$var}, '$' ;
while ($ix >= 0)
{
$this->_dbg_prt([" + + ix=$ix : $var = $vars_href->{$var}\n"], 2) ;
# At least 1 more variable to replace, so replace it
$vars_href->{$var} =~ s{
\$ # find a literal dollar sign
\{{0,1} # optional brace
(\w+) # find a "word" and store it in $1
\}{0,1} # optional brace
}{
if (defined $vars_href->{$1}) {
$vars_href->{$1}; # expand
} else {
""; # remove
}
}egx;
$ix = index $vars_href->{$var}, '$' ;
$this->_dbg_prt([" + + + $var = $vars_href->{$var}\n"], 2) ;
}
}
$this->_dbg_prt(["_sql_expand_vars - END\n"], 2) ;
}
#----------------------------------------------------------------------------
=item B<_sql_expand_arrays($vars_href)>
Expand all the array variables in the HASH ref
=cut
sub _sql_expand_arrays
{
my $this = shift ;
my ($vars_href) = @_ ;
$this->_dbg_prt(["_sql_expand_arrays()\n"], 2) ;
$this->_dbg_prt(["vars", \$vars_href], 2) ;
# do all vars in HASH
foreach my $var (keys %$vars_href)
{
$this->_dbg_prt([" + $var=", $vars_href->{$var}, "\n"], 2) ;
# skip variables that aren't named @....
next unless $var =~ /^\@/ ;
# skip if already an array
next if ref($vars_href->{$var}) eq 'ARRAY' ;
# Expand it
$this->_sql_expand_array($var, $vars_href) ;
}
$this->_dbg_prt(["_sql_expand_arrays() - END\n"], 2) ;
}
#----------------------------------------------------------------------------
=item B<_sql_expand_array($arr, $vars_href)>
Expand the named array
=cut
sub _sql_expand_array
{
my $this = shift ;
my ($array, $vars_href) = @_ ;
$this->_dbg_prt(["_sql_expand_array($array)\n"], 2) ;
# skip if already an array
unless (ref($vars_href->{$array}) eq 'ARRAY')
{
if ($vars_href->{$array})
{
# split on commas
my @arr_list = split(/[,\s+]/, $vars_href->{$array}) ;
# start array off
$vars_href->{$array} = [] ;
$this->_dbg_prt([" -- setting array\n"], 2) ;
# process them
foreach my $arr (@arr_list)
{
$this->_dbg_prt([" -- -- get $arr\n"], 2) ;
# if reference to another array, evaluate it
if ($arr =~ /^\@/)
{
$this->_dbg_prt([" -- -- -- expand $arr\n"], 2) ;
my $arr_aref = $this->_sql_expand_array($arr, $vars_href) ;
$this->_dbg_prt([" -- -- -- push array $arr=", $arr_aref, "\n"], 2) ;
# Add to list
push @{$vars_href->{$array}}, @$arr_aref if $arr_aref ;
}
else
{
$this->_dbg_prt([" -- -- -- push value ", $arr, "\n"], 2) ;
# Add to list
push @{$vars_href->{$array}}, $arr ;
}
}
}
}
$this->_dbg_prt(["ARRAY $array=", $vars_href->{$array}], 2) ;
$this->_dbg_prt(["_sql_expand_array($array) - END\n"], 2) ;
return ($vars_href->{$array}) ;
}
#----------------------------------------------------------------------------
=item B<_sth_record($name)>
Returns the saved sth information looked up from $name; returns undef otherwise
=cut
sub _sth_record
{
my $this = shift ;
my ($name) = @_ ;
# error check
if (!$name)
{
$this->dump_callstack() if $this->debug() ;
$this->throw_fatal("Attempting to find prepared statement but no name has been specified") unless $name ;
}
my $sth_href = $this->_sth() ;
if (exists($sth_href->{$name}))
{
$sth_href = $sth_href->{$name} ;
# error check
$this->throw_fatal("sth $name not created") unless $sth_href ;
}
else
{
# error
$this->throw_fatal("sth $name not created") ;
}
return $sth_href ;
}
#----------------------------------------------------------------------------
=item B<_sth_record_sth($name)>
Returns the saved sth looked up from $name; returns undef otherwise
=cut
sub _sth_record_sth
{
my $this = shift ;
my ($name) = @_ ;
my $sth ;
my $sth_href = $this->_sth_record($name) ;
if ($sth_href && exists($sth_href->{'sth'}))
( run in 1.021 second using v1.01-cache-2.11-cpan-5623c5533a1 )