File Coverage

blib/lib/DBIx/OnlineDDL/Helper/SQLite.pm
Criterion Covered Total %
statement 56 58 96.5
branch 1 2 50.0
condition 1 2 50.0
subroutine 21 22 95.4
pod 11 11 100.0
total 90 95 94.7


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