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   1381 use version;
  2         4  
  2         16  
6             our $VERSION = 'v1.0.0'; # VERSION
7              
8 2     2   158 use v5.10;
  2         5  
9 2     2   9 use Moo;
  2         3  
  2         13  
10              
11             extends 'DBIx::OnlineDDL::Helper::Base';
12              
13 2     2   607 use Types::Standard qw( InstanceOf );
  2         4  
  2         43  
14              
15 2     2   1104 use Sub::Util qw( set_subname );
  2         3  
  2         106  
16              
17 2     2   10 use namespace::clean; # don't export the above
  2         3  
  2         16  
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 414 sub dbms_uses_global_fk_namespace { 0 }
33 81     81 1 354 sub child_fks_need_adjusting { 0 }
34 27     27 1 75 sub null_safe_equals_op { 'IS' }
35              
36             sub current_catalog_schema {
37 28     28 1 118 my $self = shift;
38              
39 28         487 my $databases = $self->dbh->selectall_hashref('PRAGMA database_list', 'seq');
40 28         775538 my $schema = $databases->{0}{name}; # probably 'main'
41 28         169 return (undef, $schema);
42             }
43              
44             sub insert_select_stmt {
45 27     27 1 77 my ($self, $column_list_str) = @_;
46              
47 27         677 my $dbh = $self->dbh;
48              
49 27         763183 my $id_name_quote = $dbh->quote_identifier( $self->copy_opts->{id_name} );
50              
51 27         2447 my $orig_table_name_quote = $dbh->quote_identifier($self->table_name);
52 27         2060 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         1814 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 82 my $self = shift;
67              
68 28         435 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         863 '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       146 push @stmts, 'PRAGMA legacy_alter_table = ON' if $self->mmver >= 3.026;
86              
87 28         167 return @stmts;
88             }
89              
90             sub is_error_retryable {
91 3     3 1 37 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 13970 my ($self, $table_name) = @_;
110              
111 56         159 my $create_sql;
112             $self->dbh_runner(run => set_subname '_create_table_sql', sub {
113 56     56   522 ($create_sql) = $_->selectrow_array('SELECT sql FROM sqlite_master WHERE name = ?', undef, $table_name);
114 56         1483 });
115              
116 56         278 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 88 my ($self, $table_name) = @_;
123              
124             return $self->dbh_runner(run => set_subname '_has_triggers_on_table', sub {
125 28     28   282 $_->selectrow_array(
126             'SELECT name FROM sqlite_master WHERE type = ? AND tbl_name = ?',
127             undef, 'trigger', $table_name
128             );
129 28         853 });
130             }
131              
132             sub find_new_trigger_identifier {
133 84     84 1 348 my ($self, $trigger_name) = @_;
134              
135             return $self->find_new_identifier(
136             $trigger_name => sub {
137 84     84   612 $_[0]->selectrow_array(
138             'SELECT name FROM sqlite_master WHERE type = ? AND name = ?',
139             undef, 'trigger', $_[1]
140             );
141             },
142 84         1999 );
143             }
144              
145             # Keep Base->modify_trigger_dml_stmts (nothing changed)
146              
147             sub analyze_table {
148 27     27 1 965 my ($self, $table_name) = @_;
149 27         480 my $table_name_quote = $self->dbh->quote_identifier($table_name);
150 27         872909 $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__