File Coverage

blib/lib/Filter/SQL.pm
Criterion Covered Total %
statement 68 101 67.3
branch 25 56 44.6
condition n/a
subroutine 11 16 68.7
pod 2 9 22.2
total 106 182 58.2


line stmt bran cond sub pod time code
1             package Filter::SQL;
2              
3 3     3   2178 use strict;
  3         5  
  3         109  
4 3     3   17 use warnings;
  3         5  
  3         81  
5 3     3   27 use Carp;
  3         4  
  3         259  
6 3     3   570039 use DBI;
  3         59167  
  3         295  
7 3     3   110245 use List::MoreUtils qw(uniq);
  3         4648  
  3         276  
8 3     3   21 use base qw(Exporter);
  3         8  
  3         368  
9              
10 3     3   14218 use Filter::Simple;
  3         335236  
  3         157  
11              
12             our %EXPORT_TAGS = (
13             dbh => [ qw/dbh/ ],
14             mysql => [ qw/mysql_insert_id/ ],
15             );
16             $EXPORT_TAGS{all} = [ uniq map { @$_ } values %EXPORT_TAGS ];
17             our @EXPORT_OK = @{$EXPORT_TAGS{all}};
18             our $VERSION = '0.10';
19              
20             FILTER_ONLY
21             code => sub {
22             s{(EXEC\s+(?:\S+)|SELECT(?:\s+ROW|)(?:\s+AS\s+HASH|)|INSERT|UPDATE|DELETE|REPLACE)\s+([^;]*);}{'Filter::SQL->' . Filter::SQL::to_func($1) . quote_vars($2) . ")"}egm;
23             # print STDERR $_; $_;
24             };
25              
26             sub to_func {
27 36     36 0 62 my $op = shift;
28 36         49 $op = uc $op;
29 36 100       137 if ($op =~ /^EXEC\s+/) {
    100          
30 5         43 return "sql_prepare_exec('$' ";
31             } elsif ($op =~ /^SELECT(\s+ROW|)(\s+AS\s+HASH|)/) {
32 23 100       54 my $as_hash = $2 ? '1' : 'undef';
33 23 100       51 if ($1) {
34 21         74 return "sql_selectrow($as_hash, 'SELECT ";
35             } else {
36 2         9 return "sql_selectall($as_hash, 'SELECT ";
37             }
38             } else {
39 8         26 return "sql_prepare_exec('$op ";
40             }
41             }
42              
43             sub quote_vars {
44 36     36 0 62 my $src = shift;
45 36         43 my $ph = $Filter::Simple::placeholder;
46 36         127 $src =~ s/$ph/recover_quotelike($&, $1)/egm;
  15         27  
47 36         44 my $out;
48             my @params;
49 36         341 while ($src =~ /($ph)|(\$|\{)/) {
50 16         23 $out .= $`;
51 16         32 $src = $';
52 16 100       26 if ($1) {
53 9         12 $out .= '?';
54 9         45 push @params, $1;
55             } else {
56 7 100       23 my ($var, $depth) = ($&, $& eq '$' ? 0 : 1);
57 7         19 while ($src ne '') {
58 15 100       23 if ($depth == 0) {
59             last
60 11 100       38 unless $src =~ /^(?:([A-Za-z0-9_]+(?:->|))|([\[\{\(]))/;
61 8         14 $src = $';
62 8 100       16 if ($1) {
63 5         15 $var .= $1;
64             } else {
65 3         5 $var .= $2;
66 3         6 $depth++;
67             }
68             } else {
69 4 50       14 last unless $src =~ /([\]\}\)](?:->|))/;
70 4         6 $src = $';
71 4         8 $var .= "$`$1";
72 4         7 $depth--;
73             }
74             }
75 7         29 $var =~ s/^{(.*)}$/$1/m;
76 7         9 $out .= '?';
77 7         38 push @params, $var;
78             }
79             }
80 36         58 $out .= $src;
81 36         281 join ',', "$out'", @params;
82             }
83              
84             sub recover_quotelike {
85 15     15 0 65 my ($ph, $n) = ($_[0], unpack('N', $_[1]));
86 15         17 my $s = ${$Filter::Simple::components[$n]};
  15         40  
87 15 100       74 $s =~ /^[\'\"]/ ? $ph : $s;
88             }
89              
90             my $dbh;
91              
92             if (defined $ENV{FILTER_SQL_DBI}) {
93             $dbh = sub {
94             # self rewrite and return
95             $dbh = DBI->connect(
96             $ENV{FILTER_SQL_DBI},
97             $ENV{FILTER_SQL_DBI_USERNAME} || undef,
98             $ENV{FILTER_SQL_DBI_PASSWORD} || undef,
99             ) or carp DBI->errstr;
100             };
101             }
102              
103             sub dbh {
104 5     5 1 2008 my $klass = shift;
105 5 100       18 if (@_) {
106 2         55 $dbh = shift;
107 2         9 return; # returns undef
108             }
109 3 100       93 ref $dbh eq 'CODE' ? $dbh->() : $dbh;
110             }
111              
112             sub sql_prepare_exec {
113 0     0 0   my ($klass, $sql, @params) = @_;
114 0           my $pe = Filter::SQL->dbh->{PrintError};
115 0           local Filter::SQL->dbh->{PrintError} = undef;
116 0           my $sth = Filter::SQL->dbh->prepare($sql);
117 0 0         unless ($sth) {
118 0 0         carp Filter::SQL->dbh->errstr if $pe;
119 0           return;
120             }
121 0 0         unless ($sth->execute(@params)) {
122 0 0         carp Filter::SQL->dbh->errstr if $pe;
123 0           return;
124             }
125 0           $sth;
126             }
127              
128             sub sql_selectall {
129 0     0 0   my ($klass, $as_hash, $sql, @params) = @_;
130 0           my $pe = Filter::SQL->dbh->{PrintError};
131 0           local Filter::SQL->dbh->{PrintError} = undef;
132 0 0         my $rows = Filter::SQL->dbh->selectall_arrayref(
133             $sql,
134             $as_hash ? { Slice => {} } : {},
135             @params,
136             );
137 0 0         unless ($rows) {
138 0 0         carp Filter::SQL->dbh->errstr if $pe;
139 0           return;
140             }
141 0 0         wantarray ? @$rows : $rows->[0];
142             }
143              
144             sub sql_selectrow {
145 0     0 0   my ($klass, $as_hash, $sql, @params) = @_;
146 0           my $pe = Filter::SQL->dbh->{PrintError};
147 0           local Filter::SQL->dbh->{PrintError} = undef;
148 0 0         my $rows = Filter::SQL->dbh->selectall_arrayref(
149             $sql,
150             $as_hash ? { Slice => {} } : {},
151             @params,
152             );
153 0 0         unless ($rows) {
154 0 0         carp Filter::SQL->dbh->errstr if $pe;
155 0           return;
156             }
157 0 0         return @$rows ? %{$rows->[0]} : ()
  0 0          
158             if $as_hash;
159 0 0         @$rows ? wantarray ? @{$rows->[0]} : $rows->[0][0] : ();
  0 0          
160             }
161              
162             sub quote {
163 0     0 0   my ($klass, $v) = @_;
164 0           Filter::SQL->dbh->quote($v);
165             }
166              
167             sub mysql_insert_id {
168 0     0 1   Filter::SQL->dbh->{mysql_insertid};
169             };
170              
171             1;
172              
173             __END__