File Coverage

blib/lib/Pg/SQL/PrettyPrinter/Node/A_Expr.pm
Criterion Covered Total %
statement 139 142 97.8
branch 81 88 92.0
condition 4 12 33.3
subroutine 21 21 100.0
pod 4 4 100.0
total 249 267 93.2


line stmt bran cond sub pod time code
1             package Pg::SQL::PrettyPrinter::Node::A_Expr;
2              
3             # UTF8 boilerplace, per http://stackoverflow.com/questions/6162484/why-does-modern-perl-avoid-utf-8-by-default/
4 5     5   3573 use v5.26;
  5         20  
5 5     5   27 use strict;
  5         15  
  5         103  
6 5     5   38 use warnings;
  5         21  
  5         148  
7 5     5   29 use warnings qw( FATAL utf8 );
  5         11  
  5         185  
8 5     5   31 use utf8;
  5         10  
  5         50  
9 5     5   131 use open qw( :std :utf8 );
  5         29  
  5         35  
10 5     5   679 use Unicode::Normalize qw( NFC );
  5         13  
  5         346  
11 5     5   45 use Unicode::Collate;
  5         27  
  5         185  
12 5     5   28 use Encode qw( decode );
  5         12  
  5         310  
13              
14             if ( grep /\P{ASCII}/ => @ARGV ) {
15             @ARGV = map { decode( 'UTF-8', $_ ) } @ARGV;
16             }
17              
18             # If there is __DATA__,then uncomment next line:
19             # binmode( DATA, ':encoding(UTF-8)' );
20             # UTF8 boilerplace, per http://stackoverflow.com/questions/6162484/why-does-modern-perl-avoid-utf-8-by-default/
21              
22             # Useful common code
23 5     5   1069 use autodie;
  5         13  
  5         33  
24 5     5   27338 use Carp qw( carp croak confess cluck );
  5         12  
  5         390  
25 5     5   63 use English qw( -no_match_vars );
  5         12  
  5         31  
26 5     5   1854 use Data::Dumper qw( Dumper );
  5         12  
  5         1077  
27              
28             # give a full stack dump on any untrapped exceptions
29             local $SIG{ __DIE__ } = sub {
30             confess "Uncaught exception: @_" unless $^S;
31             };
32              
33             # now promote run-time warnings into stackdumped exceptions
34             # *unless* we're in an try block, in which
35             # case just generate a clucking stackdump instead
36             local $SIG{ __WARN__ } = sub {
37             if ( $^S ) { cluck "Trapped warning: @_" }
38             else { confess "Deadly warning: @_" }
39             };
40              
41             # Useful common code
42              
43 5     5   37 use parent qw( Pg::SQL::PrettyPrinter::Node );
  5         11  
  5         31  
44 5     5   336 use List::Util qw( any );
  5         11  
  5         10054  
