File Coverage

blib/lib/DBIx/OnlineDDL/Helper/SQLite.pm
Criterion Covered Total %
statement 51 51 100.0
branch 1 2 50.0
condition n/a
subroutine 20 20 100.0
pod 11 11 100.0
total 83 84 98.8


line stmt bran cond sub pod time code
1             package DBIx::OnlineDDL::Helper::SQLite;
2              
3             our $AUTHORITY = 'cpan:GSG';
4             # ABSTRACT: Private OnlineDDL helper for SQLite-specific code
5 2     2   1850 use version;
  2         4  
  2         18  
6             our $VERSION = 'v0.940.0'; # VERSION
7              
8 2     2   259 use v5.10;
  2         7  
9 2     2   12 use Moo;
  2         4  
  2         18  
10              
11             extends 'DBIx::OnlineDDL::Helper::Base';
12              
13 2     2   930 use Types::Standard qw( InstanceOf );
  2         8  
  2         38  
14              
15 2     2   1292 use Sub::Util qw( set_subname );
  2         3  
  2         121  
16              
17 2     2   12 use namespace::clean; # don't export the above
  2         3  
  2         19  
18              
19             #pod =encoding utf8
20             #pod
21             #pod =head1 DESCRIPTION
22             #pod
23             #pod This is a private helper module for any SQLite-specific code. B
24             #pod methods or attributes here are subject to change.>
25             #pod
26             #pod You should really be reading documentation for L. Or, if you want to
27             #pod create a helper module for a different RDBMS, read the docs for
28             #pod L.
29             #pod
30             #pod =cut
31              
32 82     82 1 507 sub dbms_uses_global_fk_namespace { 0 }
33 81     81 1 442 sub child_fks_need_adjusting { 0 }
34 27     27 1 96 sub null_safe_equals_op { 'IS' }
35              
36             sub current_catalog_schema {
37 28     28 1 77 my $self = shift;
38              
39 28         684 my $databases = $self->dbh->selectall_hashref('PRAGMA database_list', 'seq');
40 28         1079319 my $schema = $databases->{0}{name}; # probably 'main'
41 28         202 return (undef, $schema);
42             }
43              
44             sub insert_select_stmt {
45 27     27 1 100 my ($self, $column_list_str) = @_;
46              
47 27         751 my $dbh = $self->dbh;
48              
49 27         1073278 my $id_name_quote = $dbh->quote_identifier( $self->copy_opts->{id_name} );
50              
51 27         2888 my $orig_table_name_quote = $dbh->quote_identifier($self->table_name);
52 27         2149 my $new_table_name_quote = $dbh->quote_identifier($self->new_table_name);
53              
54             # Use INSERT OR IGNORE to ignore dupe key errors
55 27         2101 return join("\n",
56             "INSERT OR IGNORE INTO $new_table_name_quote",
57             " ($column_list_str)",
58             "SELECT",
59             " $column_list_str",
60             "FROM $orig_table_name_quote",
61             "WHERE $id_name_quote BETWEEN ? AND ?",
62             );
63             }
64              
65             sub post_connection_stmts {
66 28     28 1 142 my $self = shift;
67              
68 28         529 my $db_timeouts = $self->db_timeouts;
69             my @stmts = (
70             # See FK comment in MySQL module. FKs in SQLite are a per-connection enabled
71             # feature, so this is always a "session" command.
72             'PRAGMA foreign_keys = OFF',
73              
74             # DB timeouts
75 28         937 'PRAGMA busy_timeout = '.int($db_timeouts->{lock_file} * 1_000), # busy_timeout uses ms
76             );
77              
78             # SQLite version 3.25.0 fixes table renames to also rename references to the table,
79             # ie: child FKs. Since SQLite doesn't yet have an DDL statement for renaming the FKs
80             # back to the old name, setting this PRAGMA variable is the only option.
81             #
82             # Also, while this change was introduced in 3.25.0, it seems to only manifest itself
83             # when the driver reports version 3.26.0, possibly due to how their production
84             # releases work.
85 28 50       151 push @stmts, 'PRAGMA legacy_alter_table = ON' if $self->mmver >= 3.026;
86              
87 28         184 return @stmts;
88             }
89              
90             sub is_error_retryable {
91 3     3 1 42 my ($self, $error) = @_;
92              
93             # Disable /x flag to allow for whitespace within string, but turn it on for newlines
94             # and comments.
95 3         10 return $error =~ m<
96             # Locks
97             (?-x:database( table)? is locked)|
98              
99             # Connections
100             (?-x:attempt to [\w\s]+ on inactive database handle)|
101              
102             # Queries
103             (?-x:query aborted)|
104             (?-x:interrupted)
105             >xi;
106             }
107              
108             sub create_table_sql {
109 56     56 1 20014 my ($self, $table_name) = @_;
110              
111 56         142 my $create_sql;
112             $self->dbh_runner(run => set_subname '_create_table_sql', sub {
113 56     56   480 ($create_sql) = $_->selectrow_array('SELECT sql FROM sqlite_master WHERE name = ?', undef, $table_name);
114 56         1665 });
115              
116 56         369 return $create_sql;
117             }
118              
119             # Keep Base->rename_fks_in_table_sql (not used)
120              
121             sub has_conflicting_triggers_on_table {
122 28     28 1 90 my ($self, $table_name) = @_;
123              
124             return $self->dbh_runner(run => set_subname '_has_triggers_on_table', sub {
125 28     28   239 $_->selectrow_array(
126             'SELECT name FROM sqlite_master WHERE type = ? AND tbl_name = ?',
127             undef, 'trigger', $table_name
128             );
129 28         983 });
130             }
131              
132             sub find_new_trigger_identifier {
133 84     84 1 454 my ($self, $trigger_name) = @_;
134              
135             return $self->find_new_identifier(
136             $trigger_name => sub {
137 84     84   727 $_[0]->selectrow_array(
138             'SELECT name FROM sqlite_master WHERE type = ? AND name = ?',
139             undef, 'trigger', $_[1]
140             );
141             },
142 84         2164 );
143             }
144              
145             # Keep Base->modify_trigger_dml_stmts (nothing changed)
146              
147             sub analyze_table {
148 27     27 1 1020 my ($self, $table_name) = @_;
149 27         456 my $table_name_quote = $self->dbh->quote_identifier($table_name);
150 27         2209371 $self->dbh_runner_do("ANALYZE $table_name_quote");
151             }
152              
153             # Keep Base->swap_tables (has transactional DDL)
154              
155             # Keep the other FK methods (not used)
156              
157             1;
158              
159             __END__