File Coverage

blib/lib/CHI/Driver/DBI.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package CHI::Driver::DBI;
2              
3 1     1   46378 use strict;
  1         3  
  1         40  
4 1     1   5 use warnings;
  1         2  
  1         28  
5              
6 1     1   1282 use DBI::Const::GetInfoType;
  1         11602  
  1         243  
7 1     1   712 use Moose;
  0            
  0            
8             use Moose::Util::TypeConstraints;
9             use Carp qw(croak);
10              
11             our $VERSION = '1.24';
12              
13             extends 'CHI::Driver';
14              
15             my $type = "CHI::Driver::DBI";
16              
17             subtype "$type.DBIHandleGenerator" => as 'CodeRef';
18             subtype "$type.DBIXConnector" => as 'DBIx::Connector';
19             subtype "$type.DBIHandle" => as 'DBI::db';
20              
21             coerce "$type.DBIHandleGenerator" => from "$type.DBIXConnector" => via {
22             my $dbixconn = $_;
23             sub { $dbixconn->dbh }
24             };
25             coerce "$type.DBIHandleGenerator" => from "$type.DBIHandle" => via {
26             my $dbh = $_;
27             sub { $dbh }
28             };
29              
30             has 'db_name' => ( is => 'rw', isa => 'Str' );
31             has 'dbh' => ( is => 'ro', isa => "$type.DBIHandleGenerator", coerce => 1 );
32             has 'dbh_ro' => ( is => 'ro', isa => "$type.DBIHandleGenerator", predicate => 'has_dbh_ro', coerce => 1 );
33             has 'sql_strings' => ( is => 'rw', isa => 'HashRef', lazy_build => 1 );
34             has 'table_prefix' => ( is => 'rw', isa => 'Str', default => 'chi_' );
35              
36             __PACKAGE__->meta->make_immutable;
37              
38             sub BUILD {
39             my ( $self, $args ) = @_;
40              
41             my $dbh = $self->dbh->();
42              
43             $self->db_name( $dbh->get_info( $GetInfoType{SQL_DBMS_NAME} ) );
44             $self->sql_strings;
45              
46             if ( $args->{create_table} ) {
47             $dbh->do( $self->sql_strings->{create} )
48             or croak $dbh->errstr;
49             }
50              
51             return;
52             }
53              
54             sub _table {
55             my ( $self, ) = @_;
56              
57             return $self->table_prefix() . $self->namespace();
58             }
59              
60             sub _build_sql_strings {
61             my ( $self, ) = @_;
62              
63             my $dbh = $self->dbh->();
64             my $table = $dbh->quote_identifier( $self->_table );
65             my $value = $dbh->quote_identifier('value');
66             my $key = $dbh->quote_identifier('key');
67              
68             my $strings = {
69             fetch => "SELECT $value FROM $table WHERE $key = ?",
70             store => "INSERT INTO $table ( $key, $value ) VALUES ( ?, ? )",
71             store2 => "UPDATE $table SET $value = ? WHERE $key = ?",
72             remove => "DELETE FROM $table WHERE $key = ?",
73             clear => "DELETE FROM $table",
74             get_keys => "SELECT DISTINCT $key FROM $table",
75             create => "CREATE TABLE IF NOT EXISTS $table ("
76             . " $key VARCHAR( 300 ), $value TEXT,"
77             . " PRIMARY KEY ( $key ) )",
78             };
79              
80             if ( $self->db_name eq 'MySQL' ) {
81             $strings->{store} =
82             "INSERT INTO $table"
83             . " ( $key, $value )"
84             . " VALUES ( ?, ? )"
85             . " ON DUPLICATE KEY UPDATE $value=VALUES($value)";
86             delete $strings->{store2};
87             }
88             elsif ( $self->db_name eq 'SQLite' ) {
89             $strings->{store} =
90             "INSERT OR REPLACE INTO $table"
91             . " ( $key, $value )"
92             . " values ( ?, ? )";
93             delete $strings->{store2};
94             }
95             elsif ( $self->db_name eq 'PostgreSQL' ) {
96             $strings->{create} =
97             "CREATE TABLE IF NOT EXISTS $table ("
98             . " $key BYTEA, $value BYTEA,"
99             . " PRIMARY KEY ( $key ) )";
100             }
101              
102             return $strings;
103             }
104              
105             sub fetch {
106             my ( $self, $key, ) = @_;
107              
108             my $dbh = $self->has_dbh_ro ? $self->dbh_ro->() : $self->dbh->();
109             my $sth = $dbh->prepare_cached( $self->sql_strings->{fetch} )
110             or croak $dbh->errstr;
111             if ( $self->db_name eq 'PostgreSQL' ) {
112             $sth->bind_param( 1, undef, { pg_type => DBD::Pg::PG_BYTEA() } );
113             }
114             $sth->execute($key) or croak $sth->errstr;
115             my $results = $sth->fetchall_arrayref;
116              
117             return $results->[0]->[0];
118             }
119              
120             sub store {
121             my ( $self, $key, $data, ) = @_;
122              
123             my $dbh = $self->dbh->();
124             my $sth = $dbh->prepare_cached( $self->sql_strings->{store} );
125             if ( $self->db_name eq 'PostgreSQL' ) {
126             $sth->bind_param( 1, undef, { pg_type => DBD::Pg::PG_BYTEA() } );
127             $sth->bind_param( 2, undef, { pg_type => DBD::Pg::PG_BYTEA() } );
128             }
129             if ( not $sth->execute( $key, $data ) ) {
130             if ( $self->sql_strings->{store2} ) {
131             my $sth = $dbh->prepare_cached( $self->sql_strings->{store2} )
132             or croak $dbh->errstr;
133             if ( $self->db_name eq 'PostgreSQL' ) {
134             $sth->bind_param( 1, undef,
135             { pg_type => DBD::Pg::PG_BYTEA() } );
136             $sth->bind_param( 2, undef,
137             { pg_type => DBD::Pg::PG_BYTEA() } );
138             }
139             $sth->execute( $data, $key )
140             or croak $sth->errstr;
141             }
142             else {
143             croak $sth->errstr;
144             }
145             }
146             $sth->finish;
147              
148             return;
149             }
150              
151             sub remove {
152             my ( $self, $key, ) = @_;
153              
154             my $dbh = $self->dbh->();
155             my $sth = $dbh->prepare_cached( $self->sql_strings->{remove} )
156             or croak $dbh->errstr;
157             if ( $self->db_name eq 'PostgreSQL' ) {
158             $sth->bind_param( 1, undef, { pg_type => DBD::Pg::PG_BYTEA() } );
159             }
160             $sth->execute($key) or croak $sth->errstr;
161             $sth->finish;
162              
163             return;
164             }
165              
166             sub clear {
167             my ( $self, $key, ) = @_;
168              
169             my $dbh = $self->dbh->();
170             my $sth = $dbh->prepare_cached( $self->sql_strings->{clear} )
171             or croak $dbh->errstr;
172             $sth->execute() or croak $sth->errstr;
173             $sth->finish();
174              
175             return;
176             }
177              
178             sub get_keys {
179             my ( $self, ) = @_;
180              
181             my $dbh = $self->has_dbh_ro ? $self->dbh_ro->() : $self->dbh->();
182             my $sth = $dbh->prepare_cached( $self->sql_strings->{get_keys} )
183             or croak $dbh->errstr;
184             $sth->execute() or croak $sth->errstr;
185             my $results = $sth->fetchall_arrayref( [0] );
186             $_ = $_->[0] for @{$results};
187              
188             return @{$results};
189             }
190              
191             sub get_namespaces { croak 'not supported' }
192              
193             # TODO: For pg see "upsert" - http://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#PLPGSQL-UPSERT-EXAMPLE
194              
195             1;
196              
197             __END__
198              
199             =pod
200              
201             =head1 NAME
202              
203             CHI::Driver::DBI - Use DBI for cache storage
204              
205             =head1 VERSION
206              
207             version 1.27
208              
209             =head1 SYNOPSIS
210              
211             use CHI;
212            
213             # Supply a DBI handle
214             #
215             my $cache = CHI->new( driver => 'DBI', dbh => DBI->connect(...) );
216            
217             # or a DBIx::Connector
218             #
219             my $cache = CHI->new( driver => 'DBI', dbh => DBIx::Connector->new(...) );
220            
221             # or code that generates a DBI handle
222             #
223             my $cache = CHI->new( driver => 'DBI', dbh => sub { ...; return $dbh } );
224              
225             =head1 DESCRIPTION
226              
227             This driver uses a database table to store the cache. The newest versions of
228             MySQL and SQLite work are known to work. Other RDBMSes should work.
229              
230             Why cache things in a database? Isn't the database what people are trying to
231             avoid with caches? This is often true, but a simple primary key lookup is
232             extremely fast in many databases and this provides a shared cache that can be
233             used when less reliable storage like memcached is not appropriate. Also, the
234             speed of simple lookups on MySQL when accessed over a local socket is very hard
235             to beat. DBI is fast.
236              
237             =for readme stop
238              
239             =head1 SCHEMA
240              
241             Each namespace requires a table like this:
242              
243             CREATE TABLE chi_<namespace> (
244             `key` VARCHAR(...),
245             `value` TEXT,
246             PRIMARY KEY (`key`)
247             )
248              
249             The size of the key column depends on how large you want keys to be and may be
250             limited by the maximum size of an indexed column in your database.
251              
252             The driver will try to create an appropriate table for you if you pass
253             C<create_table> to the constructor.
254              
255             =head1 CONSTRUCTOR PARAMETERS
256              
257             =over
258              
259             =item create_table
260              
261             Boolean. If true, attempt to create the database table if it does not already
262             exist. Defaults to false.
263              
264             =item namespace
265              
266             The namespace you pass in will be appended to the C<table_prefix> to form the
267             table name. That means that if you don't specify a namespace or table_prefix
268             the cache will be stored in a table called C<chi_Default>.
269              
270             =item table_prefix
271              
272             This is the prefix that is used when building a table name. If you want to
273             just use the namespace as a literal table name, set this to the empty string.
274             Defaults to C<chi_>.
275              
276             =item dbh
277              
278             The main, or rw, DBI handle used to communicate with the db. If a dbh_ro handle
279             is defined then this handle will only be used for writing.
280              
281             You may pass this handle, and dbh_ro below, in one of three forms:
282              
283             =over
284              
285             =item *
286              
287             a regular DBI handle
288              
289             =item *
290              
291             a L<DBIx::Connector|DBIx::Connector> object
292              
293             =item *
294              
295             a code reference that will be called each time and is expected to return a DBI
296             handle, e.g.
297              
298             sub { My::Rose::DB->new->dbh }
299              
300             =back
301              
302             The last two options are valuable if your CHI object is going to live for
303             enough time that a single DBI handle might time out, etc.
304              
305             =item dbh_ro
306              
307             The optional DBI handle used for read-only operations. This is to support
308             master/slave RDBMS setups.
309              
310             =back
311              
312             =for readme continue
313              
314             =head1 AUTHORS
315              
316             Original version by Justin DeVuyst and Perrin Harkins. Currently maintained by
317             Jonathan Swartz.
318              
319             =head1 COPYRIGHT AND LICENSE
320              
321             This software is copyright (c) 2011 by Justin DeVuyst.
322              
323             This is free software; you can redistribute it and/or modify it under
324             the same terms as the Perl 5 programming language system itself.
325              
326             =cut