File Coverage

blib/lib/RDF/Trine/Store/DBI/mysql.pm
Criterion Covered Total %
statement 18 103 17.4
branch 0 34 0.0
condition 0 3 0.0
subroutine 6 11 54.5
pod 3 3 100.0
total 27 154 17.5


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             RDF::Trine::Store::DBI::mysql - Mysql subclass of DBI store
4              
5             =head1 VERSION
6              
7             This document describes RDF::Trine::Store::DBI::mysql version 1.018
8              
9             =head1 SYNOPSIS
10              
11             use RDF::Trine::Store::DBI::mysql;
12              
13             =head1 DESCRIPTION
14              
15             =cut
16              
17             package RDF::Trine::Store::DBI::mysql;
18              
19 68     68   477 use strict;
  68         159  
  68         1729  
20 68     68   340 use warnings;
  68         150  
  68         1823  
21 68     68   318 no warnings 'redefine';
  68         148  
  68         2417  
22 68     68   444 use base qw(RDF::Trine::Store::DBI);
  68         150  
  68         6081  
23              
24 68     68   480 use Scalar::Util qw(blessed reftype refaddr);
  68         167  
  68         5802  
25              
26             our $VERSION;
27             BEGIN {
28 68     68   261 $VERSION = "1.018";
29 68         168 my $class = __PACKAGE__;
30 68         50376 $RDF::Trine::Store::STORE_CLASSES{ $class } = $VERSION;
31             }
32              
33              
34             sub _config_meta {
35             return {
36 0     0     required_keys => [qw(dsn username password name)],
37             fields => {
38             name => { description => 'Model Name', type => 'string' },
39             dsn => { description => 'DSN', type => 'string', template => 'DBI:mysql:database=[%database%]' },
40             database => { description => 'Database Name', type => 'string' },
41             username => { description => 'Username', type => 'string' },
42             password => { description => 'Password', type => 'password' },
43             driver => { description => 'Driver', type => 'string', value => 'mysql' },
44             },
45             }
46             }
47              
48             =head1 METHODS
49              
50             Beyond the methods documented below, this class inherits methods from the
51             L<RDF::Trine::Store::DBI> class.
52              
53             =over 4
54              
55             =item C<< new_with_config ( \%config ) >>
56              
57             Returns a new RDF::Trine::Store object based on the supplied configuration hashref.
58              
59             =cut
60              
61             sub new_with_config {
62 0     0 1   my $proto = shift;
63 0           my $config = shift;
64 0           $config->{storetype} = 'DBI::mysql';
65 0           return $proto->SUPER::new_with_config( $config );
66             }
67              
68             =item C<< add_statement ( $statement [, $context] ) >>
69              
70             Adds the specified C<$statement> to the underlying model.
71              
72             =cut
73              
74             sub add_statement {
75 0     0 1   my $self = shift;
76 0           my $stmt = shift;
77 0           my $context = shift;
78              
79 0           my $dbh = $self->dbh;
80             # Carp::confess unless (blessed($stmt));
81 0           my $stable = $self->statements_table;
82 0 0 0       unless (blessed($stmt) and $stmt->can('nodes')) {
83 0           Carp::confess "No statement passed to add_statement";
84             }
85 0           my @nodes = $stmt->nodes;
86 0           foreach my $n (@nodes) {
87 0           $self->_add_node( $n );
88             }
89            
90 0           my @values = map { $self->_mysql_node_hash( $_ ) } @nodes;
  0            
91 0 0         if ($stmt->isa('RDF::Trine::Statement::Quad')) {
92 0 0         if (blessed($context)) {
93 0           throw RDF::Trine::Error::MethodInvocationError -text => "add_statement cannot be called with both a quad and a context";
94             }
95 0           $context = $stmt->context;
96             } else {
97 0           my $cid = do {
98 0 0         if ($context) {
99 0           $self->_add_node( $context );
100 0           $self->_mysql_node_hash( $context );
101             } else {
102 0           0
103             }
104             };
105 0           push(@values, $cid);
106             }
107 0           my $sql = sprintf( "INSERT IGNORE INTO ${stable} (Subject, Predicate, Object, Context) VALUES (?,?,?,?)" );
108 0           my $sth = $dbh->prepare( $sql );
109 0           $sth->execute(@values);
110             }
111              
112             sub _add_node {
113 0     0     my $self = shift;
114 0           my $node = shift;
115 0           my $hash = $self->_mysql_node_hash( $node );
116 0           my $dbh = $self->dbh;
117            
118 0           my @cols;
119             my $table;
120 0           my %values;
121             # Carp::confess unless (blessed($node));
122 0 0         if ($node->is_blank) {
    0          
    0          
123 0           $table = "Bnodes";
124 0           @cols = qw(ID Name);
125 0           @values{ @cols } = ($hash, $node->blank_identifier);
126             } elsif ($node->is_resource) {
127 0           $table = "Resources";
128 0           @cols = qw(ID URI);
129 0           @values{ @cols } = ($hash, $node->uri_value);
130             } elsif ($node->isa('RDF::Trine::Node::Literal')) {
131 0           $table = "Literals";
132 0           @cols = qw(ID Value);
133 0           @values{ @cols } = ($hash, $node->literal_value);
134 0           $values{ 'Datatype' } = '';
135 0           $values{ 'Language' } = '';
136 0 0         if ($node->has_language) {
    0          
137 0           push(@cols, 'Language');
138 0           $values{ 'Language' } = $node->literal_value_language;
139             } elsif ($node->has_datatype) {
140 0           push(@cols, 'Datatype');
141 0           $values{ 'Datatype' } = $node->literal_datatype;
142             }
143             }
144            
145 0           my $sql = "INSERT IGNORE INTO ${table} (" . join(', ', @cols) . ") VALUES (" . join(',',('?')x scalar(@cols)) . ")";
146 0           my $sth = $dbh->prepare( $sql );
147 0           $sth->execute( map "$_", @values{ @cols } );
148 0           return $hash;
149             }
150              
151             =item C<< init >>
152              
153             Creates the necessary tables in the underlying database.
154              
155             =cut
156              
157             sub init {
158 0     0 1   my $self = shift;
159 0           my $dbh = $self->dbh;
160 0           my $name = $self->model_name;
161 0           my $id = RDF::Trine::Store::DBI::_mysql_hash( $name );
162 0           local($dbh->{AutoCommit}) = 0;
163 0 0         unless ($self->_table_exists("Literals")) {
164 0 0         $dbh->do( <<"END" ) || do { $dbh->rollback; return };
  0            
  0            
165             CREATE TABLE IF NOT EXISTS Literals (
166             ID bigint unsigned PRIMARY KEY,
167             Value longtext NOT NULL,
168             Language text NOT NULL,
169             Datatype text NOT NULL
170             ) CHARACTER SET utf8 COLLATE utf8_bin;
171             END
172              
173 0 0         $dbh->do( <<"END" ) || do { $dbh->rollback; return };
  0            
  0            
174             CREATE TABLE IF NOT EXISTS Resources (
175             ID bigint unsigned PRIMARY KEY,
176             URI text NOT NULL
177             );
178             END
179 0 0         $dbh->do( <<"END" ) || do { $dbh->rollback; return };
  0            
  0            
180             CREATE TABLE IF NOT EXISTS Bnodes (
181             ID bigint unsigned PRIMARY KEY,
182             Name text NOT NULL
183             );
184             END
185 0 0         $dbh->do( <<"END" ) || do { $dbh->rollback; return };
  0            
  0            
186             CREATE TABLE IF NOT EXISTS Models (
187             ID bigint unsigned PRIMARY KEY,
188             Name text NOT NULL
189             );
190             END
191 0 0         $dbh->commit or warn $dbh->errstr;
192             }
193              
194 0 0         unless ($self->_table_exists("Statements${id}")) {
195 0 0         $dbh->do( <<"END" ) || do { $dbh->rollback; return };
  0            
  0            
196             CREATE TABLE IF NOT EXISTS Statements${id} (
197             Subject bigint unsigned NOT NULL,
198             Predicate bigint unsigned NOT NULL,
199             Object bigint unsigned NOT NULL,
200             Context bigint unsigned NOT NULL DEFAULT 0,
201             PRIMARY KEY (Subject, Predicate, Object, Context)
202             );
203             END
204              
205             # $dbh->do( "DROP TABLE IF EXISTS Statements${id}" ) || do { $dbh->rollback; return };
206              
207              
208             # $dbh->do( "CREATE INDEX idx_${name}_spog ON Statements${id} (Subject,Predicate,Object,Context);", undef, $name ); # || do { $dbh->rollback; return };
209 0           $dbh->do( "CREATE INDEX `idx_${name}_pogs` ON Statements${id} (Predicate,Object,Context,Subject);", undef, $name ); # || do { $dbh->rollback; return };
210 0           $dbh->do( "CREATE INDEX `idx_${name}_opcs` ON Statements${id} (Object,Predicate,Context,Subject);", undef, $name ); # || do { $dbh->rollback; return };
211 0           $dbh->do( "CREATE INDEX `idx_${name}_cpos` ON Statements${id} (Context,Predicate,Object,Subject);", undef, $name ); # || do { $dbh->rollback; return };
212              
213             # $dbh->do( "DELETE FROM Models WHERE ID = ${id}") || do { $dbh->rollback; return };
214 0           $dbh->do( "INSERT INTO Models (ID, Name) VALUES (${id}, ?)", undef, $name );
215            
216 0           $dbh->commit;
217             }
218             }
219              
220              
221             1; # Magic true value required at end of module
222             __END__
223              
224             =back
225              
226             =head1 BUGS
227              
228             Please report any bugs or feature requests to through the GitHub web interface
229             at L<https://github.com/kasei/perlrdf/issues>.
230              
231             =head1 AUTHOR
232              
233             Gregory Todd Williams C<< <gwilliams@cpan.org> >>
234              
235             =head1 COPYRIGHT
236              
237             Copyright (c) 2006-2012 Gregory Todd Williams. This
238             program is free software; you can redistribute it and/or modify it under
239             the same terms as Perl itself.
240              
241             =cut