line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Mysql::PrettyPrinter; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
22056
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
34
|
|
4
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
3707
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = 0.10; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
# Knowledge of MySQL keywords is stored in class variables to aid efficiency in |
9
|
|
|
|
|
|
|
# persistent environments (eg mod_perl) |
10
|
|
|
|
|
|
|
my $Keywords = []; |
11
|
|
|
|
|
|
|
# First-level keywords; outdent |
12
|
|
|
|
|
|
|
$Keywords->[0] = [ qw( |
13
|
|
|
|
|
|
|
ALTER CHANGE CREATE DELETE DROP FROM GRANT GROUP HAVING INSERT LIMIT MODIFY |
14
|
|
|
|
|
|
|
ORDER SELECT SET SHOW UNION UPDATE WHERE |
15
|
|
|
|
|
|
|
) ]; |
16
|
|
|
|
|
|
|
# Second-level keywords; prepend a linebreak |
17
|
|
|
|
|
|
|
$Keywords->[1] = [ qw( |
18
|
|
|
|
|
|
|
CROSS INNER JOIN LEFT OUTER RIGHT |
19
|
|
|
|
|
|
|
ELSE ELSEIF THEN WHEN |
20
|
|
|
|
|
|
|
) ]; |
21
|
|
|
|
|
|
|
# Third-level keywords; prepend a linebreak if within a join |
22
|
|
|
|
|
|
|
$Keywords->[2] = [ qw( |
23
|
|
|
|
|
|
|
AND OR |
24
|
|
|
|
|
|
|
) ]; |
25
|
|
|
|
|
|
|
# Other keywords; no intention to treat specially |
26
|
|
|
|
|
|
|
$Keywords->[3] = [ qw( |
27
|
|
|
|
|
|
|
ACCESSIBLE ADD ALL ANALYZE AS ASC ASENSITIVE BEFORE BETWEEN BIGINT BINARY |
28
|
|
|
|
|
|
|
BLOB BOTH BY CALL CASCADE CASE CHAR CHARACTER CHECK COLLATE COLUMN |
29
|
|
|
|
|
|
|
CONDITION CONNECTION CONSTRAINT CONTINUE CONVERT CURRENT_DATE CURRENT_TIME |
30
|
|
|
|
|
|
|
CURRENT_TIMESTAMP CURRENT_USER CURSOR DATABASE DATABASES DAY_HOUR |
31
|
|
|
|
|
|
|
DAY_MICROSECOND DAY_MINUTE DAY_SECOND DEC DECIMAL DECLARE DEFAULT DELAYED |
32
|
|
|
|
|
|
|
DESC DESCRIBE DETERMINISTIC DISTINCT DISTINCTROW DIV DOUBLE DUAL EACH |
33
|
|
|
|
|
|
|
ELSEIF ENCLOSED ESCAPED EXISTS EXIT EXPLAIN FALSE FETCH FLOAT FLOAT4 FLOAT8 |
34
|
|
|
|
|
|
|
FOR FORCE FOREIGN FULLTEXT GOTO HIGH_PRIORITY HOUR_MICROSECOND HOUR_MINUTE |
35
|
|
|
|
|
|
|
HOUR_SECOND IF IGNORE IN INDEX INFILE INOUT INSENSITIVE INT INT1 INT2 INT3 |
36
|
|
|
|
|
|
|
INT4 INT8 INTEGER INTERVAL INTO IS ITERATE KEY KEYS KILL LABEL LEADING |
37
|
|
|
|
|
|
|
LEAVE LIKE LIMIT LINEAR LINES LOAD LOCALTIME LOCALTIMESTAMP LOCK LONG |
38
|
|
|
|
|
|
|
LONGBLOB LONGTEXT LOOP LOW_PRIORITY MASTER_SSL_VERIFY_SERVER_CERT MATCH |
39
|
|
|
|
|
|
|
MEDIUMBLOB MEDIUMINT MEDIUMTEXT MIDDLEINT MINUTE_MICROSECOND MINUTE_SECOND |
40
|
|
|
|
|
|
|
MOD MODIFIES NATURAL NOT NO_WRITE_TO_BINLOG NULL NUMERIC ON OPTIMIZE OPTION |
41
|
|
|
|
|
|
|
OPTIONALLY OUT OUTFILE PRECISION PRIMARY PROCEDURE PURGE RANGE READ |
42
|
|
|
|
|
|
|
READ_ONLY READS READ_WRITE REAL REFERENCES REGEXP RELEASE RENAME REPEAT |
43
|
|
|
|
|
|
|
REPLACE REQUIRE RESTRICT RETURN REVOKE RLIKE SCHEMA SCHEMAS |
44
|
|
|
|
|
|
|
SECOND_MICROSECOND SENSITIVE SEPARATOR SHOW SMALLINT SPATIAL SPECIFIC SQL |
45
|
|
|
|
|
|
|
SQL_BIG_RESULT SQL_CALC_FOUND_ROWS SQLEXCEPTION SQL_SMALL_RESULT SQLSTATE |
46
|
|
|
|
|
|
|
SQLWARNING SSL STARTING STRAIGHT_JOIN TABLE TABLES TEMPORARY TERMINATED |
47
|
|
|
|
|
|
|
TINYBLOB TINYINT TINYTEXT TO TRAILING TRIGGER TRUE UNDO UNIQUE UNLOCK |
48
|
|
|
|
|
|
|
UNSIGNED UPGRADE USAGE USE USING UTC_DATE UTC_TIME UTC_TIMESTAMP VALUES |
49
|
|
|
|
|
|
|
VARBINARY VARCHAR VARCHARACTER VARYING WHILE WITH WRITE XOR YEAR_MONTH |
50
|
|
|
|
|
|
|
ZEROFILL |
51
|
|
|
|
|
|
|
) ]; |
52
|
|
|
|
|
|
|
my $Keyword = { map { $_ => 4 } @{$Keywords->[3]} }; |
53
|
|
|
|
|
|
|
foreach my $n (1..3) { |
54
|
|
|
|
|
|
|
%$Keyword = (%$Keyword, map { $_ => $n } @{$Keywords->[$n - 1]}); |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
sub new { |
58
|
0
|
|
|
0
|
1
|
|
my ($class, %param) = @_; |
59
|
0
|
|
|
|
|
|
return bless { |
60
|
|
|
|
|
|
|
space => ' ', |
61
|
|
|
|
|
|
|
break => "\n", |
62
|
|
|
|
|
|
|
indent => ' ', |
63
|
|
|
|
|
|
|
wrap => undef, |
64
|
|
|
|
|
|
|
sql => '', |
65
|
|
|
|
|
|
|
tokens => [], |
66
|
|
|
|
|
|
|
_level => 0, |
67
|
|
|
|
|
|
|
_pending => 1, |
68
|
|
|
|
|
|
|
%param |
69
|
|
|
|
|
|
|
}, $class; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub sql { |
73
|
0
|
|
|
0
|
1
|
|
my ($self, $sql) = @_; |
74
|
0
|
0
|
|
|
|
|
if (defined($sql)) { |
75
|
|
|
|
|
|
|
# Setter |
76
|
0
|
|
|
|
|
|
$self->{sql} = $sql; |
77
|
0
|
|
|
|
|
|
$self->{_pending} = 1; |
78
|
0
|
|
|
|
|
|
return $self; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
else { |
81
|
|
|
|
|
|
|
# Getter |
82
|
0
|
|
|
|
|
|
return $self->{sql}; |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
sub add_sql { |
87
|
0
|
|
|
0
|
1
|
|
my ($self, $sql) = @_; |
88
|
0
|
0
|
|
|
|
|
$sql =~ s/^\s*/ / if length $self->{sql}; |
89
|
0
|
|
|
|
|
|
$self->{sql} .= $sql; |
90
|
0
|
|
|
|
|
|
$self->{_pending} = 1; |
91
|
0
|
|
|
|
|
|
return $self; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub make_tokens { |
95
|
0
|
|
|
0
|
1
|
|
my ($self, %param) = @_; |
96
|
0
|
0
|
|
|
|
|
if (%param) { |
97
|
0
|
|
|
|
|
|
%$self = ( %$self, %param ); |
98
|
|
|
|
|
|
|
} |
99
|
0
|
0
|
|
|
|
|
if (exists $param{sql}) { |
100
|
0
|
|
|
|
|
|
$self->{_pending} = 1; |
101
|
|
|
|
|
|
|
} |
102
|
0
|
0
|
0
|
|
|
|
if ($self->{_pending} and length $self->{sql}) { |
103
|
0
|
|
|
|
|
|
@{ $self->{tokens} } = $self->lexicals($self->{sql}, 1); |
|
0
|
|
|
|
|
|
|
104
|
0
|
|
|
|
|
|
$self->{_pending} = 0; |
105
|
|
|
|
|
|
|
} |
106
|
0
|
|
|
|
|
|
return $self; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub tokens { |
110
|
0
|
|
|
0
|
1
|
|
my ($self, @toks) = @_; |
111
|
0
|
0
|
|
|
|
|
if (scalar @toks) { |
112
|
|
|
|
|
|
|
# Setter |
113
|
0
|
|
|
|
|
|
@{ $self->{sql} } = @toks; |
|
0
|
|
|
|
|
|
|
114
|
0
|
|
|
|
|
|
$self->{_pending} = 0; |
115
|
0
|
|
|
|
|
|
return $self; |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
else { |
118
|
|
|
|
|
|
|
# Getter |
119
|
0
|
0
|
|
|
|
|
if ($self->{_pending}) { |
120
|
0
|
|
|
|
|
|
warn "Probable data conflict; suspicious invocation sequence"; |
121
|
|
|
|
|
|
|
} |
122
|
0
|
0
|
|
|
|
|
return wantarray ? @{$self->{tokens}} : $self->{tokens}; |
|
0
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
sub add_tokens { |
127
|
0
|
|
|
0
|
1
|
|
my ($self, @toks) = @_; |
128
|
0
|
0
|
|
|
|
|
if ($self->{_pending}) { |
129
|
0
|
|
|
|
|
|
warn "Probable data conflict; suspicious invocation sequence"; |
130
|
|
|
|
|
|
|
} |
131
|
0
|
|
|
|
|
|
push(@{$self->{tokens}}, @toks); |
|
0
|
|
|
|
|
|
|
132
|
0
|
|
|
|
|
|
$self->{_pending} = 0; |
133
|
0
|
|
|
|
|
|
return $self; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
sub format { |
137
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
138
|
0
|
0
|
|
|
|
|
unless (ref $self) { |
|
|
0
|
|
|
|
|
|
139
|
|
|
|
|
|
|
# Shortcut used; need to start from scratch |
140
|
0
|
|
|
|
|
|
$self = $self->new(@_); |
141
|
0
|
|
|
|
|
|
$self->make_tokens; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
elsif ($self->{_pending}) { |
144
|
|
|
|
|
|
|
# SQL waiting to be tokenised |
145
|
0
|
|
|
|
|
|
$self->make_tokens(@_); |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
0
|
|
|
|
|
|
$self->{_output} = ''; # Ultimate output |
149
|
0
|
|
|
|
|
|
$self->{_levels} = []; # Nested levels |
150
|
0
|
|
|
|
|
|
$self->{_blank_line} = 1; # Whether in a blank line |
151
|
0
|
|
|
|
|
|
$self->{_previous} = ''; # Previous token |
152
|
0
|
|
|
|
|
|
$self->{_joining} = 0; # Whether in a compound join |
153
|
0
|
|
|
|
|
|
$self->{_conditioning} = 0; # Whether in a conditional |
154
|
|
|
|
|
|
|
|
155
|
0
|
|
|
|
|
|
while (defined(my $token = shift @{$self->{tokens}} )) { |
|
0
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
# Some preprocessing of token |
157
|
0
|
0
|
|
|
|
|
if ($self->_is_keyword(uc $token)) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# Keyword => uppercase |
159
|
0
|
|
|
|
|
|
$token = uc $token; |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
elsif ($token =~ /^[,.;\(\)]$/) { |
162
|
|
|
|
|
|
|
# Punctuation |
163
|
|
|
|
|
|
|
; # nothing |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
elsif ($self->{_pending_nl}) { |
166
|
|
|
|
|
|
|
# Non-keyword/punctuation |
167
|
0
|
|
|
|
|
|
$self->_new_line; |
168
|
0
|
|
|
|
|
|
$self->{_pending_nl} = 0; |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
# Build output |
172
|
0
|
0
|
0
|
|
|
|
if ($token eq '(') { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
173
|
0
|
|
|
|
|
|
push @{ $self->{_levels} }, $self->{_level}; |
|
0
|
|
|
|
|
|
|
174
|
0
|
|
|
|
|
|
$self->_add_token($token)->_new_line->_over; |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
elsif ($token eq ')') { |
177
|
0
|
|
0
|
|
|
|
$self->{_level} = pop(@{ $self->{_levels} }) || 0; |
178
|
0
|
|
|
|
|
|
$self->_new_line->_add_token($token); |
179
|
0
|
0
|
0
|
|
|
|
$self->_new_line |
180
|
|
|
|
|
|
|
unless uc($self->_next_token) eq 'AS' |
181
|
|
|
|
|
|
|
|| $self->_next_token eq ','; |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
elsif ($token eq ',') { |
184
|
0
|
|
|
|
|
|
$self->_add_token($token)->_new_line; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
elsif ($token eq ';') { |
187
|
0
|
|
|
|
|
|
$self->_add_token($token)->_new_line; |
188
|
|
|
|
|
|
|
# End of statement; remove all indentation |
189
|
0
|
|
|
|
|
|
@{ $self->{_levels} } = (); |
|
0
|
|
|
|
|
|
|
190
|
0
|
|
|
|
|
|
$self->{_level} = 0; |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
elsif ($token eq 'UNION') { |
193
|
|
|
|
|
|
|
# End of statement; remove all indentation |
194
|
0
|
|
|
|
|
|
@{ $self->{_levels} } = (); |
|
0
|
|
|
|
|
|
|
195
|
0
|
|
|
|
|
|
$self->{_level} = 0; |
196
|
0
|
|
|
|
|
|
$self->_new_line->_add_token($token, 'K')->_new_line; |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
elsif ($token eq 'JOIN') { |
199
|
0
|
0
|
|
|
|
|
unless ($self->_is_keyword($self->{_previous})) { |
200
|
0
|
|
|
|
|
|
$self->_new_line; |
201
|
|
|
|
|
|
|
} |
202
|
0
|
|
|
|
|
|
$self->_add_token($token, 'K'); |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
elsif ($token eq 'ON') { |
205
|
0
|
|
|
|
|
|
$self->_add_token($token, 'K'); |
206
|
0
|
0
|
|
|
|
|
if ($self->_is_keyword($self->_next_keyword) == 3) { |
207
|
0
|
|
|
|
|
|
$self->_new_line->_over; |
208
|
0
|
|
|
|
|
|
$self->{_joining} = 1; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
elsif ($token eq 'CASE') { |
212
|
0
|
|
|
|
|
|
$self->_add_token($token, 'K')->_over; |
213
|
0
|
|
|
|
|
|
$self->{_conditioning} = 1; |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
elsif ($token eq 'END' and $self->{_conditioning}) { |
216
|
0
|
|
|
|
|
|
$self->_back->_new_line->_add_token($token, 'K'); |
217
|
0
|
|
|
|
|
|
$self->{_conditioning} = 0; |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
elsif ($self->_is_keyword($token) == 1) { |
220
|
|
|
|
|
|
|
# First-level keyword |
221
|
0
|
0
|
|
|
|
|
$self->_back unless $self->{_previous} eq '('; |
222
|
0
|
0
|
|
|
|
|
if ($self->{_joining}) { |
223
|
0
|
|
|
|
|
|
$self->_back; |
224
|
0
|
|
|
|
|
|
$self->{_joining} = 0; |
225
|
|
|
|
|
|
|
} |
226
|
0
|
|
|
|
|
|
$self->_new_line->_add_token($token, 'K')->_over; |
227
|
0
|
|
|
|
|
|
$self->{_pending_nl} = 1; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
elsif ($self->_is_keyword($token) == 2) { |
230
|
|
|
|
|
|
|
# Second-level keyword |
231
|
0
|
0
|
|
|
|
|
if ($self->{_joining}) { |
232
|
0
|
|
|
|
|
|
$self->_back; |
233
|
0
|
|
|
|
|
|
$self->{_joining} = 0; |
234
|
|
|
|
|
|
|
} |
235
|
0
|
|
|
|
|
|
$self->_new_line->_add_token($token, 'K'); |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
elsif ($self->_is_keyword($token) == 3) { |
238
|
|
|
|
|
|
|
# Third-level keyword |
239
|
0
|
|
|
|
|
|
$self->_new_line->_add_token($token, 'K'); |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
elsif ($self->_is_keyword($token)) { |
242
|
|
|
|
|
|
|
# Other keyword |
243
|
0
|
|
|
|
|
|
$self->_add_token($token, 'K'); |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
elsif ($token =~ /^"[^"']*"$/) { |
246
|
|
|
|
|
|
|
# Quoted string |
247
|
0
|
|
|
|
|
|
$token =~ s/"/'/g; |
248
|
0
|
|
|
|
|
|
$self->_add_token($token, 'L'); |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
elsif ($token =~ /^'.*'$/) { |
251
|
|
|
|
|
|
|
# Quoted string |
252
|
0
|
|
|
|
|
|
$self->_add_token($token, 'L'); |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
elsif ($token =~ /^\d+$/) { |
255
|
|
|
|
|
|
|
# Number |
256
|
0
|
|
|
|
|
|
$self->_add_token($token, 'L'); |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
elsif ($self->_next_token eq '(') { |
259
|
0
|
|
|
|
|
|
$token = lc $token; |
260
|
0
|
|
|
|
|
|
$self->_add_token($token, 'F'); |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
else { |
263
|
0
|
|
|
|
|
|
$self->_add_token($token); |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
#TODO: Identify comments |
266
|
|
|
|
|
|
|
|
267
|
0
|
|
|
|
|
|
$self->{_previous} = $token; |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
0
|
|
|
|
|
|
$self->_new_line; |
271
|
0
|
|
|
|
|
|
return $self->{_output}; |
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
# Add a token to the formatted string. |
275
|
|
|
|
|
|
|
sub _add_token { |
276
|
0
|
|
|
0
|
|
|
my ($self, $token, $type) = @_; |
277
|
0
|
|
0
|
|
|
|
$type ||= ''; |
278
|
|
|
|
|
|
|
|
279
|
0
|
0
|
|
|
|
|
if ($self->{wrap}) { |
280
|
|
|
|
|
|
|
# Format wrapping of keywords, etc |
281
|
0
|
0
|
0
|
|
|
|
if ($type eq 'K' and exists $self->{wrap}->{keyword}) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
282
|
|
|
|
|
|
|
# Keyword |
283
|
0
|
|
|
|
|
|
$token = $self->{wrap}->{keyword}->[0] |
284
|
|
|
|
|
|
|
. $token |
285
|
|
|
|
|
|
|
. $self->{wrap}->{keyword}->[1]; |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
elsif ($type eq 'F' and exists $self->{wrap}->{function}) { |
288
|
|
|
|
|
|
|
# Function |
289
|
0
|
|
|
|
|
|
$token = $self->{wrap}->{function}->[0] |
290
|
|
|
|
|
|
|
. $token |
291
|
|
|
|
|
|
|
. $self->{wrap}->{function}->[1]; |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
elsif ($type eq 'L' and exists $self->{wrap}->{literal}) { |
294
|
|
|
|
|
|
|
# Literal |
295
|
0
|
|
|
|
|
|
$token = $self->{wrap}->{literal}->[0] |
296
|
|
|
|
|
|
|
. $token |
297
|
|
|
|
|
|
|
. $self->{wrap}->{literal}->[1]; |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
elsif ($type eq 'C' and exists $self->{wrap}->{comment}) { |
300
|
|
|
|
|
|
|
# Comment |
301
|
0
|
|
|
|
|
|
$token = $self->{wrap}->{comment}->[0] |
302
|
|
|
|
|
|
|
. $token |
303
|
|
|
|
|
|
|
. $self->{wrap}->{comment}->[1]; |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
0
|
0
|
0
|
|
|
|
if ($token =~ /^[,.;]$/ or $self->{_previous} eq '.') { |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
308
|
|
|
|
|
|
|
# Punctuation => no indent |
309
|
|
|
|
|
|
|
; |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
elsif ($token eq '(' |
312
|
|
|
|
|
|
|
and not $self->_is_keyword($self->{_previous}) |
313
|
|
|
|
|
|
|
and not $self->{_previous} eq ',') { |
314
|
|
|
|
|
|
|
# Function => no indent |
315
|
|
|
|
|
|
|
; |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
else { |
318
|
0
|
|
|
|
|
|
$self->{_output} .= $self->_indent; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
|
321
|
0
|
|
|
|
|
|
$self->{_output} .= $token; |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
# This can't be the beginning of a new line anymore. |
324
|
0
|
|
|
|
|
|
$self->{_blank_line} = 0; |
325
|
0
|
|
|
|
|
|
return $self; |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
# Increase the indentation level. |
329
|
|
|
|
|
|
|
sub _over { |
330
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
331
|
0
|
|
|
|
|
|
++$self->{_level}; |
332
|
0
|
|
|
|
|
|
return $self; |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
# Decrease the indentation level. |
336
|
|
|
|
|
|
|
sub _back { |
337
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
338
|
0
|
0
|
|
|
|
|
--$self->{_level} if $self->{_level} > 0; |
339
|
0
|
|
|
|
|
|
return $self; |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
# Return a string of spaces according to the current indentation level and the |
343
|
|
|
|
|
|
|
# spaces setting for indenting. |
344
|
|
|
|
|
|
|
sub _indent { |
345
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
346
|
0
|
0
|
|
|
|
|
if ($self->{_blank_line}) { |
347
|
0
|
|
|
|
|
|
return $self->{indent} x $self->{_level}; |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
else { |
350
|
0
|
|
|
|
|
|
return $self->{space}; |
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
# Add a line break, but make sure there are no empty lines. |
355
|
|
|
|
|
|
|
sub _new_line { |
356
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
357
|
0
|
0
|
|
|
|
|
$self->{_output} .= $self->{break} unless $self->{_blank_line}; |
358
|
0
|
|
|
|
|
|
$self->{_blank_line} = 1; |
359
|
0
|
|
|
|
|
|
return $self; |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
0
|
0
|
|
0
|
|
|
sub _next_token { scalar @{ $_[0]->{tokens} } ? $_[0]->{tokens}->[0] : '' } |
|
0
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
sub _next_keyword { |
365
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
366
|
0
|
|
|
|
|
|
my $len = scalar @{ $self->{tokens} }; |
|
0
|
|
|
|
|
|
|
367
|
0
|
|
|
|
|
|
for (my $i = 0; $i < $len; $i++) { |
368
|
0
|
0
|
|
|
|
|
if ($self->_is_keyword(uc $self->{tokens}->[$i])) { |
369
|
0
|
|
|
|
|
|
return(uc $self->{tokens}->[$i]); |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
} |
372
|
0
|
|
|
|
|
|
return ''; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
0
|
0
|
0
|
0
|
|
|
sub _is_keyword { defined $_[1] && exists $Keyword->{$_[1]} ? $Keyword->{$_[1]} : 0 } |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
sub lexicals { |
378
|
0
|
|
|
0
|
1
|
|
my ($proto, $sql, $omit_whitespace_tokens) = @_; |
379
|
0
|
|
|
|
|
|
my @tokens = $sql =~ m{ |
380
|
|
|
|
|
|
|
(?:--|\#)[\ \t\S]* # single line comments |
381
|
|
|
|
|
|
|
| |
382
|
|
|
|
|
|
|
(?:<>|<=>|>=|<=|==|=|!=|!|<<|>>|<|>|\|\||\||&&|&|-|\+|\*(?!/)|/(?!\*)|\%|~|\^|\?) |
383
|
|
|
|
|
|
|
# operators and tests |
384
|
|
|
|
|
|
|
| |
385
|
|
|
|
|
|
|
[\[\]\(\),;.] # punctuation (parenthesis, comma) |
386
|
|
|
|
|
|
|
| |
387
|
|
|
|
|
|
|
\'\'(?!\') # empty single quoted string |
388
|
|
|
|
|
|
|
| |
389
|
|
|
|
|
|
|
\"\"(?!\"") # empty double quoted string |
390
|
|
|
|
|
|
|
| |
391
|
|
|
|
|
|
|
".*?(?:(?:""){1,}"|(?
|
392
|
|
|
|
|
|
|
# anything inside double quotes, ungreedy |
393
|
|
|
|
|
|
|
| |
394
|
|
|
|
|
|
|
`.*?(?:(?:``){1,}`|(?
|
395
|
|
|
|
|
|
|
# anything inside backticks quotes, ungreedy |
396
|
|
|
|
|
|
|
| |
397
|
|
|
|
|
|
|
'.*?(?:(?:''){1,}'|(?
|
398
|
|
|
|
|
|
|
# anything inside single quotes, ungreedy. |
399
|
|
|
|
|
|
|
| |
400
|
|
|
|
|
|
|
/\*[\ \t\n\S]*?\*/ # C style comments |
401
|
|
|
|
|
|
|
| |
402
|
|
|
|
|
|
|
(?:[\w:@]+(?:\.(?:\w+|\*)?)*) |
403
|
|
|
|
|
|
|
# words, standard named placeholders, db.table.*, db.* |
404
|
|
|
|
|
|
|
| |
405
|
|
|
|
|
|
|
(?:\${1,2}) # dollars |
406
|
|
|
|
|
|
|
| |
407
|
|
|
|
|
|
|
[\t\ ]+ # any kind of white spaces |
408
|
|
|
|
|
|
|
}mxg; |
409
|
|
|
|
|
|
|
|
410
|
0
|
0
|
|
|
|
|
@tokens = grep(!/^[\s\n\r]*$/, @tokens) if $omit_whitespace_tokens; |
411
|
0
|
0
|
|
|
|
|
return wantarray ? @tokens : \@tokens; |
412
|
|
|
|
|
|
|
} |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
sub passthrough { |
415
|
0
|
|
|
0
|
1
|
|
my ($class, @args) = @_; |
416
|
0
|
|
|
|
|
|
my %param; |
417
|
0
|
0
|
|
|
|
|
if (ref($class)) { |
418
|
0
|
|
|
|
|
|
die "'passthrough' is a class method"; |
419
|
|
|
|
|
|
|
} |
420
|
0
|
|
|
|
|
|
eval { |
421
|
0
|
|
0
|
|
|
|
%param = @args || (); |
422
|
|
|
|
|
|
|
}; |
423
|
0
|
0
|
|
|
|
|
if ($@) { |
424
|
0
|
|
|
|
|
|
die "Options should be passed in hash style\n". $@; |
425
|
|
|
|
|
|
|
} |
426
|
0
|
|
|
|
|
|
local($/) = ''; |
427
|
0
|
|
|
|
|
|
print $class->format(sql => <>); |
428
|
|
|
|
|
|
|
} |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
1; |
431
|
|
|
|
|
|
|
__END__ |