| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Mojo::SQL::Statement; |
|
2
|
2
|
|
|
2
|
|
13
|
use Mojo::Base -base, -signatures; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
15
|
|
|
3
|
|
|
|
|
|
|
|
|
4
|
2
|
|
|
2
|
|
578
|
use Scalar::Util qw(blessed); |
|
|
2
|
|
|
|
|
26
|
|
|
|
2
|
|
|
|
|
2096
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
has [qw(parts values)] => sub { [] }; |
|
7
|
|
|
|
|
|
|
|
|
8
|
46
|
|
|
46
|
1
|
209174
|
sub parse ($self, $text, @values) { |
|
|
46
|
|
|
|
|
53
|
|
|
|
46
|
|
|
|
|
65
|
|
|
|
46
|
|
|
|
|
51
|
|
|
|
46
|
|
|
|
|
44
|
|
|
9
|
46
|
|
|
|
|
41
|
my $escape = "\0"; |
|
10
|
46
|
|
|
|
|
103
|
$escape .= "\0" while index($text, $escape) >= 0; |
|
11
|
46
|
|
|
|
|
79
|
$text =~ s/\?\?/$escape/g; |
|
12
|
|
|
|
|
|
|
|
|
13
|
46
|
|
|
|
|
93
|
my @text_parts = split /\?/, $text, -1; |
|
14
|
46
|
100
|
|
|
|
73
|
@text_parts = ('') unless @text_parts; |
|
15
|
|
|
|
|
|
|
|
|
16
|
46
|
|
|
|
|
239
|
s/\Q$escape\E/?/g for @text_parts; |
|
17
|
|
|
|
|
|
|
|
|
18
|
46
|
|
|
|
|
51
|
my (@merged_parts, @merged_values); |
|
19
|
46
|
|
|
|
|
44
|
my $merge_next = 0; |
|
20
|
46
|
|
|
|
|
98
|
for my $i (0 .. $#text_parts) { |
|
21
|
114
|
100
|
|
|
|
145
|
if ($merge_next) { |
|
22
|
19
|
|
|
|
|
24
|
$merged_parts[-1] .= $text_parts[$i]; |
|
23
|
19
|
|
|
|
|
16
|
$merge_next = 0; |
|
24
|
|
|
|
|
|
|
} |
|
25
|
95
|
|
|
|
|
135
|
else { push @merged_parts, $text_parts[$i] } |
|
26
|
|
|
|
|
|
|
|
|
27
|
114
|
100
|
|
|
|
157
|
next if $i == $#text_parts; |
|
28
|
|
|
|
|
|
|
|
|
29
|
68
|
|
|
|
|
73
|
my $value = $values[$i]; |
|
30
|
68
|
100
|
66
|
|
|
138
|
if (blessed($value) && $value->isa('Mojo::SQL::Statement')) { |
|
31
|
19
|
|
|
|
|
21
|
my @value_parts = @{$value->parts}; |
|
|
19
|
|
|
|
|
28
|
|
|
32
|
19
|
|
|
|
|
88
|
$merged_parts[-1] .= shift @value_parts; |
|
33
|
19
|
|
|
|
|
27
|
push @merged_parts, @value_parts; |
|
34
|
19
|
|
|
|
|
19
|
push @merged_values, @{$value->values}; |
|
|
19
|
|
|
|
|
27
|
|
|
35
|
19
|
|
|
|
|
58
|
$merge_next = 1; |
|
36
|
|
|
|
|
|
|
} |
|
37
|
49
|
|
|
|
|
62
|
else { push @merged_values, $value } |
|
38
|
|
|
|
|
|
|
} |
|
39
|
|
|
|
|
|
|
|
|
40
|
46
|
|
|
|
|
68
|
$self->{parts} = \@merged_parts; |
|
41
|
46
|
|
|
|
|
55
|
$self->{values} = \@merged_values; |
|
42
|
|
|
|
|
|
|
|
|
43
|
46
|
|
|
|
|
200
|
return $self; |
|
44
|
|
|
|
|
|
|
} |
|
45
|
|
|
|
|
|
|
|
|
46
|
4
|
|
|
4
|
1
|
2163
|
sub parse_unsafe ($self, $text, @values) { |
|
|
4
|
|
|
|
|
5
|
|
|
|
4
|
|
|
|
|
4
|
|
|
|
4
|
|
|
|
|
5
|
|
|
|
4
|
|
|
|
|
4
|
|
|
47
|
4
|
|
|
|
|
5
|
my $escape = "\0"; |
|
48
|
4
|
|
|
|
|
10
|
$escape .= "\0" while index($text, $escape) >= 0; |
|
49
|
4
|
|
|
|
|
11
|
$text =~ s/\?\?/$escape/g; |
|
50
|
|
|
|
|
|
|
|
|
51
|
4
|
|
|
|
|
10
|
my @text_parts = split /\?/, $text, -1; |
|
52
|
4
|
|
|
|
|
32
|
s/\Q$escape\E/?/g for @text_parts; |
|
53
|
|
|
|
|
|
|
|
|
54
|
4
|
|
|
|
|
5
|
my @merged; |
|
55
|
4
|
|
|
|
|
17
|
for my $i (0 .. $#text_parts) { |
|
56
|
10
|
|
|
|
|
15
|
push @merged, $text_parts[$i]; |
|
57
|
10
|
100
|
|
|
|
28
|
push @merged, $values[$i] if $i < $#text_parts; |
|
58
|
|
|
|
|
|
|
} |
|
59
|
4
|
|
|
|
|
14
|
$self->{parts} = [join '', @merged]; |
|
60
|
4
|
|
|
|
|
7
|
$self->{values} = []; |
|
61
|
|
|
|
|
|
|
|
|
62
|
4
|
|
|
|
|
13
|
return $self; |
|
63
|
|
|
|
|
|
|
} |
|
64
|
|
|
|
|
|
|
|
|
65
|
25
|
|
|
25
|
1
|
33
|
sub to_query ($self, $options = {}) { {text => $self->to_string($options), values => $self->values} } |
|
|
25
|
|
|
|
|
25
|
|
|
|
25
|
|
|
|
|
25
|
|
|
|
25
|
|
|
|
|
20
|
|
|
|
25
|
|
|
|
|
39
|
|
|
66
|
|
|
|
|
|
|
|
|
67
|
12
|
|
|
12
|
1
|
11
|
sub to_array ($self, $options = {}) { [$self->to_string($options), @{$self->values}] } |
|
|
12
|
|
|
|
|
10
|
|
|
|
12
|
|
|
|
|
12
|
|
|
|
12
|
|
|
|
|
13
|
|
|
|
12
|
|
|
|
|
19
|
|
|
|
12
|
|
|
|
|
21
|
|
|
68
|
|
|
|
|
|
|
|
|
69
|
6
|
|
|
6
|
1
|
7
|
sub to_list ($self, $options = {}) { @{$self->to_array($options)} } |
|
|
6
|
|
|
|
|
6
|
|
|
|
6
|
|
|
|
|
8
|
|
|
|
6
|
|
|
|
|
5
|
|
|
|
6
|
|
|
|
|
9
|
|
|
|
6
|
|
|
|
|
10
|
|
|
70
|
|
|
|
|
|
|
|
|
71
|
37
|
|
|
37
|
1
|
31
|
sub to_string ($self, $options = {}) { |
|
|
37
|
|
|
|
|
34
|
|
|
|
37
|
|
|
|
|
36
|
|
|
|
37
|
|
|
|
|
32
|
|
|
72
|
37
|
|
|
|
|
36
|
my @query; |
|
73
|
37
|
|
|
|
|
41
|
my $placeholder = $options->{placeholder}; |
|
74
|
37
|
|
|
|
|
55
|
my $parts = $self->parts; |
|
75
|
37
|
|
|
|
|
135
|
for my $i (1 .. scalar @$parts) { |
|
76
|
98
|
|
|
|
|
129
|
push @query, $parts->[$i - 1]; |
|
77
|
98
|
100
|
|
|
|
172
|
push @query, defined $placeholder ? $placeholder : "\$$i" if defined $parts->[$i]; |
|
|
|
100
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
} |
|
79
|
|
|
|
|
|
|
|
|
80
|
37
|
|
|
|
|
112
|
return join '', @query; |
|
81
|
|
|
|
|
|
|
} |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
1; |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=encoding utf8 |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=head1 NAME |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
Mojo::SQL::Statement - SQL statement container |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
use Mojo::SQL::Statement; |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
my $stmt = Mojo::SQL::Statement->new->parse('SELECT * FROM users WHERE name = ?', 'sebastian'); |
|
96
|
|
|
|
|
|
|
my $query = $stmt->to_query; |
|
97
|
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
L is a container for an SQL statement and its bind values. Statements are composable by passing |
|
101
|
|
|
|
|
|
|
one as a value to another, in which case its parts and values are spliced in recursively. |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
L implements the following attributes. |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=head2 parts |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
my $parts = $stmt->parts; |
|
110
|
|
|
|
|
|
|
$stmt = $stmt->parts(['SELECT * FROM users WHERE name = ', '']); |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
The literal SQL fragments around each placeholder, as an array reference. There is always one more fragment than |
|
113
|
|
|
|
|
|
|
placeholder. |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=head2 values |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
my $values = $stmt->values; |
|
118
|
|
|
|
|
|
|
$stmt = $stmt->values(['sebastian']); |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
The bind values for each placeholder, as an array reference. |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=head1 METHODS |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
L inherits all methods from L and implements the following new ones. |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=head2 parse |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
$stmt = $stmt->parse('SELECT * FROM users WHERE name = ?', 'sebastian'); |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
Parse an SQL string with C> placeholders and bind values into L"parts"> and L"values">. L |
|
131
|
|
|
|
|
|
|
values are spliced in recursively, allowing partial statements to be composed. Literal question marks can be escaped |
|
132
|
|
|
|
|
|
|
with C?>. |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=head2 parse_unsafe |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
$stmt = $stmt->parse_unsafe("AND role = 'admin'"); |
|
137
|
|
|
|
|
|
|
$stmt = $stmt->parse_unsafe('AND ?', "role = 'admin'"); |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
Parse an SQL string where every C> slot is replaced literally by the corresponding value. The result has no |
|
140
|
|
|
|
|
|
|
placeholders or bind values; use with care, and make sure to escape values yourself with the appropriate escaping |
|
141
|
|
|
|
|
|
|
functions for your database. Literal question marks can be escaped with C?>. |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=head2 to_array |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
my $array = $stmt->to_array; |
|
146
|
|
|
|
|
|
|
my $array = $stmt->to_array({placeholder => '?'}); |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
Render the statement to an array reference containing the SQL text and bind values, ready to be passed to a database |
|
149
|
|
|
|
|
|
|
driver. Accepts the same options as L"to_query">. |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=head2 to_list |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
my @list = $stmt->to_list; |
|
154
|
|
|
|
|
|
|
my @list = $stmt->to_list({placeholder => '?'}); |
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
Same as L"to_array"> but returns a list. |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
=head2 to_query |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
my $query = $stmt->to_query; |
|
161
|
|
|
|
|
|
|
my $query = $stmt->to_query({placeholder => '?'}); |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
Render the statement to a query hash reference with C and C keys, ready to be passed to a database |
|
164
|
|
|
|
|
|
|
driver. |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
These options are currently available: |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=over 2 |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=item placeholder |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
placeholder => '?' |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
Placeholder character to use, defaults to numbered placeholders like C<$1> and C<$2>. |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=back |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=head2 to_string |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
my $string = $stmt->to_string; |
|
181
|
|
|
|
|
|
|
my $string = $stmt->to_string({placeholder => '?'}); |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
Render just the SQL string portion of the statement. Accepts the same options as L"to_query">. |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
L, L, L. |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=cut |