45              
46             sub new {
47 76     76 1 2343 my $class = shift;
48 76         269 my $self = $class->SUPER::new( @_ );
49 76         168 bless $self, $class;
50              
51 76         175 my @types_ok = map { 'AEXPR_' . $_ } qw( BETWEEN IN OP OP_ALL OP_ANY NOT_BETWEEN BETWEEN_SYM NOT_BETWEEN_SYM DISTINCT NOT_DISTINCT LIKE ILIKE NULLIF SIMILAR );
  1064         2154  
52 76         173 my %type_is_ok = map { $_ => 1 } @types_ok;
  1064         2040  
53 76 50       336 if ( !$type_is_ok{ $self->{ 'kind' } } ) {
54 0         0 croak( "Unsupported A_Expr kind: " . $self->{ 'kind' } );
55             }
56              
57 76         305 $self->objectify( 'name', 'rexpr', 'lexpr' );
58 76         397 return $self;
59             }
60              
61             sub operator {
62 167     167 1 290 my $self = shift;
63 167 100       244 if ( 1 == scalar @{ $self->{ 'name' } } ) {
  167         400  
64 165         509 return $self->{ 'name' }->[ 0 ]->{ 'str' };
65             }
66 2         10 my @elements = map { $_->as_ident() } @{ $self->{ 'name' } };
  4         9  
  2         5  
67 2         8 $elements[ -1 ] = $self->{ 'name' }->[ -1 ]->{ 'str' };
68 2         11 return sprintf( "OPERATOR( %s )", join( '.', @elements ) );
69             }
70              
71             sub as_text {
72 79     79 1 152 my $self = shift;
73              
74 79 100       551 if ( $self->{ 'kind' } eq 'AEXPR_IN' ) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
75             return sprintf(
76             '%s IN %s',
77             $self->{ 'lexpr' }->as_text,
78 2         6 $self->{ 'rexpr' }->as_text
79             );
80             }
81             elsif ( $self->{ 'kind' } eq 'AEXPR_OP_ANY' ) {
82             return sprintf(
83             '%s %s ANY( %s )',
84             $self->{ 'lexpr' }->as_text,
85             $self->operator,
86 1         4 $self->{ 'rexpr' }->as_text
87             );
88             }
89             elsif ( $self->{ 'kind' } eq 'AEXPR_OP_ALL' ) {
90             return sprintf(
91             '%s %s ALL( %s )',
92             $self->{ 'lexpr' }->as_text,
93             $self->operator,
94 1         5 $self->{ 'rexpr' }->as_text
95             );
96             }
97 291     291   831 elsif ( any { $_ eq $self->{ 'kind' } } qw( AEXPR_BETWEEN AEXPR_NOT_BETWEEN AEXPR_BETWEEN_SYM AEXPR_NOT_BETWEEN_SYM ) ) {
98             return sprintf(
99             '%s %s %s AND %s',
100             $self->{ 'lexpr' }->as_text,
101             $self->operator,
102             $self->{ 'rexpr' }->{ 'items' }->[ 0 ]->as_text,
103 5         16 $self->{ 'rexpr' }->{ 'items' }->[ 1 ]->as_text,
104             );
105             }
106             elsif ( $self->{ 'kind' } eq 'AEXPR_DISTINCT' ) {
107             return sprintf(
108             '%s IS DISTINCT FROM %s',
109             $self->{ 'lexpr' }->as_text,
110 2         8 $self->{ 'rexpr' }->as_text,
111             );
112             }
113             elsif ( $self->{ 'kind' } eq 'AEXPR_NOT_DISTINCT' ) {
114             return sprintf(
115             '%s IS NOT DISTINCT FROM %s',
116             $self->{ 'lexpr' }->as_text,
117 2         8 $self->{ 'rexpr' }->as_text,
118             );
119             }
120             elsif ( $self->{ 'kind' } eq 'AEXPR_LIKE' ) {
121             return sprintf(
122             '%s LIKE %s',
123             $self->{ 'lexpr' }->as_text,
124 1         6 $self->{ 'rexpr' }->as_text,
125             );
126             }
127             elsif ( $self->{ 'kind' } eq 'AEXPR_NULLIF' ) {
128             return sprintf(
129             'NULLIF( %s, %s )',
130             $self->{ 'lexpr' }->as_text,
131 1         8 $self->{ 'rexpr' }->as_text,
132             );
133             }
134             elsif ( $self->{ 'kind' } eq 'AEXPR_ILIKE' ) {
135             return sprintf(
136             '%s ILIKE %s',
137             $self->{ 'lexpr' }->as_text,
138 1         5 $self->{ 'rexpr' }->as_text,
139             );
140             }
141             elsif ( $self->{ 'kind' } eq 'AEXPR_SIMILAR' ) {
142 1         4 my $right_side;
143 1 50 33     14 if ( ( $self->{ 'rexpr' }->isa( 'Pg::SQL::PrettyPrinter::Node::FuncCall' ) )
      33        
144             && ( $self->{ 'rexpr' }->func_name eq 'pg_catalog.similar_to_escape' )
145 1         6 && ( 1 == scalar @{ $self->{ 'rexpr' }->{ 'args' } } ) )
146             {
147 1         7 $right_side = $self->{ 'rexpr' }->{ 'args' }->[ 0 ]->as_text;
148             }
149             else {
150 0         0 $right_side = $self->{ 'rexpr' }->as_text;
151             }
152             return sprintf(
153             '%s SIMILAR TO %s',
154 1         12 $self->{ 'lexpr' }->as_text,
155             $right_side,
156             );
157             }
158              
159 62         203 my @parts = ();
160 62 100       184 if ( exists $self->{ 'lexpr' } ) {
161 61         128 my $this_expr = '';
162 61         102 my $add_parens = 0;
163 61 100       344 if ( $self->{ 'lexpr' }->isa( 'Pg::SQL::PrettyPrinter::Node::A_Expr' ) ) {
164 7 100       16 $add_parens = 1 if $self->{ 'lexpr' }->operator ne $self->operator;
165             }
166 61 100       141 $this_expr .= '( ' if $add_parens;
167 61         190 $this_expr .= $self->{ 'lexpr' }->as_text;
168 61 100       171 $this_expr .= ' )' if $add_parens;
169 61         135 push @parts, $this_expr;
170             }
171              
172 62         153 push @parts, $self->operator;
173              
174 62 50       165 if ( exists $self->{ 'rexpr' } ) {
175 62         103 my $this_expr = '';
176 62         106 my $add_parens = 0;
177 62 100       252 if ( $self->{ 'rexpr' }->isa( 'Pg::SQL::PrettyPrinter::Node::A_Expr' ) ) {
178 2 50       13 $add_parens = 1 if $self->{ 'rexpr' }->operator ne $self->operator;
179             }
180 62 100       142 $this_expr .= '( ' if $add_parens;
181 62         161 $this_expr .= $self->{ 'rexpr' }->as_text;
182 62 100       210 $this_expr .= ' )' if $add_parens;
183 62         141 push @parts, $this_expr;
184             }
185              
186 62         212 return join( ' ', @parts );
187             }
188              
189             sub pretty_print {
190 72     72 1 130 my $self = shift;
191 72 100       510 if ( $self->{ 'kind' } eq 'AEXPR_IN' ) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
192             return sprintf(
193             '%s IN %s',
194             $self->{ 'lexpr' }->pretty_print,
195 2         7 $self->{ 'rexpr' }->pretty_print
196             );
197             }
198             elsif ( $self->{ 'kind' } eq 'AEXPR_OP_ANY' ) {
199             return sprintf(
200             '%s %s ANY( %s )',
201             $self->{ 'lexpr' }->pretty_print,
202             $self->operator,
203 1         7 $self->{ 'rexpr' }->pretty_print
204             );
205             }
206             elsif ( $self->{ 'kind' } eq 'AEXPR_OP_ALL' ) {
207             return sprintf(
208             '%s %s ALL( %s )',
209             $self->{ 'lexpr' }->pretty_print,
210             $self->operator,
211 1         8 $self->{ 'rexpr' }->pretty_print
212             );
213             }
214 263     263   679 elsif ( any { $_ eq $self->{ 'kind' } } qw( AEXPR_BETWEEN AEXPR_NOT_BETWEEN AEXPR_BETWEEN_SYM AEXPR_NOT_BETWEEN_SYM ) ) {
215             return sprintf(
216             '%s %s %s AND %s',
217             $self->{ 'lexpr' }->pretty_print,
218             $self->operator,
219             $self->{ 'rexpr' }->{ 'items' }->[ 0 ]->pretty_print,
220 5         16 $self->{ 'rexpr' }->{ 'items' }->[ 1 ]->pretty_print,
221             );
222             }
223             elsif ( $self->{ 'kind' } eq 'AEXPR_DISTINCT' ) {
224             return sprintf(
225             '%s IS DISTINCT FROM %s',
226             $self->{ 'lexpr' }->pretty_print,
227 2         11 $self->{ 'rexpr' }->pretty_print,
228             );
229             }
230             elsif ( $self->{ 'kind' } eq 'AEXPR_NOT_DISTINCT' ) {
231             return sprintf(
232             '%s IS NOT DISTINCT FROM %s',
233             $self->{ 'lexpr' }->pretty_print,
234 2         9 $self->{ 'rexpr' }->pretty_print,
235             );
236             }
237             elsif ( $self->{ 'kind' } eq 'AEXPR_LIKE' ) {
238             return sprintf(
239             '%s LIKE %s',
240             $self->{ 'lexpr' }->pretty_print,
241 1         6 $self->{ 'rexpr' }->pretty_print,
242             );
243             }
244             elsif ( $self->{ 'kind' } eq 'AEXPR_NULLIF' ) {
245             return sprintf(
246             'NULLIF( %s, %s )',
247             $self->{ 'lexpr' }->pretty_print,
248 1         6 $self->{ 'rexpr' }->pretty_print,
249             );
250             }
251             elsif ( $self->{ 'kind' } eq 'AEXPR_ILIKE' ) {
252             return sprintf(
253             '%s ILIKE %s',
254             $self->{ 'lexpr' }->pretty_print,
255 1         6 $self->{ 'rexpr' }->pretty_print,
256             );
257             }
258             elsif ( $self->{ 'kind' } eq 'AEXPR_SIMILAR' ) {
259 1         3 my $right_side;
260 1 50 33     14 if ( ( $self->{ 'rexpr' }->isa( 'Pg::SQL::PrettyPrinter::Node::FuncCall' ) )
      33        
261             && ( $self->{ 'rexpr' }->func_name eq 'pg_catalog.similar_to_escape' )
262 1         4 && ( 1 == scalar @{ $self->{ 'rexpr' }->{ 'args' } } ) )
263             {
264 1         5 $right_side = $self->{ 'rexpr' }->{ 'args' }->[ 0 ]->pretty_print;
265             }
266             else {
267 0         0 $right_side = $self->{ 'rexpr' }->pretty_print;
268             }
269             return sprintf(
270             '%s SIMILAR TO %s',
271 1         5 $self->{ 'lexpr' }->pretty_print,
272             $right_side,
273             );
274             }
275              
276 55         185 my @parts = ();
277 55 100       131 if ( exists $self->{ 'lexpr' } ) {
278 54         100 my $this_expr = '';
279 54         84 my $add_parens = 0;
280 54 100       271 if ( $self->{ 'lexpr' }->isa( 'Pg::SQL::PrettyPrinter::Node::A_Expr' ) ) {
281 7 100       15 $add_parens = 1 if $self->{ 'lexpr' }->operator ne $self->operator;
282             }
283 54 100       129 $this_expr .= '( ' if $add_parens;
284 54         178 $this_expr .= $self->{ 'lexpr' }->pretty_print;
285 54 100       157 $this_expr .= ' )' if $add_parens;
286 54         116 push @parts, $this_expr;
287             }
288              
289 55         136 push @parts, $self->operator;
290              
291 55 50       139 if ( exists $self->{ 'rexpr' } ) {
292 55         99 my $this_expr = '';
293 55         95 my $add_parens = 0;
294 55 100       196 if ( $self->{ 'rexpr' }->isa( 'Pg::SQL::PrettyPrinter::Node::A_Expr' ) ) {
295 2 50       5 $add_parens = 1 if $self->{ 'rexpr' }->operator ne $self->operator;
296             }
297 55 100       132 $this_expr .= '( ' if $add_parens;
298 55         147 $this_expr .= $self->{ 'rexpr' }->pretty_print;
299 55 100       157 $this_expr .= ' )' if $add_parens;
300 55         121 push @parts, $this_expr;
301             }
302              
303 55         210 return join( ' ', @parts );
304             }
305              
306             1;