| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package SQL::Translator::Producer::SQLite; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
SQL::Translator::Producer::SQLite - SQLite producer for SQL::Translator |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
use SQL::Translator; |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
my $t = SQL::Translator->new( parser => '...', producer => 'SQLite' ); |
|
12
|
|
|
|
|
|
|
$t->translate; |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
This module will produce text output of the schema suitable for SQLite. |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=cut |
|
19
|
|
|
|
|
|
|
|
|
20
|
9
|
|
|
9
|
|
5064
|
use strict; |
|
|
9
|
|
|
|
|
22
|
|
|
|
9
|
|
|
|
|
318
|
|
|
21
|
9
|
|
|
9
|
|
49
|
use warnings; |
|
|
9
|
|
|
|
|
23
|
|
|
|
9
|
|
|
|
|
254
|
|
|
22
|
9
|
|
|
9
|
|
1459
|
use Data::Dumper; |
|
|
9
|
|
|
|
|
18246
|
|
|
|
9
|
|
|
|
|
570
|
|
|
23
|
9
|
|
|
9
|
|
107
|
use SQL::Translator::Schema::Constants; |
|
|
9
|
|
|
|
|
31
|
|
|
|
9
|
|
|
|
|
735
|
|
|
24
|
9
|
|
|
9
|
|
122
|
use SQL::Translator::Utils qw(debug header_comment parse_dbms_version batch_alter_table_statements); |
|
|
9
|
|
|
|
|
18
|
|
|
|
9
|
|
|
|
|
528
|
|
|
25
|
9
|
|
|
9
|
|
4044
|
use SQL::Translator::Generator::DDL::SQLite; |
|
|
9
|
|
|
|
|
33
|
|
|
|
9
|
|
|
|
|
28936
|
|
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
our ( $DEBUG, $WARN ); |
|
28
|
|
|
|
|
|
|
our $VERSION = '1.62'; |
|
29
|
|
|
|
|
|
|
$DEBUG = 0 unless defined $DEBUG; |
|
30
|
|
|
|
|
|
|
$WARN = 0 unless defined $WARN; |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
our $max_id_length = 30; |
|
33
|
|
|
|
|
|
|
my %global_names; |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# HIDEOUS TEMPORARY DEFAULT WITHOUT QUOTING! |
|
36
|
|
|
|
|
|
|
our $NO_QUOTES = 1; |
|
37
|
|
|
|
|
|
|
{ |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
my ($quoting_generator, $nonquoting_generator); |
|
40
|
|
|
|
|
|
|
sub _generator { |
|
41
|
368
|
100
|
66
|
368
|
|
3192
|
$NO_QUOTES |
|
|
|
|
66
|
|
|
|
|
|
42
|
|
|
|
|
|
|
? $nonquoting_generator ||= SQL::Translator::Generator::DDL::SQLite->new(quote_chars => []) |
|
43
|
|
|
|
|
|
|
: $quoting_generator ||= SQL::Translator::Generator::DDL::SQLite->new |
|
44
|
|
|
|
|
|
|
} |
|
45
|
|
|
|
|
|
|
} |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub produce { |
|
48
|
10
|
|
|
10
|
0
|
26
|
my $translator = shift; |
|
49
|
10
|
|
|
|
|
43
|
local $DEBUG = $translator->debug; |
|
50
|
10
|
|
|
|
|
263
|
local $WARN = $translator->show_warnings; |
|
51
|
10
|
|
|
|
|
241
|
my $no_comments = $translator->no_comments; |
|
52
|
10
|
|
|
|
|
232
|
my $add_drop_table = $translator->add_drop_table; |
|
53
|
10
|
|
|
|
|
239
|
my $schema = $translator->schema; |
|
54
|
10
|
|
|
|
|
264
|
my $producer_args = $translator->producer_args; |
|
55
|
|
|
|
|
|
|
my $sqlite_version = parse_dbms_version( |
|
56
|
10
|
|
|
|
|
69
|
$producer_args->{sqlite_version}, 'perl' |
|
57
|
|
|
|
|
|
|
); |
|
58
|
10
|
|
|
|
|
32
|
my $no_txn = $producer_args->{no_transaction}; |
|
59
|
|
|
|
|
|
|
|
|
60
|
10
|
|
|
|
|
61
|
debug("PKG: Beginning production\n"); |
|
61
|
|
|
|
|
|
|
|
|
62
|
10
|
|
|
|
|
33
|
%global_names = (); #reset |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# only quote if quotes were requested for real |
|
65
|
|
|
|
|
|
|
# 0E0 indicates "the default of true" was assumed |
|
66
|
10
|
100
|
66
|
|
|
236
|
local $NO_QUOTES = 0 |
|
67
|
|
|
|
|
|
|
if $translator->quote_identifiers and $translator->quote_identifiers ne '0E0'; |
|
68
|
|
|
|
|
|
|
|
|
69
|
10
|
|
|
|
|
86
|
my $head; |
|
70
|
10
|
100
|
|
|
|
71
|
$head = (header_comment() . "\n") unless $no_comments; |
|
71
|
|
|
|
|
|
|
|
|
72
|
10
|
|
|
|
|
31
|
my @create = (); |
|
73
|
|
|
|
|
|
|
|
|
74
|
10
|
100
|
|
|
|
42
|
push @create, "BEGIN TRANSACTION" unless $no_txn; |
|
75
|
|
|
|
|
|
|
|
|
76
|
10
|
|
|
|
|
57
|
for my $table ( $schema->get_tables ) { |
|
77
|
17
|
|
|
|
|
137
|
push @create, create_table($table, { no_comments => $no_comments, |
|
78
|
|
|
|
|
|
|
sqlite_version => $sqlite_version, |
|
79
|
|
|
|
|
|
|
add_drop_table => $add_drop_table,}); |
|
80
|
|
|
|
|
|
|
} |
|
81
|
|
|
|
|
|
|
|
|
82
|
10
|
|
|
|
|
65
|
for my $view ( $schema->get_views ) { |
|
83
|
4
|
|
|
|
|
28
|
push @create, create_view($view, { |
|
84
|
|
|
|
|
|
|
add_drop_view => $add_drop_table, |
|
85
|
|
|
|
|
|
|
no_comments => $no_comments, |
|
86
|
|
|
|
|
|
|
}); |
|
87
|
|
|
|
|
|
|
} |
|
88
|
|
|
|
|
|
|
|
|
89
|
10
|
|
|
|
|
61
|
for my $trigger ( $schema->get_triggers ) { |
|
90
|
11
|
|
|
|
|
55
|
push @create, create_trigger($trigger, { |
|
91
|
|
|
|
|
|
|
add_drop_trigger => $add_drop_table, |
|
92
|
|
|
|
|
|
|
no_comments => $no_comments, |
|
93
|
|
|
|
|
|
|
}); |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
|
|
96
|
10
|
100
|
|
|
|
53
|
push @create, "COMMIT" unless $no_txn; |
|
97
|
|
|
|
|
|
|
|
|
98
|
10
|
100
|
|
|
|
35
|
if (wantarray) { |
|
99
|
3
|
|
33
|
|
|
32
|
return ($head||(), @create); |
|
100
|
|
|
|
|
|
|
} else { |
|
101
|
7
|
|
66
|
|
|
295
|
return join ('', |
|
102
|
|
|
|
|
|
|
$head||(), |
|
103
|
|
|
|
|
|
|
join(";\n\n", @create ), |
|
104
|
|
|
|
|
|
|
";\n", |
|
105
|
|
|
|
|
|
|
); |
|
106
|
|
|
|
|
|
|
} |
|
107
|
|
|
|
|
|
|
} |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub mk_name { |
|
110
|
28
|
|
|
28
|
0
|
186
|
my ($name, $scope, $critical) = @_; |
|
111
|
|
|
|
|
|
|
|
|
112
|
28
|
|
50
|
|
|
129
|
$scope ||= \%global_names; |
|
113
|
28
|
100
|
|
|
|
114
|
if ( my $prev = $scope->{ $name } ) { |
|
114
|
5
|
|
|
|
|
17
|
my $name_orig = $name; |
|
115
|
5
|
|
|
|
|
27
|
$name .= sprintf( "%02d", ++$prev ); |
|
116
|
5
|
50
|
|
|
|
22
|
substr($name, $max_id_length - 3) = "00" |
|
117
|
|
|
|
|
|
|
if length( $name ) > $max_id_length; |
|
118
|
|
|
|
|
|
|
|
|
119
|
5
|
50
|
|
|
|
23
|
warn "The name '$name_orig' has been changed to ", |
|
120
|
|
|
|
|
|
|
"'$name' to make it unique.\n" if $WARN; |
|
121
|
|
|
|
|
|
|
|
|
122
|
5
|
|
|
|
|
14
|
$scope->{ $name_orig }++; |
|
123
|
|
|
|
|
|
|
} |
|
124
|
|
|
|
|
|
|
|
|
125
|
28
|
|
|
|
|
84
|
$scope->{ $name }++; |
|
126
|
28
|
|
|
|
|
75
|
return _generator()->quote($name); |
|
127
|
|
|
|
|
|
|
} |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub create_view { |
|
130
|
8
|
|
|
8
|
0
|
166
|
my ($view, $options) = @_; |
|
131
|
8
|
|
|
|
|
23
|
my $add_drop_view = $options->{add_drop_view}; |
|
132
|
|
|
|
|
|
|
|
|
133
|
8
|
|
|
|
|
29
|
my $view_name = _generator()->quote($view->name); |
|
134
|
8
|
|
|
|
|
45
|
$global_names{$view->name} = 1; |
|
135
|
|
|
|
|
|
|
|
|
136
|
8
|
|
|
|
|
53
|
debug("PKG: Looking at view '${view_name}'\n"); |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# Header. Should this look like what mysqldump produces? |
|
139
|
8
|
|
|
|
|
213
|
my $extra = $view->extra; |
|
140
|
8
|
|
|
|
|
23
|
my @create; |
|
141
|
8
|
100
|
|
|
|
45
|
push @create, "DROP VIEW IF EXISTS $view_name" if $add_drop_view; |
|
142
|
|
|
|
|
|
|
|
|
143
|
8
|
|
|
|
|
21
|
my $create_view = 'CREATE'; |
|
144
|
8
|
50
|
66
|
|
|
41
|
$create_view .= " TEMPORARY" if exists($extra->{temporary}) && $extra->{temporary}; |
|
145
|
8
|
|
|
|
|
23
|
$create_view .= ' VIEW'; |
|
146
|
8
|
50
|
66
|
|
|
38
|
$create_view .= " IF NOT EXISTS" if exists($extra->{if_not_exists}) && $extra->{if_not_exists}; |
|
147
|
8
|
|
|
|
|
21
|
$create_view .= " ${view_name}"; |
|
148
|
|
|
|
|
|
|
|
|
149
|
8
|
50
|
|
|
|
42
|
if( my $sql = $view->sql ){ |
|
150
|
8
|
|
|
|
|
28
|
$create_view .= " AS\n ${sql}"; |
|
151
|
|
|
|
|
|
|
} |
|
152
|
8
|
|
|
|
|
20
|
push @create, $create_view; |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
# Tack the comment onto the first statement. |
|
155
|
8
|
50
|
|
|
|
32
|
unless ($options->{no_comments}) { |
|
156
|
0
|
|
|
|
|
0
|
$create[0] = "--\n-- View: ${view_name}\n--\n" . $create[0]; |
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
|
|
159
|
8
|
|
|
|
|
39
|
return @create; |
|
160
|
|
|
|
|
|
|
} |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
sub create_table |
|
164
|
|
|
|
|
|
|
{ |
|
165
|
29
|
|
|
29
|
0
|
137
|
my ($table, $options) = @_; |
|
166
|
|
|
|
|
|
|
|
|
167
|
29
|
|
|
|
|
99
|
my $table_name = _generator()->quote($table->name); |
|
168
|
29
|
|
|
|
|
575
|
$global_names{$table->name} = 1; |
|
169
|
|
|
|
|
|
|
|
|
170
|
29
|
|
|
|
|
598
|
my $no_comments = $options->{no_comments}; |
|
171
|
29
|
|
|
|
|
65
|
my $add_drop_table = $options->{add_drop_table}; |
|
172
|
29
|
|
50
|
|
|
135
|
my $sqlite_version = $options->{sqlite_version} || 0; |
|
173
|
|
|
|
|
|
|
|
|
174
|
29
|
|
|
|
|
152
|
debug("PKG: Looking at table '$table_name'\n"); |
|
175
|
|
|
|
|
|
|
|
|
176
|
29
|
|
|
|
|
68
|
my ( @index_defs, @constraint_defs ); |
|
177
|
29
|
50
|
|
|
|
117
|
my @fields = $table->get_fields or die "No fields in $table_name"; |
|
178
|
|
|
|
|
|
|
|
|
179
|
29
|
100
|
|
|
|
108
|
my $temp = $options->{temporary_table} ? 'TEMPORARY ' : ''; |
|
180
|
|
|
|
|
|
|
# |
|
181
|
|
|
|
|
|
|
# Header. |
|
182
|
|
|
|
|
|
|
# |
|
183
|
29
|
50
|
|
|
|
99
|
my $exists = ($sqlite_version >= 3.003) ? ' IF EXISTS' : ''; |
|
184
|
29
|
|
|
|
|
49
|
my @create; |
|
185
|
29
|
|
|
|
|
68
|
my ($comment, $create_table) = ""; |
|
186
|
29
|
100
|
|
|
|
111
|
$comment = "--\n-- Table: $table_name\n--\n" unless $no_comments; |
|
187
|
29
|
100
|
|
|
|
67
|
if ($add_drop_table) { |
|
188
|
12
|
|
|
|
|
50
|
push @create, $comment . qq[DROP TABLE$exists $table_name]; |
|
189
|
|
|
|
|
|
|
} else { |
|
190
|
17
|
|
|
|
|
46
|
$create_table = $comment; |
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
|
|
193
|
29
|
|
|
|
|
113
|
$create_table .= "CREATE ${temp}TABLE $table_name (\n"; |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
# |
|
196
|
|
|
|
|
|
|
# Comments |
|
197
|
|
|
|
|
|
|
# |
|
198
|
29
|
50
|
33
|
|
|
645
|
if ( $table->comments and !$no_comments ){ |
|
199
|
0
|
|
|
|
|
0
|
$create_table .= "-- Comments: \n-- "; |
|
200
|
0
|
|
|
|
|
0
|
$create_table .= join "\n-- ", $table->comments; |
|
201
|
0
|
|
|
|
|
0
|
$create_table .= "\n--\n\n"; |
|
202
|
|
|
|
|
|
|
} |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
# |
|
205
|
|
|
|
|
|
|
# How many fields in PK? |
|
206
|
|
|
|
|
|
|
# |
|
207
|
29
|
|
|
|
|
107
|
my $pk = $table->primary_key; |
|
208
|
29
|
100
|
|
|
|
554
|
my @pk_fields = $pk ? $pk->fields : (); |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
# |
|
211
|
|
|
|
|
|
|
# Fields |
|
212
|
|
|
|
|
|
|
# |
|
213
|
29
|
|
|
|
|
86
|
my ( @field_defs, $pk_set ); |
|
214
|
29
|
|
|
|
|
74
|
for my $field ( @fields ) { |
|
215
|
105
|
|
|
|
|
269
|
push @field_defs, create_field($field); |
|
216
|
|
|
|
|
|
|
} |
|
217
|
|
|
|
|
|
|
|
|
218
|
29
|
100
|
66
|
|
|
281
|
if ( |
|
|
|
|
66
|
|
|
|
|
|
219
|
|
|
|
|
|
|
scalar @pk_fields > 1 |
|
220
|
|
|
|
|
|
|
|| |
|
221
|
|
|
|
|
|
|
( @pk_fields && !grep /INTEGER PRIMARY KEY/, @field_defs ) |
|
222
|
|
|
|
|
|
|
) { |
|
223
|
2
|
|
|
|
|
9
|
push @field_defs, 'PRIMARY KEY (' . join(', ', map _generator()->quote($_), @pk_fields ) . ')'; |
|
224
|
|
|
|
|
|
|
} |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# |
|
227
|
|
|
|
|
|
|
# Indices |
|
228
|
|
|
|
|
|
|
# |
|
229
|
29
|
|
|
|
|
163
|
for my $index ( $table->get_indices ) { |
|
230
|
10
|
|
|
|
|
96
|
push @index_defs, create_index($index); |
|
231
|
|
|
|
|
|
|
} |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
# |
|
234
|
|
|
|
|
|
|
# Constraints |
|
235
|
|
|
|
|
|
|
# |
|
236
|
29
|
|
|
|
|
92
|
for my $c ( $table->get_constraints ) { |
|
237
|
41
|
100
|
|
|
|
1125
|
if ($c->type eq "FOREIGN KEY") { |
|
|
|
50
|
|
|
|
|
|
|
238
|
10
|
|
|
|
|
216
|
push @field_defs, create_foreignkey($c); |
|
239
|
|
|
|
|
|
|
} |
|
240
|
|
|
|
|
|
|
elsif ($c->type eq "CHECK") { |
|
241
|
0
|
|
|
|
|
0
|
push @field_defs, create_check_constraint($c); |
|
242
|
|
|
|
|
|
|
} |
|
243
|
41
|
100
|
|
|
|
1279
|
next unless $c->type eq UNIQUE; |
|
244
|
11
|
|
|
|
|
240
|
push @constraint_defs, create_constraint($c); |
|
245
|
|
|
|
|
|
|
} |
|
246
|
|
|
|
|
|
|
|
|
247
|
29
|
|
|
|
|
369
|
$create_table .= join(",\n", map { " $_" } @field_defs ) . "\n)"; |
|
|
117
|
|
|
|
|
335
|
|
|
248
|
|
|
|
|
|
|
|
|
249
|
29
|
|
|
|
|
194
|
return (@create, $create_table, @index_defs, @constraint_defs ); |
|
250
|
|
|
|
|
|
|
} |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
sub create_check_constraint { |
|
253
|
1
|
|
|
1
|
0
|
5
|
my $c = shift; |
|
254
|
1
|
|
|
|
|
3
|
my $check = ''; |
|
255
|
1
|
50
|
|
|
|
20
|
$check .= 'CONSTRAINT ' . _generator->quote( $c->name ) . ' ' if $c->name; |
|
256
|
1
|
|
|
|
|
31
|
$check .= 'CHECK(' . $c->expression . ')'; |
|
257
|
1
|
|
|
|
|
3
|
return $check; |
|
258
|
|
|
|
|
|
|
} |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
sub create_foreignkey { |
|
261
|
11
|
|
|
11
|
0
|
61
|
my $c = shift; |
|
262
|
|
|
|
|
|
|
|
|
263
|
11
|
|
|
|
|
42
|
my @fields = $c->fields; |
|
264
|
11
|
50
|
|
|
|
249
|
my @rfields = map { $_ || () } $c->reference_fields; |
|
|
11
|
|
|
|
|
50
|
|
|
265
|
11
|
50
|
|
|
|
94
|
unless ( @rfields ) { |
|
266
|
0
|
|
|
|
|
0
|
my $rtable_name = $c->reference_table; |
|
267
|
0
|
0
|
|
|
|
0
|
if ( my $ref_table = $c->schema->get_table( $rtable_name ) ) { |
|
268
|
0
|
|
|
|
|
0
|
push @rfields, $ref_table->primary_key; |
|
269
|
|
|
|
|
|
|
|
|
270
|
0
|
0
|
|
|
|
0
|
die "FK constraint on " . $rtable_name . '.' . join('', @fields) . " has no reference fields\n" |
|
271
|
|
|
|
|
|
|
unless @rfields; |
|
272
|
|
|
|
|
|
|
} |
|
273
|
|
|
|
|
|
|
else { |
|
274
|
0
|
|
|
|
|
0
|
die "Can't find reference table '$rtable_name' in schema\n"; |
|
275
|
|
|
|
|
|
|
} |
|
276
|
|
|
|
|
|
|
} |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
my $fk_sql = sprintf 'FOREIGN KEY (%s) REFERENCES %s(%s)', |
|
279
|
11
|
|
|
|
|
33
|
join (', ', map { _generator()->quote($_) } @fields ), |
|
280
|
|
|
|
|
|
|
_generator()->quote($c->reference_table), |
|
281
|
11
|
|
|
|
|
35
|
join (', ', map { _generator()->quote($_) } @rfields ) |
|
|
11
|
|
|
|
|
36
|
|
|
282
|
|
|
|
|
|
|
; |
|
283
|
|
|
|
|
|
|
|
|
284
|
11
|
100
|
|
|
|
63
|
$fk_sql .= " ON DELETE " . $c->{on_delete} if $c->{on_delete}; |
|
285
|
11
|
100
|
|
|
|
43
|
$fk_sql .= " ON UPDATE " . $c->{on_update} if $c->{on_update}; |
|
286
|
|
|
|
|
|
|
|
|
287
|
11
|
|
|
|
|
41
|
return $fk_sql; |
|
288
|
|
|
|
|
|
|
} |
|
289
|
|
|
|
|
|
|
|
|
290
|
108
|
|
|
108
|
0
|
236
|
sub create_field { return _generator()->field($_[0]) } |
|
291
|
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
sub create_index |
|
293
|
|
|
|
|
|
|
{ |
|
294
|
13
|
|
|
13
|
0
|
42
|
my ($index, $options) = @_; |
|
295
|
|
|
|
|
|
|
|
|
296
|
13
|
|
|
|
|
268
|
(my $index_table_name = $index->table->name) =~ s/^.+?\.//; # table name may not specify schema |
|
297
|
13
|
|
66
|
|
|
473
|
my $name = mk_name($index->name || "${index_table_name}_idx"); |
|
298
|
|
|
|
|
|
|
|
|
299
|
13
|
100
|
|
|
|
301
|
my $type = $index->type eq 'UNIQUE' ? "UNIQUE " : ''; |
|
300
|
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
# strip any field size qualifiers as SQLite doesn't like these |
|
302
|
13
|
|
|
|
|
524
|
my @fields = map { s/\(\d+\)$//; _generator()->quote($_) } $index->fields; |
|
|
13
|
|
|
|
|
52
|
|
|
|
13
|
|
|
|
|
44
|
|
|
303
|
13
|
|
|
|
|
38
|
$index_table_name = _generator()->quote($index_table_name); |
|
304
|
13
|
50
|
|
|
|
50
|
warn "removing schema name from '" . $index->table->name . "' to make '$index_table_name'\n" if $WARN; |
|
305
|
13
|
|
|
|
|
70
|
my $index_def = |
|
306
|
|
|
|
|
|
|
"CREATE ${type}INDEX $name ON " . $index_table_name . |
|
307
|
|
|
|
|
|
|
' (' . join( ', ', @fields ) . ')'; |
|
308
|
|
|
|
|
|
|
|
|
309
|
13
|
|
|
|
|
52
|
return $index_def; |
|
310
|
|
|
|
|
|
|
} |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub create_constraint |
|
313
|
|
|
|
|
|
|
{ |
|
314
|
15
|
|
|
15
|
0
|
108
|
my ($c, $options) = @_; |
|
315
|
|
|
|
|
|
|
|
|
316
|
15
|
|
|
|
|
306
|
(my $index_table_name = $c->table->name) =~ s/^.+?\.//; # table name may not specify schema |
|
317
|
15
|
|
66
|
|
|
560
|
my $name = mk_name($c->name || "${index_table_name}_idx"); |
|
318
|
15
|
|
|
|
|
70
|
my @fields = map _generator()->quote($_), $c->fields; |
|
319
|
15
|
|
|
|
|
46
|
$index_table_name = _generator()->quote($index_table_name); |
|
320
|
15
|
50
|
|
|
|
204
|
warn "removing schema name from '" . $c->table->name . "' to make '$index_table_name'\n" if $WARN; |
|
321
|
|
|
|
|
|
|
|
|
322
|
15
|
|
|
|
|
83
|
my $c_def = |
|
323
|
|
|
|
|
|
|
"CREATE UNIQUE INDEX $name ON " . $index_table_name . |
|
324
|
|
|
|
|
|
|
' (' . join( ', ', @fields ) . ')'; |
|
325
|
|
|
|
|
|
|
|
|
326
|
15
|
|
|
|
|
259
|
return $c_def; |
|
327
|
|
|
|
|
|
|
} |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
sub create_trigger { |
|
330
|
13
|
|
|
13
|
0
|
37
|
my ($trigger, $options) = @_; |
|
331
|
13
|
|
|
|
|
59
|
my $add_drop = $options->{add_drop_trigger}; |
|
332
|
|
|
|
|
|
|
|
|
333
|
13
|
|
|
|
|
21
|
my @statements; |
|
334
|
|
|
|
|
|
|
|
|
335
|
13
|
|
|
|
|
46
|
my $trigger_name = $trigger->name; |
|
336
|
13
|
|
|
|
|
37
|
$global_names{$trigger_name} = 1; |
|
337
|
|
|
|
|
|
|
|
|
338
|
13
|
|
|
|
|
284
|
my $events = $trigger->database_events; |
|
339
|
13
|
|
|
|
|
109
|
for my $evt ( @$events ) { |
|
340
|
|
|
|
|
|
|
|
|
341
|
16
|
|
|
|
|
33
|
my $trig_name = $trigger_name; |
|
342
|
16
|
100
|
|
|
|
48
|
if (@$events > 1) { |
|
343
|
6
|
|
|
|
|
18
|
$trig_name .= "_$evt"; |
|
344
|
|
|
|
|
|
|
|
|
345
|
6
|
50
|
|
|
|
17
|
warn "Multiple database events supplied for trigger '$trigger_name', ", |
|
346
|
|
|
|
|
|
|
"creating trigger '$trig_name' for the '$evt' event.\n" if $WARN; |
|
347
|
|
|
|
|
|
|
} |
|
348
|
|
|
|
|
|
|
|
|
349
|
16
|
|
|
|
|
46
|
$trig_name = _generator()->quote($trig_name); |
|
350
|
16
|
100
|
|
|
|
65
|
push @statements, "DROP TRIGGER IF EXISTS $trig_name" if $add_drop; |
|
351
|
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
|
|
353
|
16
|
|
|
|
|
47
|
$DB::single = 1; |
|
354
|
16
|
|
|
|
|
36
|
my $action = ""; |
|
355
|
16
|
100
|
|
|
|
75
|
if (not ref $trigger->action) { |
|
356
|
12
|
|
|
|
|
33
|
$action = $trigger->action; |
|
357
|
12
|
100
|
|
|
|
80
|
$action = "BEGIN " . $action . " END" |
|
358
|
|
|
|
|
|
|
unless $action =~ /^ \s* BEGIN [\s\;] .*? [\s\;] END [\s\;]* $/six; |
|
359
|
|
|
|
|
|
|
} |
|
360
|
|
|
|
|
|
|
else { |
|
361
|
|
|
|
|
|
|
$action = $trigger->action->{for_each} . " " |
|
362
|
4
|
50
|
|
|
|
21
|
if $trigger->action->{for_each}; |
|
363
|
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
$action = $trigger->action->{when} . " " |
|
365
|
4
|
50
|
|
|
|
15
|
if $trigger->action->{when}; |
|
366
|
|
|
|
|
|
|
|
|
367
|
4
|
|
50
|
|
|
16
|
my $steps = $trigger->action->{steps} || []; |
|
368
|
|
|
|
|
|
|
|
|
369
|
4
|
|
|
|
|
9
|
$action .= "BEGIN "; |
|
370
|
4
|
|
|
|
|
16
|
$action .= $_ . "; " for (@$steps); |
|
371
|
4
|
|
|
|
|
6
|
$action .= "END"; |
|
372
|
|
|
|
|
|
|
} |
|
373
|
|
|
|
|
|
|
|
|
374
|
16
|
|
|
|
|
386
|
push @statements, sprintf ( |
|
375
|
|
|
|
|
|
|
'CREATE TRIGGER %s %s %s on %s %s', |
|
376
|
|
|
|
|
|
|
$trig_name, |
|
377
|
|
|
|
|
|
|
$trigger->perform_action_when, |
|
378
|
|
|
|
|
|
|
$evt, |
|
379
|
|
|
|
|
|
|
_generator()->quote($trigger->on_table), |
|
380
|
|
|
|
|
|
|
$action |
|
381
|
|
|
|
|
|
|
); |
|
382
|
|
|
|
|
|
|
} |
|
383
|
|
|
|
|
|
|
|
|
384
|
13
|
|
|
|
|
64
|
return @statements; |
|
385
|
|
|
|
|
|
|
} |
|
386
|
|
|
|
|
|
|
|
|
387
|
1
|
|
|
1
|
0
|
15
|
sub alter_table { () } # Noop |
|
388
|
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
sub add_field { |
|
390
|
3
|
|
|
3
|
0
|
30
|
my ($field) = @_; |
|
391
|
|
|
|
|
|
|
|
|
392
|
3
|
|
|
|
|
11
|
return sprintf("ALTER TABLE %s ADD COLUMN %s", |
|
393
|
|
|
|
|
|
|
_generator()->quote($field->table->name), create_field($field)) |
|
394
|
|
|
|
|
|
|
} |
|
395
|
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
sub alter_create_index { |
|
397
|
1
|
|
|
1
|
0
|
10
|
my ($index) = @_; |
|
398
|
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
# This might cause name collisions |
|
400
|
1
|
|
|
|
|
5
|
return create_index($index); |
|
401
|
|
|
|
|
|
|
} |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
sub alter_create_constraint { |
|
404
|
3
|
|
|
3
|
0
|
25
|
my ($constraint) = @_; |
|
405
|
|
|
|
|
|
|
|
|
406
|
3
|
100
|
|
|
|
55
|
return create_constraint($constraint) if $constraint->type eq 'UNIQUE'; |
|
407
|
|
|
|
|
|
|
} |
|
408
|
|
|
|
|
|
|
|
|
409
|
2
|
|
|
2
|
0
|
18
|
sub alter_drop_constraint { alter_drop_index(@_) } |
|
410
|
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
sub alter_drop_index { |
|
412
|
3
|
|
|
3
|
0
|
11
|
my ($constraint) = @_; |
|
413
|
|
|
|
|
|
|
|
|
414
|
3
|
|
|
|
|
8
|
return sprintf("DROP INDEX %s", |
|
415
|
|
|
|
|
|
|
_generator()->quote($constraint->name)); |
|
416
|
|
|
|
|
|
|
} |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
sub batch_alter_table { |
|
419
|
5
|
|
|
5
|
0
|
164
|
my ($table, $diffs, $options) = @_; |
|
420
|
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
# If we have any of the following |
|
422
|
|
|
|
|
|
|
# |
|
423
|
|
|
|
|
|
|
# rename_field |
|
424
|
|
|
|
|
|
|
# alter_field |
|
425
|
|
|
|
|
|
|
# drop_field |
|
426
|
|
|
|
|
|
|
# |
|
427
|
|
|
|
|
|
|
# we need to do the following |
|
428
|
|
|
|
|
|
|
# |
|
429
|
|
|
|
|
|
|
# BEGIN TRANSACTION; |
|
430
|
|
|
|
|
|
|
# CREATE TEMPORARY TABLE t1_backup(a,b); |
|
431
|
|
|
|
|
|
|
# INSERT INTO t1_backup SELECT a,b FROM t1; |
|
432
|
|
|
|
|
|
|
# DROP TABLE t1; |
|
433
|
|
|
|
|
|
|
# CREATE TABLE t1(a,b); |
|
434
|
|
|
|
|
|
|
# INSERT INTO t1 SELECT a,b FROM t1_backup; |
|
435
|
|
|
|
|
|
|
# DROP TABLE t1_backup; |
|
436
|
|
|
|
|
|
|
# COMMIT; |
|
437
|
|
|
|
|
|
|
# |
|
438
|
|
|
|
|
|
|
# Fun, eh? |
|
439
|
|
|
|
|
|
|
# |
|
440
|
|
|
|
|
|
|
# If we have rename_field we do similarly. |
|
441
|
|
|
|
|
|
|
# |
|
442
|
|
|
|
|
|
|
# We create the temporary table as a copy of the new table, copy all data |
|
443
|
|
|
|
|
|
|
# to temp table, create new table and then copy as appropriate taking note |
|
444
|
|
|
|
|
|
|
# of renamed fields. |
|
445
|
|
|
|
|
|
|
|
|
446
|
5
|
|
|
|
|
88
|
my $table_name = $table->name; |
|
447
|
|
|
|
|
|
|
|
|
448
|
5
|
100
|
66
|
|
|
91
|
if ( @{$diffs->{rename_field}} == 0 && |
|
|
5
|
|
100
|
|
|
24
|
|
|
449
|
4
|
|
|
|
|
18
|
@{$diffs->{alter_field}} == 0 && |
|
450
|
4
|
|
|
|
|
14
|
@{$diffs->{drop_field}} == 0 |
|
451
|
|
|
|
|
|
|
) { |
|
452
|
2
|
|
|
|
|
9
|
return batch_alter_table_statements($diffs, $options); |
|
453
|
|
|
|
|
|
|
} |
|
454
|
|
|
|
|
|
|
|
|
455
|
3
|
|
|
|
|
8
|
my @sql; |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
# $table is the new table but we may need an old one |
|
458
|
|
|
|
|
|
|
# TODO: this is NOT very well tested at the moment so add more tests |
|
459
|
|
|
|
|
|
|
|
|
460
|
3
|
|
|
|
|
5
|
my $old_table = $table; |
|
461
|
|
|
|
|
|
|
|
|
462
|
3
|
50
|
33
|
|
|
13
|
if ( $diffs->{rename_table} && @{$diffs->{rename_table}} ) { |
|
|
3
|
|
|
|
|
12
|
|
|
463
|
0
|
|
|
|
|
0
|
$old_table = $diffs->{rename_table}[0][0]; |
|
464
|
|
|
|
|
|
|
} |
|
465
|
|
|
|
|
|
|
|
|
466
|
3
|
|
|
|
|
10
|
my $temp_table_name = $table_name . '_temp_alter'; |
|
467
|
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
# CREATE TEMPORARY TABLE t1_backup(a,b); |
|
469
|
|
|
|
|
|
|
|
|
470
|
3
|
|
|
|
|
8
|
my %temp_table_fields; |
|
471
|
3
|
|
|
|
|
4
|
do { |
|
472
|
3
|
|
|
|
|
11
|
local $table->{name} = $temp_table_name; |
|
473
|
|
|
|
|
|
|
# We only want the table - don't care about indexes on tmp table |
|
474
|
3
|
|
|
|
|
18
|
my ($table_sql) = create_table($table, {no_comments => 1, temporary_table => 1}); |
|
475
|
3
|
|
|
|
|
14
|
push @sql,$table_sql; |
|
476
|
|
|
|
|
|
|
|
|
477
|
3
|
|
|
|
|
15
|
%temp_table_fields = map { $_ => 1} $table->get_fields; |
|
|
14
|
|
|
|
|
29
|
|
|
478
|
|
|
|
|
|
|
}; |
|
479
|
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
# record renamed fields for later |
|
481
|
3
|
|
|
|
|
74
|
my %rename_field = map { $_->[1]->name => $_->[0]->name } @{$diffs->{rename_field}}; |
|
|
1
|
|
|
|
|
21
|
|
|
|
3
|
|
|
|
|
14
|
|
|
482
|
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
# drop added fields from %temp_table_fields |
|
484
|
3
|
|
|
|
|
27
|
delete @temp_table_fields{@{$diffs->{add_field}}}; |
|
|
3
|
|
|
|
|
17
|
|
|
485
|
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
# INSERT INTO t1_backup SELECT a,b FROM t1; |
|
487
|
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
push @sql, sprintf( 'INSERT INTO %s( %s) SELECT %s FROM %s', |
|
489
|
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
_generator()->quote( $temp_table_name ), |
|
491
|
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
join( ', ', |
|
493
|
|
|
|
|
|
|
map _generator()->quote($_), |
|
494
|
14
|
|
|
|
|
224
|
grep { $temp_table_fields{$_} } $table->get_fields ), |
|
495
|
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
join( ', ', |
|
497
|
|
|
|
|
|
|
map _generator()->quote($_), |
|
498
|
11
|
100
|
|
|
|
215
|
map { $rename_field{$_} ? $rename_field{$_} : $_ } |
|
499
|
3
|
|
|
|
|
43
|
grep { $temp_table_fields{$_} } $table->get_fields ), |
|
|
14
|
|
|
|
|
213
|
|
|
500
|
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
_generator()->quote( $old_table->name ) |
|
502
|
|
|
|
|
|
|
); |
|
503
|
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
# DROP TABLE t1; |
|
505
|
|
|
|
|
|
|
|
|
506
|
3
|
|
|
|
|
27
|
push @sql, sprintf('DROP TABLE %s', _generator()->quote($old_table->name)); |
|
507
|
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
# CREATE TABLE t1(a,b); |
|
509
|
|
|
|
|
|
|
|
|
510
|
3
|
|
|
|
|
26
|
push @sql, create_table($table, { no_comments => 1 }); |
|
511
|
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
# INSERT INTO t1 SELECT a,b FROM t1_backup; |
|
513
|
|
|
|
|
|
|
|
|
514
|
3
|
|
|
|
|
14
|
push @sql, sprintf('INSERT INTO %s SELECT %s FROM %s', |
|
515
|
|
|
|
|
|
|
_generator()->quote($table_name), |
|
516
|
|
|
|
|
|
|
join(', ', map _generator()->quote($_), $table->get_fields), |
|
517
|
|
|
|
|
|
|
_generator()->quote($temp_table_name) |
|
518
|
|
|
|
|
|
|
); |
|
519
|
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
# DROP TABLE t1_backup; |
|
521
|
|
|
|
|
|
|
|
|
522
|
3
|
|
|
|
|
20
|
push @sql, sprintf('DROP TABLE %s', _generator()->quote($temp_table_name)); |
|
523
|
|
|
|
|
|
|
|
|
524
|
3
|
50
|
|
|
|
49
|
return wantarray ? @sql : join(";\n", @sql); |
|
525
|
|
|
|
|
|
|
} |
|
526
|
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
sub drop_table { |
|
528
|
2
|
|
|
2
|
0
|
33
|
my ($table) = @_; |
|
529
|
2
|
|
|
|
|
6
|
$table = _generator()->quote($table); |
|
530
|
2
|
|
|
|
|
12
|
return "DROP TABLE $table"; |
|
531
|
|
|
|
|
|
|
} |
|
532
|
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
sub rename_table { |
|
534
|
2
|
|
|
2
|
0
|
20
|
my ($old_table, $new_table, $options) = @_; |
|
535
|
|
|
|
|
|
|
|
|
536
|
2
|
|
|
|
|
9
|
$old_table = _generator()->quote($old_table); |
|
537
|
2
|
|
|
|
|
7
|
$new_table = _generator()->quote($new_table); |
|
538
|
|
|
|
|
|
|
|
|
539
|
2
|
|
|
|
|
10
|
return "ALTER TABLE $old_table RENAME TO $new_table"; |
|
540
|
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
} |
|
542
|
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
# No-op. Just here to signify that we are a new style parser. |
|
544
|
|
|
|
0
|
0
|
|
sub preproces_schema { } |
|
545
|
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
1; |
|
547
|
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
=pod |
|
549
|
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
551
|
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
SQL::Translator, http://www.sqlite.org/. |
|
553
|
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
=head1 AUTHOR |
|
555
|
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
Ken Youens-Clark C<< >>. |
|
557
|
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
Diff code added by Ash Berlin C<< >>. |
|
559
|
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
=cut |