File Coverage

blib/lib/DBIx/Perlish/Parse.pm
Criterion Covered Total %
statement 1109 1339 82.8
branch 698 1014 68.8
condition 231 397 58.1
subroutine 98 105 93.3
pod 0 90 0.0
total 2136 2945 72.5


line stmt bran cond sub pod time code
1             package DBIx::Perlish::Parse;
2 26     26   491 use 5.014;
  26         176  
3 26     26   131 use warnings;
  26         44  
  26         1394  
4 26     26   146 use strict;
  26         41  
  26         1633  
5              
6             our $DEVEL;
7             our $_cover;
8              
9 26     26   148 use B;
  26         60  
  26         806  
10 26     26   125 use Carp;
  26         40  
  26         2101  
11 26     26   15594 use Devel::Caller qw(caller_cv);
  26         105478  
  26         604793  
12              
13 0 0   0   0 sub _o($) { ref($_[0]) . sprintf (" (0x%x)", ${$_[0]}) . ( $_[0]->can('name') ? (" " . $_[0]->name) : '' ) }
  0         0  
14              
15             sub bailout
16             {
17 57     57 0 241 my ($S, @rest) = @_;
18 57 50       171 if ($DEVEL) {
19 0         0 confess @rest;
20             } else {
21 57         185 my $args = join '', @rest;
22 57 50       202 $args = "Something's wrong" unless $args;
23 57         139 my $file = $S->{file};
24 57         126 my $line = $S->{line};
25 57 100       340 $args .= " at $file line $line.\n"
26             unless substr($args, length($args) -1) eq "\n";
27 57         2081 CORE::die($args);
28             }
29             }
30              
31             # "is" checks
32              
33             sub is
34             {
35 55753     55753 0 116746 my ($optype, $op, $name) = @_;
36 55753 100       899474 return 0 unless ref($op) eq $optype;
37 17173 100       59973 return 1 unless $name;
38 15281         229964 return $op->name eq $name;
39             }
40              
41             sub gen_is
42             {
43 364     364 0 841 my ($optype) = @_;
44 364         720 my $pkg = "B::" . uc($optype);
45 364 50   5246 0 18830 eval qq[ sub is_$optype { is("$pkg", \@_) } ] unless __PACKAGE__->can("is_$optype");
  5246     1282 0 13721  
  1282     7349 0 3662  
  7349     4005 0 24163  
  4005     8 0 14394  
  8     818 0 26  
  818     3459 0 2501  
  3459     13489 0 8501  
  13489     821 0 52520  
  821     154 0 2345  
  154     69 0 501  
  69     2582 0 228  
  2582     16125 0 6954  
  16125     346 0 41395  
  346         1067  
46             }
47              
48             gen_is("binop");
49             gen_is("pvop");
50             gen_is("cop");
51             gen_is("listop");
52             gen_is("logop");
53             gen_is("loop");
54             gen_is("null");
55             gen_is("op");
56             gen_is("padop");
57             gen_is("svop");
58             gen_is("unop");
59             gen_is("pmop");
60             gen_is("methop");
61             gen_is("unop_aux");
62              
63             sub is_const
64             {
65 1558     1558 0 3416 my ($S, $op) = @_;
66 1558 100       38827 return () unless is_svop($op, "const");
67 953         3530 my $sv = $op->sv;
68 953 50       2346 if (!$$sv) {
69 0         0 $sv = $S->{padlist}->[1]->ARRAYelt($op->targ);
70             }
71 953 100       2189 if (wantarray) {
72 123         238 return (${$sv->object_2svref}, $sv);
  123         854  
73             } else {
74 830         1228 return ${$sv->object_2svref};
  830         3716  
75             }
76             }
77              
78             # "want" helpers
79              
80             sub gen_want
81             {
82 130     130 0 401 my ($optype, $return) = @_;
83 130 100       791 if (!$return) {
    100          
84 52         108 $return = '$op';
85             } elsif ($return =~ /^\w+$/) {
86 52         133 $return = '$op->' . $return;
87             }
88 130 50   6 0 14984 eval <can("want_$optype");
  6 0   382 0 25  
  6 50   0 0 170  
  0 0   8 0 0  
  0 50   1043 0 0  
  6 0       26  
  382 0       1109  
  382 0       8491  
  0 50       0  
  0 0       0  
  382 50       970  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  8         22  
  8         260  
  0         0  
  0         0  
  8         59  
  1043         2997  
  1043         23818  
  0         0  
  0         0  
  1043         6066  
89             sub want_$optype {
90             my (\$S, \$op, \$n) = \@_;
91             unless (is_$optype(\$op, \$n)) {
92             bailout \$S, "want $optype" unless \$n;
93             bailout \$S, "want $optype \$n";
94             }
95             $return;
96             }
97             EOF
98             }
99              
100             gen_want("op");
101             gen_want("unop", "first");
102             gen_want("listop", 'get_all_children($op)');
103             gen_want("svop", "sv");
104             gen_want("null");
105              
106             sub is_pushmark_or_padrange
107             {
108 3433     3433 0 8164 my $op = shift;
109 3433   100     77098 return is_op($op, "pushmark") || is_op($op, "padrange");
110             }
111              
112             sub want_pushmark_or_padrange
113             {
114 382     382 0 895 my ($S, $op) = @_;
115 382 50       998 unless (is_pushmark_or_padrange($op)) {
116 0         0 bailout $S, "want op pushmark or op padrange, got " . _o $op;
117             }
118             }
119              
120             sub want_const
121             {
122 8     8 0 23 my ($S, $op) = @_;
123 8         218 my $sv = want_svop($S, $op, "const");
124 8 50       29 if (!$$sv) {
125 0         0 $sv = $S->{padlist}->[1]->ARRAYelt($op->targ);
126             }
127 8         15 ${$sv->object_2svref};
  8         55  
128             }
129              
130             sub want_variable_method
131             {
132 2     2 0 5 my ($S, $op) = @_;
133 2 50 33     40 return unless is_unop($op, "method") || is_methop($op, "method");
134 2         6 $op = $op->first;
135 2 50       43 return unless is_null($op->sibling);
136 2         8 my ($name, $ok) = get_value($S, $op, soft => 1);
137 2 50       5 return unless $ok;
138 2         5 return $name;
139             }
140              
141             sub want_method
142             {
143 599     599 0 1531 my ($S, $op) = @_;
144 599         954 my $sv;
145 599 100       16297 if ( is_methop($op, "method_named")) {
    50          
146 597         2294 $sv = $op->meth_sv;
147             } elsif ( is_svop($op, "method_named")) {
148 0         0 $sv = $op->sv;
149             } else {
150 2         6 my $r = want_variable_method($S, $op);
151 2 50       6 bailout $S, "method call syntax expected" unless $r;
152 2         5 return $r;
153             }
154 597 50       1641 if (!$$sv) {
155 0         0 $sv = $S->{padlist}->[1]->ARRAYelt($op->targ);
156             }
157 597         975 ${$sv->object_2svref};
  597         3928  
158             }
159              
160             # getters
161              
162             sub get_all_children
163             {
164 555     555 0 1162 my ($op) = @_;
165 555         2085 my $c = $op->children;
166 555         982 my @op;
167 555 50       1452 return @op unless $c;
168 555         3509 push @op, $op->first;
169 555         2099 while (--$c) {
170 1293         5595 push @op, $op[-1]->sibling;
171             }
172 555         2559 @op;
173             }
174              
175             sub padname
176             {
177 599     599 0 1353 my ($S, $op, %p) = @_;
178              
179 599         13182 my $padname = $S->{padlist}->[0]->ARRAYelt($op->targ);
180 599 50 33     7030 if ($padname && !$padname->isa("B::SPECIAL")) {
181 599 50 66     1924 return if $p{no_fakes} && $padname->FLAGS & B::SVf_FAKE;
182 599 100       2344 return unless defined $padname->PVX;
183 596         3083 return "my " . $padname->PVX;
184             } else {
185 0         0 return "my #" . $op->targ;
186             }
187             }
188              
189             sub get_padlist_scalar_by_name
190             {
191 6     6 0 12 my ($S, $n) = @_;
192 6         11 my $padlist = $S->{padlist};
193 6         53 my @n = $padlist->[0]->ARRAY;
194 6         21 for (my $k = 0; $k < @n; $k++) {
195 34 50       65 next if $n[$k]->isa("B::SPECIAL");
196 34 50       77 next if $n[$k]->isa("B::NULL");
197 34 100 100     134 if (($n[$k]->PVX // '') eq $n) {
198 6         20 my $v = $padlist->[1]->ARRAYelt($k);
199 6 100       20 if (!$v->isa("B::SPECIAL")) {
200 3         17 return $v;
201             }
202 3 50       19 if ($n[$k]->FLAGS & B::SVf_FAKE) {
203             bailout $S, "internal error: cannot retrieve value of $n: no more scopes to check"
204 3 50       12 unless $S->{gen_args}->{prev_S};
205 3         17 return get_padlist_scalar_by_name($S->{gen_args}->{prev_S}, $n);
206             }
207 0         0 bailout $S, "internal error: cannot retrieve value of $n: it's an in-scope SPECIAL";
208             }
209             }
210 0         0 bailout $S, "internal error: cannot retrieve value of $n: not found in outer scope";
211             }
212              
213             sub get_padlist_scalar
214             {
215 51     51 0 146 my ($S, $i, $ref_only) = @_;
216 51         132 my $padlist = $S->{padlist};
217 51         275 my $v = $padlist->[1]->ARRAYelt($i);
218 51 50       280 bailout $S, "internal error: no such pad element" unless $v;
219 51 100       396 if ($v->isa("B::SPECIAL")) {
220 3         13 my $n = $padlist->[0]->ARRAYelt($i);
221 3 50       15 if ($n->FLAGS & B::SVf_FAKE) {
222 3         27 $v = get_padlist_scalar_by_name($S, $n->PVX);
223             } else {
224 0         0 bailout $S, "internal error: cannot retrieve in-scope SPECIAL";
225             }
226             }
227 51         217 $v = $v->object_2svref;
228 51 100       143 return $v if $ref_only;
229 44         144 return $$v;
230             }
231              
232             sub bailout_multiref_vivify($)
233             {
234 5     5 0 12 my $S = shift;
235 5         20 bailout $S,
236             "accessing fields syntax is not supported anymore; for tables use methods instead, ".
237             "for arrayrefs and hashrefs don't leave them unassigned"
238             }
239              
240             sub aux_init_padsv
241             {
242 56     56 0 142 my ( $S ) = @_;
243              
244 56         322 my $inner = $S->{curr_cv}->PADLIST;
245             return {
246 56         1498 S => $S,
247             inner => $inner,
248             orig_pads => [ $inner->ARRAY ]->[1],
249             names => [ $inner->NAMES->ARRAY ],
250             outer_padlist => undef,
251             outer_padlist_array => undef,
252             padlist => [],
253             };
254             }
255              
256             sub aux_get_padsv
257             {
258 64     64 0 162 my ( $store, $index ) = @_;
259              
260 64 50       195 unless ( defined $store->{padlist}->[$index] ) {
261 64         153 my $padname = $store->{names}->[$index];
262 64 100 100     550 if ( $padname->FLAGS & B::SVf_FAKE && $store->{inner}->outid > 1) {
263 3 50       12 unless ($store->{outer_padlist}) {
264 3         16 $store->{outer_padlist} = $store->{S}->{padlists}->{$store->{inner}->outid};
265 3 100       10 unless ($store->{outer_padlist}) {
266             # hacky hacky - look up the caller stack to get their padlists, maybe?
267 1         3 my $id = 0;
268 1         2 while ( 1 ) {
269 14 50       35 my $sub = caller_cv($id++) or last;
270 14         162 my $padlist = B::svref_2object($sub)->PADLIST;
271 14   100     125 $store->{S}->{padlists}->{$padlist->id} //= [$padlist->ARRAY];
272 14 100       55 next unless $padlist->id == $store->{inner}->outid;
273 1         5 $store->{outer_padlist} = $store->{S}->{padlists}->{$store->{inner}->outid};
274 1         4 last;
275             }
276             }
277 3 50       8 goto DEFAULT_PADLIST unless $store->{outer_padlist};
278 3         29 $store->{outer_padlist_array} = [$store->{outer_padlist}->[1]->ARRAY];
279             }
280 3         13 $store->{padlist}->[$index] = $store->{outer_padlist_array}->[ $padname->PARENT_PAD_INDEX ];
281             } else {
282             DEFAULT_PADLIST:
283 61         368 $store->{padlist}->[$index] = $store->{orig_pads}->ARRAYelt($index);
284             }
285             }
286              
287 64         309 return $store->{padlist}->[$index];
288             }
289              
290             sub parse_multideref
291             {
292 56     56 0 154 my ( $S, $aux ) = @_;
293 56         412 my @items = $aux->aux_list($S->{curr_cv});
294 56         144 my @ret;
295              
296 56         234 my $AUX = aux_init_padsv($S);
297              
298 56         281 ITEMS: while ( @items ) {
299 56         147 my $actions = shift @items;
300              
301 56         123 my ($ref, $reftype);
302 56 50       185 my $sv = shift(@items) or return undef;
303              
304 56         184 while ( @items ) {
305 81         151 my $ptr = shift @items;
306 81         186 my $access = $actions & B::MDEREF_ACTION_MASK();
307 81 50       220 if ( $access == B::MDEREF_reload() ) { # XXX
308 0         0 $actions = $sv;
309 0         0 next;
310             }
311 81 100       242 unless ($ref) {
312 57 100 66     611 if (
    100 100        
    50 100        
    0 66        
      100        
      33        
      33        
      0        
313             $access == B::MDEREF_HV_padhv_helem() ||
314             $access == B::MDEREF_AV_padav_aelem() ||
315             $access == B::MDEREF_HV_padsv_vivify_rv2hv_helem() ||
316             $access == B::MDEREF_AV_padsv_vivify_rv2av_aelem()
317             ) {
318 52         218 $ref = aux_get_padsv($AUX, $sv)->object_2svref;
319 52 100 66     398 bailout_multiref_vivify $S
      66        
320             if !$ref || ((ref($ref) eq 'SCALAR') && !$$ref);
321             } elsif (
322             $access == B::MDEREF_HV_pop_rv2hv_helem() ||
323             $access == B::MDEREF_HV_vivify_rv2hv_helem() ||
324             $access == B::MDEREF_HV_gvhv_helem()
325             ) {
326 3 100       12 bailout_multiref_vivify $S unless ref($sv);
327 2         15 $ref = $sv->HV->object_2svref;
328             } elsif (
329             $access == B::MDEREF_AV_pop_rv2av_aelem() ||
330             $access == B::MDEREF_AV_vivify_rv2av_aelem() ||
331             $access == B::MDEREF_AV_gvav_aelem()
332             ) {
333 2 50       7 bailout_multiref_vivify $S unless ref($sv);
334 2         27 $ref = $sv->AV->object_2svref;
335             } elsif (
336             $access == B::MDEREF_AV_gvsv_vivify_rv2av_aelem() ||
337             $access == B::MDEREF_HV_gvsv_vivify_rv2hv_helem()
338             ) {
339 0         0 $ref = $sv->object_2svref;
340 0 0 0     0 bailout_multiref_vivify $S
      0        
341             if !$ref || ((ref($ref) eq 'SCALAR') && !$$ref);
342 0         0 $ref = $$ref;
343             } else {
344 0         0 bailout $S, "don't quite know what to do with multideref access=$access";
345             }
346             }
347              
348             $reftype = (
349 76 100 100     707 $access == B::MDEREF_HV_padhv_helem() ||
350             $access == B::MDEREF_HV_gvsv_vivify_rv2hv_helem() ||
351             $access == B::MDEREF_HV_padsv_vivify_rv2hv_helem() ||
352             $access == B::MDEREF_HV_pop_rv2hv_helem() ||
353             $access == B::MDEREF_HV_vivify_rv2hv_helem() ||
354             $access == B::MDEREF_HV_gvhv_helem()
355             ) ? 'HASH' : 'ARRAY';
356            
357 76         134 my $key;
358 76         144 my $index = $actions & B::MDEREF_INDEX_MASK();
359              
360 76 50       223 if ( $index != B::MDEREF_INDEX_none() ) {
361 76 100       206 if ( $index == B::MDEREF_INDEX_const() ) {
    50          
    0          
362 64 100       234 $key = ref($ptr) ? $ptr->object_2svref : $ptr;
363             } elsif ( $index == B::MDEREF_INDEX_padsv() ) {
364 12         30 $key = aux_get_padsv($AUX, $ptr)->object_2svref;
365             } elsif ( $index == B::MDEREF_INDEX_gvsv() ) {
366 0 0       0 $key = ref($ptr) ? $ptr->object_2svref : $ptr;
367             }
368              
369 76 100       581 $ref = $$ref if ref($ref) =~ /REF|SCALAR/;
370 76 100       483 $key = $$key if ref($key) =~ /REF|SCALAR/;
371              
372 76 100       193 if ( $reftype eq 'ARRAY') {
373 20         55 $ref = $ref->[$key];
374             } else {
375 56         159 $ref = $ref->{$key};
376             }
377              
378 76 100 66     240 if (!defined($ref) && (
      66        
379             $access == B::MDEREF_AV_gvsv_vivify_rv2av_aelem () ||
380             $access == B::MDEREF_AV_padsv_vivify_rv2av_aelem() ||
381             $access == B::MDEREF_AV_vivify_rv2av_aelem () ||
382             $access == B::MDEREF_HV_gvsv_vivify_rv2hv_helem () ||
383             $access == B::MDEREF_HV_padsv_vivify_rv2hv_helem() ||
384             $access == B::MDEREF_HV_vivify_rv2hv_helem ()
385             )) {
386 2         4 push @ret, undef;
387 2         8 last ITEMS;
388             }
389             }
390 74 50 33     363 if ($index == B::MDEREF_INDEX_none() || $index & B::MDEREF_FLAG_last()) {
391 0         0 push @ret, $ref;
392 0         0 last;
393             }
394 74         316 $actions >>= B::MDEREF_SHIFT();
395             }
396              
397 49 50       260 push @ret, $ref unless @ret;
398             }
399              
400 51 50       141 bailout $S, "cannot infer single multideref value" unless 1 == @ret;
401              
402 51         465 return $ret[0];
403             }
404              
405             sub get_concat_value
406             {
407 0     0 0 0 my ( $S, @args) = @_;
408 0         0 my $val = '';
409 0         0 for my $op ( @args ) {
410 0         0 my ($rv, $ok);
411 0 0       0 if ( $rv = is_const($S, $op)) {
412             } else {
413 0         0 ($rv, $ok) = get_value($S, $op, soft => 1, eval => 1);
414 0 0       0 bailout $S, "cannot parse expression (near $val)" unless $ok;
415             }
416 0         0 $val .= $rv;
417             }
418 0         0 return $val;
419             }
420              
421             sub get_value
422             {
423 280     280 0 1180 my ($S, $op, %p) = @_;
424              
425 280         580 my $val;
426 280 100 66     7249 if (is_op($op, "padsv")) {
    50 66        
    50 66        
    100 100        
    100 66        
    100 66        
    50 66        
    100          
    50          
    100          
427 44 50       213 if (find_aliased_tab($S, $op)) {
428 0         0 bailout $S, "cannot use a table variable as a value";
429             }
430 44         262 $val = get_padlist_scalar($S, $op->targ);
431             } elsif (is_binop($op, "helem")) {
432 0         0 my @key = is_const($S, $op->last);
433 0         0 my $key = $key[0];
434 0 0       0 unless ( @key ) {
435 0         0 my $xop = $op->last;
436 0 0       0 if (is_op($xop, "padsv")) {
437 0 0       0 if (find_aliased_tab($S, $xop)) {
438 0         0 bailout $S, "cannot use a table variable as a value";
439             }
440 0         0 $key = get_padlist_scalar($S, $xop->targ);
441             } else {
442 0         0 bailout $S, "hash key not understood";
443             }
444             }
445 0         0 $op = $op->first;
446              
447 0         0 my $vv;
448 0 0       0 if (is_op($op, "padhv")) {
    0          
449 0         0 $vv = get_padlist_scalar($S, $op->targ, "ref only");
450             } elsif (is_unop($op, "rv2hv")) {
451 0         0 $op = $op->first;
452 0 0 0     0 if (is_op($op, "padsv")) {
    0 0        
    0          
453 0 0       0 if (find_aliased_tab($S, $op)) {
454 0         0 bailout $S, "cannot use a table variable as a value";
455             }
456 0         0 $vv = get_padlist_scalar($S, $op->targ);
457             } elsif (is_svop($op, "gv") || is_padop($op, "gv")) {
458 0         0 my $gv = get_gv($S, $op, bailout => 1);
459 0         0 $vv = $gv->HV->object_2svref;
460             } elsif (is_binop($op, "helem") || is_binop($op, "aelem")) {
461 0         0 my ($nv, $ok) = get_value($S, $op, %p);
462 0 0       0 $vv = $nv if $ok;
463             }
464             }
465 0         0 $val = $vv->{$key};
466             } elsif (is_binop($op, "aelem")) {
467 0         0 my @key = is_const($S, $op->last);
468 0         0 my $key = $key[0];
469 0 0       0 unless ( @key ) {
470 0         0 my $xop = $op->last;
471 0 0       0 if (is_op($xop, "padsv")) {
472 0 0       0 if (find_aliased_tab($S, $xop)) {
473 0         0 bailout $S, "cannot use a table variable as a value";
474             }
475 0         0 $key = get_padlist_scalar($S, $xop->targ);
476             } else {
477 0         0 bailout $S, "array index not understood";
478             }
479             }
480 0         0 $op = $op->first;
481              
482 0         0 my $vv;
483 0 0       0 if (is_op($op, "padav")) {
    0          
484 0         0 $vv = get_padlist_scalar($S, $op->targ, "ref only");
485             } elsif (is_unop($op, "rv2av")) {
486 0         0 $op = $op->first;
487 0 0 0     0 if (is_op($op, "padsv")) {
    0 0        
    0          
488 0 0       0 if (find_aliased_tab($S, $op)) {
489 0         0 bailout $S, "cannot use a table variable as a value";
490             }
491 0         0 $vv = get_padlist_scalar($S, $op->targ);
492             } elsif (is_svop($op, "gv") || is_padop($op, "gv")) {
493 0         0 my $gv = get_gv($S, $op, bailout => 1);
494 0         0 $vv = $gv->AV->object_2svref;
495             } elsif (is_binop($op, "helem") || is_binop($op, "aelem")) {
496 0         0 my ($nv, $ok) = get_value($S, $op, %p);
497 0 0       0 $vv = $nv if $ok;
498             }
499             }
500 0         0 $val = $vv->[$key];
501             } elsif (is_svop($op, "gvsv") || is_padop($op, "gvsv")) {
502 1         8 my $gv = get_gv($S, $op, bailout => 1);
503 1         3 $val = ${$gv->SV->object_2svref};
  1         17  
504             } elsif (is_unop($op, "null") && (is_svop($op->first, "gvsv") || is_padop($op->first, "gvsv"))) {
505 1         9 my $gv = get_gv($S, $op->first, bailout => 1);
506 1         5 $val = ${$gv->SV->object_2svref};
  1         9  
507             } elsif (is_unop($op, "null") && is_unop_aux($op->first, "multideref")) {
508 13         75 $val = parse_multideref($S, $op->first);
509             } elsif ( $p{eval} && is_binop($op, "concat")) {
510 0         0 my @args = ($op->first);
511 0   0     0 push @args, $args[-1]->sibling while !is_null($args[-1]) && !is_null($args[-1]->sibling);
512 0         0 $val = get_concat_value($S, @args);
513             } elsif ( $p{eval} && is_unop_aux($op, "multiconcat")) {
514 1 50       6 my @terms = parse_multiconcat($S, $op, eval => 1) or goto BAILOUT;
515 1         4 $val = join('', map { $_->{str} } @terms);
  3         12  
516             } elsif (is_op($op, "aelemfast_lex")) {
517 0         0 my $sv = $S->{padlist}->[1]->ARRAYelt($op->targ);
518 0 0       0 goto BAILOUT unless $sv;
519 0         0 $sv = $sv->object_2svref;
520 0         0 $val = $sv->[$op->private];
521             } elsif (is_svop($op, "aelemfast") || is_padop($op, "aelemfast")) {
522             my $sv = is_padop($op, "aelemfast") ?
523 2 50       59 $S->{padlist}->[1]->ARRAYelt($op->padix) :
    50          
524             $op->sv or goto BAILOUT;
525 2 50       26 $sv = $sv->object_2svref or goto BAILOUT;
526 2 50       6 $sv = ${$sv} or goto BAILOUT;
  2         14  
527 2         18 $val = $sv->[$op->private];
528             } else {
529             BAILOUT:
530 218 50       6197 return () if $p{soft};
531 0         0 bailout $S, "cannot parse \"", $op->name, "\" op as a value or value reference";
532             }
533 62         390 return ($val, 1);
534             }
535              
536             sub get_var
537             {
538 5     5 0 15 my ($S, $op) = @_;
539 5 50 66     138 if (is_op($op, "padsv") || is_unop($op, "padsv_store")) {
    0          
540 5         19 return padname($S, $op);
541             } elsif (is_unop($op, "null")) {
542 0         0 $op = $op->first;
543 0         0 want_svop($S, $op, "gvsv");
544 0         0 return "*" . $op->gv->NAME;
545             } else {
546             # XXX
547 0         0 print "$op\n";
548 0         0 print "type: ", $op->type, "\n";
549 0         0 print "name: ", $op->name, "\n";
550 0         0 print "desc: ", $op->desc, "\n";
551 0         0 print "targ: ", $op->targ, "\n";
552 0         0 bailout $S, "cannot get var";
553             }
554             }
555              
556             sub find_aliased_tab
557             {
558 373     373 0 931 my ($S, $op) = @_;
559 373         1041 my $var = padname($S, $op);
560 373 100       1060 return "" unless defined $var;
561              
562 371         690 my $ss = $S;
563 371         994 while ($ss) {
564 419         665 my $tab;
565 419 50       1331 if ($ss->{operation} eq "select") {
566 419         1209 $tab = $ss->{var_alias}{$var};
567             } else {
568 0         0 $tab = $ss->{vars}{$var};
569             }
570 419 100       1705 return $tab if $tab;
571 96         302 $ss = $ss->{gen_args}->{prev_S};
572             }
573 48         189 return "";
574             }
575              
576             sub get_tab_field
577             {
578 382     382 0 938 my ($S, $unop, %p) = @_;
579 382         9650 my $op = want_unop($S, $unop, "entersub");
580 382 50       8592 $op = $op->first if is_unop($op, 'null');
581 382         1294 want_pushmark_or_padrange($S, $op);
582 382         1531 $op = $op->sibling;
583 382         1010 my $tab = is_const($S, $op);
584 382 100       6303 if ($tab) {
    50          
585 150         445 $tab = new_tab($S, $tab);
586             } elsif (is_op($op, "padsv")) {
587 232         741 $tab = find_aliased_tab($S, $op);
588             }
589 382 50       990 unless ($tab) {
590 0         0 bailout $S, "cannot get a table";
591             }
592 382         1724 $op = $op->sibling;
593 382         1140 my $field = want_method($S, $op);
594 382         1468 $op = $op->sibling;
595 382 50 66     1791 if ($p{lvalue} && is_unop($op, "rv2cv")) {
596 0         0 want_unop($S, $op, "rv2cv");
597 0         0 $op = $op->sibling;
598             }
599 382         10202 want_null($S, $op);
600 382 100 100     1505 if ($S->{parsing_return} && !$S->{inside_aggregate}) {
601 86 50       422 my $ff = $S->{operation} eq "select" ? "$tab.$field" : $field;
602 86 100       486 push @{$S->{autogroup_by}}, $ff unless $S->{autogroup_fields}{$ff}++;
  85         309  
603             }
604 382         1775 ($tab, $field);
605             }
606              
607             # helpers
608              
609             sub maybe_one_table_only
610             {
611 357     357 0 796 my ($S) = @_;
612 357 100       1455 return if $S->{operation} eq "select";
613 27 0 66     142 if ($S->{tabs} && keys %{$S->{tabs}} or $S->{vars} && keys %{$S->{vars}}) {
  22   33     175  
  0   33     0  
614 0         0 bailout $S, "a $S->{operation}'s query sub can only refer to a single table";
615             }
616             }
617              
618             sub incr_string
619             {
620 357     357 0 911 my ($s) = @_;
621 357         2595 my ($prefix, $suffix) = $s =~ /^(.*_)?(.*)$/;
622 357   100     3170 $prefix ||= "";
623 357         640 $suffix++;
624 357         1418 return "$prefix$suffix";
625             }
626              
627             sub new_tab
628             {
629 150     150 0 432 my ($S, $tab) = @_;
630 150 100       579 unless ($S->{tabs}{$tab}) {
631 137         495 maybe_one_table_only($S);
632 137         475 $S->{tabs}{$tab} = 1;
633 137         487 $S->{tab_alias}{$tab} = $S->{alias};
634 137         409 $S->{alias} = incr_string($S->{alias});
635             }
636 150         504 $S->{tab_alias}{$tab};
637             }
638              
639             sub new_var
640             {
641 220     220 0 657 my ($S, $var, $tab) = @_;
642 220         821 maybe_one_table_only($S);
643             bailout $S, "cannot reuse $var for table $tab, it's already used by $S->{vars}{$var}"
644 220 50       856 if $S->{vars}{$var};
645 220         911 $S->{vars}{$var} = $tab;
646 220         790 $S->{var_alias}{$var} = $S->{alias};
647 220         635 $S->{alias} = incr_string($S->{alias});
648             }
649              
650             # parsers
651              
652             sub try_parse_attr_assignment
653             {
654 227     227 0 1278 my ($S, $op, $realname, %opt) = @_;
655 227 50       5903 return unless is_unop($op, "entersub");
656 227         5791 $op = want_unop($S, $op);
657 227 100       637 return unless is_pushmark_or_padrange($op);
658 218         1258 $op = $op->sibling;
659 218         666 my $c = is_const($S, $op);
660 218 100 66     1644 return unless $c && $c eq "attributes";
661 217         1766 $op = $op->sibling;
662 217 50       671 return unless is_const($S, $op);
663 217         837 $op = $op->sibling;
664 217 50       5826 return unless is_unop($op, "srefgen");
665 217         5127 my $op1 = want_unop($S, $op);
666 217 50       5498 $op1 = want_unop($S, $op1) if is_unop($op1, "null");
667 217 50       5321 return unless is_op($op1, "padsv");
668 217         984 my $varn = padname($S, $op1);
669 217         1012 $op = $op->sibling;
670 217         607 my $attr = is_const($S, $op);
671 217 50       684 return unless $attr;
672 217         1066 my @attr = grep { length($_) } split /(?:[\(\)])/, $attr;
  220         898  
673 217 50       721 return unless @attr;
674 217         1114 $op = $op->sibling;
675 217 50 33     5969 return unless is_methop($op, "method_named") || is_svop($op, "method_named");
676 217 50       784 return unless want_method($S, $op, "import");
677 217 100       533 if ($realname) {
678 12 50       44 if (lc $attr[0] eq "table") {
679 12         43 @attr = ($realname);
680             } else {
681 0         0 bailout $S, "cannot decide whether you refer to $realname table or to @attr table";
682             }
683             } else {
684 205 100 100     1147 shift @attr if lc $attr[0] eq "table" && @attr > 1;
685             }
686 217         855 $attr = join ".", @attr;
687 217         832 new_var($S, $varn, $attr);
688 217         1064 return $varn;
689             }
690              
691             sub parse_list
692             {
693 390     390 0 955 my ($S, $op) = @_;
694 390         1334 my @op = get_all_children($op);
695 390         1130 for $op (@op) {
696 1385         4019 parse_op($S, $op);
697             }
698             }
699              
700             sub parse_return
701             {
702 103     103 0 249 my ($S, $op) = @_;
703 103         291 my @op = get_all_children($op);
704             bailout $S, "there should be no \"return\" statements in $S->{operation}'s query sub"
705 103 50       412 unless $S->{operation} eq "select";
706 103 100       321 bailout $S, "there should be at most one return statement" if $S->{returns};
707 100         283 $S->{returns} = [];
708 100         182 my $last_alias;
709 100         263 for $op (@op) {
710 251         617 my %rv = parse_return_value($S, $op);
711 240 100       1032 if (exists $rv{table}) {
    100          
    100          
712 15 50       80 bailout $S, "cannot alias the whole table"
713             if defined $last_alias;
714 15         30 push @{$S->{returns}}, "$rv{table}.*";
  15         67  
715 15         195 $S->{no_autogroup} = 1;
716             } elsif (exists $rv{field}) {
717 109 100       280 if (defined $last_alias) {
718 9 100       35 bailout $S, "a key field cannot be aliased" if $rv{key_field};
719 8         15 push @{$S->{returns}}, "$rv{field} as $last_alias";
  8         30  
720 8         75 undef $last_alias;
721             } else {
722 100 100       270 if ($rv{key_field}) {
723 11         24 my $kf = '$kf-' . $S->{key_field};
724 11 50       25 if ($S->{gen_args}{kf_convert}) {
725 0         0 $kf = $S->{gen_args}{kf_convert}->($kf);
726             }
727 11         16 $S->{key_field}++;
728 11         13 push @{$S->{returns}}, "$rv{field} as \"$kf\"";
  11         36  
729 11         16 push @{$S->{key_fields}}, $kf;
  11         50  
730             } else {
731 89         161 push @{$S->{returns}}, $rv{field};
  89         937  
732             }
733             }
734             } elsif (exists $rv{alias}) {
735 16 100       49 if (defined $last_alias) {
736             # XXX maybe check whether it is a number and inline it?
737 3         6 push @{$S->{ret_values}}, $rv{alias};
  3         12  
738 3         7 push @{$S->{returns}}, "? as $last_alias";
  3         10  
739 3         7 undef $last_alias;
740 3         30 next;
741             }
742             bailout $S, "bad alias name \"$rv{alias}\""
743 13 50       68 unless $rv{alias} =~ /^\w+$/;
744 13 100       47 if (lc $rv{alias} eq "distinct") {
745 1 50       2 bailout $S, "\"$rv{alias}\" is not a valid alias name" if @{$S->{returns}};
  1         3  
746 1         2 $S->{distinct}++;
747 1         2 next;
748             }
749 12         33 $last_alias = $rv{alias};
750             }
751             }
752             }
753              
754             sub parse_return_value
755             {
756 265     265 0 514 my ($S, $op) = @_;
757              
758 265 100       6364 if (is_op($op, "padsv")) {
    100          
    100          
    100          
759 16         68 return table => find_aliased_tab($S, $op);
760             } elsif (my $const = is_const($S, $op)) {
761 17         66 return alias => $const;
762             } elsif (is_pushmark_or_padrange($op)) {
763 100         313 return ();
764             } elsif (is_unop($op, "ftsvtx")) {
765 14         82 my %r = parse_return_value($S, $op->first);
766             bailout $S, "only a single value return specification can be a key field"
767 14 100       35 unless $r{field};
768 12 50       60 $r{key_field} = 1 unless $S->{gen_args}->{prev_S};
769 12         54 return %r;
770             } else {
771 118         335 my $saved_values = $S->{values};
772 118         272 $S->{values} = [];
773 118         315 $S->{parsing_return} = 1;
774 118         339 my $ret = parse_term($S, $op);
775 109         357 $S->{parsing_return} = 0;
776 109         232 push @{$S->{ret_values}}, @{$S->{values}};
  109         269  
  109         250  
777 109         247 $S->{values} = $saved_values;
778 109         603 return field => $ret;
779             }
780             }
781              
782             sub parse_term
783             {
784 685     685 0 1771 my ($S, $op, %p) = @_;
785              
786 685         1203 my $placeholder;
787 685         2248 local $S->{in_term} = 1;
788 685 100       18056 if (is_unop($op, "entersub")) {
    50          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
789 385         1298 my $funcall = try_funcall($S, $op);
790 384 100       1292 return $funcall if defined $funcall;
791 349         1201 my ($t, $f) = get_tab_field($S, $op);
792 349 100 66     2178 if ($S->{operation} eq "delete" || $S->{operation} eq "update") {
793 7         36 return $f;
794             } else {
795 342         1836 return "$t.$f";
796             }
797             } elsif (is_unop($op, "lc")) {
798 0         0 my $term = parse_term($S, $op->first);
799 0         0 return "lower($term)";
800             } elsif (is_unop($op, "uc")) {
801 0         0 my $term = parse_term($S, $op->first);
802 0         0 return "upper($term)";
803             } elsif (is_unop($op, "abs")) {
804 1         12 my $term = parse_term($S, $op->first);
805 1         7 return "abs($term)";
806             } elsif (is_unop($op, "null")) {
807 50         403 return parse_term($S, $op->first, %p);
808             } elsif (is_op($op, "null")) {
809 1         32 return parse_term($S, $op->sibling, %p);
810             } elsif (is_op($op, "undef")) {
811 4         19 return "null";
812             } elsif (is_unop($op, "not")) {
813 15         73 my $subop = $op-> first;
814 15 100       357 if (is_pmop($subop, "match")) {
815 2         8 return parse_regex( $S, $subop, 1);
816             } else {
817 13         95 my ($term, $with_not) = parse_term($S, $subop);
818 13 100       54 if ($p{not_after}) {
    100          
819 7         41 return "$term not";
820             } elsif ($with_not) {
821 2         12 return $with_not;
822             } else {
823 4         26 return "not $term";
824             }
825             }
826             } elsif (is_unop($op, "defined")) {
827 4         32 my $term = parse_term($S, $op->first);
828             return wantarray ?
829 4 100       32 ("$term is not null", "$term is null") :
830             "$term is not null";
831             } elsif (($placeholder) = get_value($S, $op, soft => 1)) {
832 28 50 66     138 return 'null' if !defined($placeholder) && $S->{gen_args}->{inline};
833 24         1355 goto PLACEHOLDER;
834             } elsif (is_unop($op, "backtick")) {
835 4         22 my $fop = $op->first;
836 4         95 $fop = $fop->sibling while is_op($fop, "null");
837 4         12 my $sql = is_const($S, $fop);
838 4 50       33 return $sql if $sql;
839             } elsif (is_binop($op)) {
840 23         114 my $expr = parse_expr($S, $op);
841 21         130 return "($expr)";
842             } elsif (is_logop($op, "or")) {
843 2         8 my $or = parse_or($S, $op);
844 2 50       7 bailout $S, "looks like a limiting range or a conditional inside an expression\n"
845             unless $or;
846 2         15 return "($or)";
847             } elsif (is_logop($op, "and")) {
848 2         9 my $and = parse_and($S, $op);
849 2 50       8 bailout $S, "looks like a conditional inside an expression\n"
850             unless $and;
851 2         15 return "($and)";
852             } elsif (my ($const,$sv) = is_const($S, $op)) {
853 97 100 66     1348 if (($sv->isa("B::IV") && !$sv->isa("B::PVIV")) ||
      33        
      66        
854             ($sv->isa("B::NV") && !$sv->isa("B::PVNV")))
855             {
856             # This is surely a number, so we can
857             # safely inline it in the SQL.
858 55         380 return $const;
859             } else {
860             # This will probably be represented by a string,
861             # we'll let DBI to handle the quoting of a bound
862             # value.
863 42         86 $placeholder = $const;
864 42         2194 goto PLACEHOLDER;
865             }
866             } elsif (is_pvop($op, "next")) {
867 12         48 my $seq = $op->pv;
868 12   50     49 my $flavor = $S->{gen_args}->{flavor}||"";
869 12 100 66     48 if ($flavor eq "oracle") {
    100          
870 5 100       32 bailout $S, "Sequence name looks wrong" unless $seq =~ /^\w+$/;
871 4         24 return "$seq.nextval";
872             } elsif ($flavor eq "pg" || $flavor eq "pglite") {
873 6 100       80 bailout $S, "Sequence name looks wrong" if $seq =~ /'/; # XXX well, I am lazy
874 5         31 return "nextval('$seq')";
875             } else {
876 1         4 bailout $S, "Sequences do not seem to be supported for this DBI flavor";
877             }
878             } elsif (is_pmop($op, "match")) {
879 2         9 return parse_regex($S, $op, 0);
880             } elsif (is_unop_aux($op, "multideref")) {
881 41         178 $placeholder = parse_multideref($S, $op);
882 38         2321 goto PLACEHOLDER;
883             } elsif (is_unop_aux($op, "multiconcat")) {
884 13         54 my ($c, $v) = try_special_concat($S, $op);
885 11 50       34 if ($c) {
886 11         28 push @{$S->{values}}, @$v;
  11         52  
887 11         71 return "($c)";
888             }
889 0         0 bailout $S, "unsupported multiconcat";
890             } else {
891 1         8 BAILOUT:
892             bailout $S, "cannot reconstruct term from operation \"",
893             $op->name, '"';
894             }
895              
896             PLACEHOLDER:
897 104 100       486 if ( $p{inline_placeholder}) {
898 4 50       10 bailout $S, "cannot inline undefined value" unless defined $placeholder;
899 4         24 return $placeholder;
900             } else {
901 100         417 return placeholder_value($S, $placeholder);
902             }
903             }
904              
905             sub placeholder_value
906             {
907 100     100 0 271 my ($S, $val) = @_;
908 100         161 my $pos = @{$S->{values}};
  100         370  
909 100         242 push @{$S->{values}}, $val;
  100         388  
910 100         630 return DBIx::Perlish::Placeholder->new($S, $pos);
911             }
912              
913             ## XXX above this point 80.parse_bad.t did not go
914              
915             sub parse_simple_term
916             {
917 16     16 0 49 my ($S, $op) = @_;
918 16 100       51 if (my ($const,$sv) = is_const($S, $op)) {
    100          
919 9         87 return $const;
920             } elsif (my ($val, $ok) = get_value($S, $op, soft => 1)) {
921 4         19 return $val;
922             } else {
923 3         21 bailout $S, "cannot reconstruct simple term from operation \"",
924             $op->name, '"';
925             }
926             }
927              
928             sub parse_simple_eval
929             {
930 6     6 0 16 my ($S, $op) = @_;
931 6 100       58 if (my ($const,$sv) = is_const($S, $op)) {
    50          
932 5         27 return $const;
933             } elsif (my ($val, $ok) = get_value($S, $op, eval => 1)) {
934 1         5 return $val;
935             } else {
936 0         0 bailout $S, "cannot reconstruct simple term from operation \"",
937             $op->name, '"';
938             }
939             }
940              
941             sub get_gv
942             {
943 83     83 0 340 my ($S, $op, %p) = @_;
944              
945 83         158 my ($gv_on_pad, $gv_idx);
946 83 50 66     1931 if (is_svop($op, "gv") || is_svop($op, "gvsv")) {
    0 0        
947 83         326 $gv_idx = $op->targ;
948             } elsif (is_padop($op, "gv") || is_padop($op, "gvsv")) {
949 0         0 $gv_idx = $op->padix;
950 0         0 $gv_on_pad = 1;
951             } else {
952 0         0 goto BAIL_OUT;
953             }
954 83 50       1805 goto BAIL_OUT unless is_null($op->sibling);
955              
956 83 50       476 my $gv = $gv_on_pad ? "" : $op->sv;
957 83 50 33     491 if (!$gv || !$$gv) {
958 0         0 $gv = $S->{padlist}->[1]->ARRAYelt($gv_idx);
959             }
960 83 100 66     782 if ( $p{get_name} && $gv->isa("B::IV")) {
961 81         279 my $subref = $gv->object_2svref;
962 81 50 33     305 if (ref($subref) eq 'REF' && ref($$subref) eq 'CODE') {
963 0         0 my $cv = B::svref_2object($$subref);
964 0         0 return $cv->NAME_HEK;
965             }
966             }
967 83 50       323 goto BAIL_OUT unless $gv->isa("B::GV");
968 83 100       930 return $p{get_name} ? $gv->NAME : $gv;
969             BAIL_OUT:
970 0 0       0 bailout $S, "unable to get GV from \"", $op->name, "\"" if $p{bailout};
971 0         0 return;
972             }
973              
974 81     81 0 454 sub get_gv_name { get_gv(@_, get_name => 1) }
975              
976             sub try_get_subselect
977             {
978 44     44 0 104 my ($S, $sub) = @_;
979              
980 44 50       1162 return unless is_unop($sub, "entersub");
981 44 50       1160 $sub = $sub->first if is_unop($sub->first, "null");
982 44 50       204 return unless is_pushmark_or_padrange($sub->first);
983              
984 44         295 my $rg = $sub->first->sibling;
985 44 50       1030 return if is_null($rg);
986 44         192 my $dbfetch = $rg->sibling;
987 44 100       966 return if is_null($dbfetch);
988 43 50       1038 return unless is_null($dbfetch->sibling);
989              
990 43         120 my $codeop;
991 43 50       139 if ( $] < 5.037 ) {
992 0 0 0     0 return unless is_unop($rg, "refgen") || is_unop($rg, "srefgen");
993 0 0       0 $rg = $rg->first if is_unop($rg->first, "null");
994 0         0 $codeop = $rg->first;
995             } else {
996 43         245 $codeop = $sub->first->sibling;
997             }
998 43 50       134 $codeop = $codeop->sibling if is_pushmark_or_padrange($codeop);
999 43 100       967 return unless is_svop($codeop, "anoncode");
1000              
1001 37 50       4214 $dbfetch = $dbfetch->first if is_unop($dbfetch->first, "null");
1002 37         190 $dbfetch = $dbfetch->first;
1003 37 50 50     119 return unless (get_gv_name($S, $dbfetch) // '') eq 'subselect';
1004              
1005 37         144 return $codeop;
1006             }
1007              
1008             sub try_parse_funcall
1009             {
1010 6     6 0 16 my ($S, $sub, %opt) = @_;
1011 6   100     26 $opt{select} //= 1;
1012 6         7 my $fn;
1013 6         37 my $sql = try_funcall($S, $sub, only_normal_funcs => 1, func_name_return => \$fn);
1014 6 50       16 return unless $sql;
1015 6 100 50     18 if (($S->{gen_args}->{flavor}||"") eq "oracle") {
    100          
1016 3         4 my $cast;
1017 3 50       8 if ($cast = $S->{gen_args}{quirks}{oracle_table_func_cast}{$fn}) {
1018 0         0 $sql = "cast($sql as $cast)";
1019             }
1020 3         7 $sql = "table($sql)";
1021 3 100       11 $sql = "select * from $sql" if $opt{select};
1022             } elsif ($opt{select}) {
1023             # XXX we know this works in postgres, what about the rest?
1024 2         11 $sql = "select $sql";
1025             }
1026 6         18 return $sql;
1027             }
1028              
1029             sub in_list
1030             {
1031 10     10 0 23 my ( $S, $sop, $list ) = @_;
1032 10   50     28 $list //= [];
1033              
1034 10         20 my $sql = '';
1035 10         59 my $left = parse_term($S, $sop->first, not_after => 1);
1036 10 50       38 return '1=0' unless @$list;
1037              
1038             my $arg_limit =
1039             $S->{gen_args}->{in_arg_limit} //
1040 10 50 50     82 ((($S->{gen_args}->{flavor}||"") eq "oracle") ? 500 : 2_000_000_000);
      33        
1041 10         33 my @args = @$list;
1042 10         36 while ( @args ) {
1043 10         15 my @placeholders;
1044 10         33 for my $val ( splice(@args, 0, $arg_limit) ) {
1045 30 100 50     124 if (( ref($val) // '') =~ /SCALAR/) {
1046 7         17 push @placeholders, $$val;
1047             } else {
1048 23         40 push @placeholders, '?';
1049 23         33 push @{$S->{values}}, $val;
  23         68  
1050             }
1051             }
1052 10 0       30 $sql .= $left =~ / not$/ ? ' and ' : ' or ' if length $sql;
    50          
1053 10         61 $sql .= "$left in (" . join(',', @placeholders) . ")";
1054             }
1055              
1056 10         70 return $sql;
1057             }
1058              
1059             sub try_parse_subselect
1060             {
1061 19     19 0 43 my ($S, $sop) = @_;
1062 19         37 my $sql;
1063             my @vals;
1064              
1065 19         106 my $sub = $sop->last->first;
1066              
1067 19 100 66     426 if (is_op($sub, "padav")) {
    100 33        
    100 33        
      66        
1068 6         30 my $ary = get_padlist_scalar($S, $sub->targ, "ref only");
1069 6         24 return in_list( $S, $sop, $ary);
1070             } elsif (is_unop($sub, "rv2av") && is_op($sub->first, "padsv")) {
1071 1         9 my $ary = get_padlist_scalar($S, $sub->first->targ, "ref only");
1072 1   50     5 return in_list( $S, $sop, ${ $ary // \[] });
  1         6  
1073             } elsif (is_listop($sub, "anonlist") or
1074             is_unop($sub, "srefgen") &&
1075             is_unop($sub->first, "null") &&
1076             is_listop($sub->first->first, "anonlist"))
1077             {
1078 3         7 my @what;
1079 3 50       80 my $alist = is_listop($sub, "anonlist") ? $sub : $sub->first->first;
1080 3         10 for my $v (get_all_children($alist)) {
1081 12 100       33 next if is_pushmark_or_padrange($v);
1082 9 100       26 if (my ($const,$sv) = is_const($S, $v)) {
1083 7 50 33     70 if (
      0        
      33        
1084             ($sv->isa("B::IV") && !$sv->isa("B::PVIV")) ||
1085             ($sv->isa("B::NV") && !$sv->isa("B::PVNV"))
1086             ) {
1087 7         26 push @what, \$const;
1088             } else {
1089 0         0 push @what, $const;
1090             }
1091             } else {
1092 2         10 my ($val, $ok) = get_value($S, $v);
1093 2         7 push @what, $val;
1094             }
1095             }
1096 3         18 return in_list($S, $sop, \@what);
1097             } else {
1098 9         35 my $codeop = try_get_subselect( $S, $sub);
1099 9 100       41 if ($codeop) {
1100 5         14 $sql = handle_subselect($S, $codeop);
1101             } else {
1102 4         12 $sql = try_parse_funcall($S, $sub);
1103             }
1104 7 50       23 bailout $S, "unsupported syntax in subselect" unless $sql;
1105             }
1106              
1107 7         51 my $left = parse_term($S, $sop->first, not_after => 1);
1108 7         17 push @{$S->{values}}, @vals;
  7         19  
1109 7         28 return "$left in ($sql)";
1110             }
1111              
1112             sub handle_subselect
1113             {
1114 10     10 0 26 my ($S, $codeop, %p) = @_;
1115              
1116 10         38 my $cv = $codeop->sv;
1117 10 50       25 if (!$$cv) {
1118 10         61 $cv = $S->{padlist}->[1]->ARRAYelt($codeop->targ);
1119             }
1120 10         32 my $subref = $cv->object_2svref;
1121              
1122 10         19 my %gen_args = %{$S->{gen_args}};
  10         69  
1123 10         30 $gen_args{prev_S} = $S;
1124 10 50       26 if ($gen_args{prefix}) {
1125 0         0 $gen_args{prefix} = "$gen_args{prefix}_$S->{subselect}";
1126             } else {
1127 10         25 $gen_args{prefix} = $S->{subselect};
1128             }
1129 10         39 $S->{subselect}++;
1130 10         113 my ($sql, $vals, $nret, %flags) = DBIx::Perlish::gen_sql($subref, "select",
1131             %gen_args);
1132 10 100 100     61 if ($nret != 1 && !$p{returns_dont_care} && !$flags{returns_dont_care}) {
      66        
1133 2         9 bailout $S, "subselect query sub must return exactly one value\n";
1134             }
1135              
1136 8         12 push @{$S->{values}}, @$vals;
  8         19  
1137 8         31 return $sql;
1138             }
1139              
1140             sub parse_assign
1141             {
1142 27     27 0 101 my ($S, $op) = @_;
1143 27 50 100     776 if (
      66        
      66        
1144             $op->name eq 'sassign' &&
1145             is_listop($op->last, "list") &&
1146             is_pushmark_or_padrange($op->last->first) &&
1147             is_unop($op->last->first->sibling, "entersub"))
1148             {
1149 12         72 my ($val, $ok) = get_value($S, $op->first, soft => 1);
1150 12 100 33     99 if ($ok) {
    100          
    100          
    50          
1151 6         68 my $tab = try_parse_attr_assignment($S,
1152             $op->last->first->sibling, $val);
1153 6 50       33 return if $tab;
1154             } elsif ($val = is_const($S, $op->first)) {
1155 1         12 my $tab = try_parse_attr_assignment($S,
1156             $op->last->first->sibling, $val);
1157 1 50       7 return if $tab;
1158             } elsif (my $codeop = try_get_subselect($S, $op->first)) {
1159 3         10 my $sql = handle_subselect($S, $codeop, returns_dont_care => 1);
1160 3         25 my $tab = try_parse_attr_assignment($S,
1161             $op->last->first->sibling, "($sql)");
1162 3 50       13 return if $tab;
1163             } elsif (
1164             is_unop( $op->first, "entersub")
1165             && ( my $sql = try_parse_funcall($S, $op->first, select => 0))
1166             ) {
1167             # my $p : table = function(1,2,3);
1168 2         19 my $tab = try_parse_attr_assignment($S,
1169             $op->last->first->sibling, $sql);
1170 2 50       11 if ( $tab ) {
1171 2         6 my $alias = $S->{var_alias}->{$tab};
1172 2         12 $S->{returns_dont_care}->{$alias} = 1;
1173 2         5 return;
1174             }
1175             }
1176             }
1177             bailout $S, "assignments are not understood in $S->{operation}'s query sub"
1178 15 100       84 unless $S->{operation} eq "update";
1179 13 100 66     402 if (is_unop($op->first, "srefgen") || is_listop($op->first, "anonhash")) {
1180 6         45 parse_multi_assign($S, $op);
1181             } else {
1182 7         43 parse_simple_assign($S, $op);
1183             }
1184             }
1185              
1186             sub parse_simple_assign
1187             {
1188 7     7 0 38 my ($S, $op) = @_;
1189              
1190 7         47 my ($tab, $f) = get_tab_field($S, $op->last, lvalue => 1);
1191 7         27 my $saved_values = $S->{values};
1192 7         21 $S->{values} = [];
1193 7         53 my $set = parse_term($S, $op->first);
1194 7         20 push @{$S->{set_values}}, @{$S->{values}};
  7         24  
  7         21  
1195 7         20 $S->{values} = $saved_values;
1196 7         30 push @{$S->{sets}}, "$f = $set";
  7         73  
1197             }
1198              
1199             sub callarg
1200             {
1201 1181     1181 0 2239 my ($S, $op) = @_;
1202 1181 100       28878 $op = $op->first if is_unop($op, "null");
1203 1181 50 33     24958 $op = $op->sibling if !is_null($op) && is_op($op, "null");
1204 1181 100       2695 return () if is_pushmark_or_padrange($op);
1205 788         1759 return $op;
1206             }
1207              
1208             sub get_codeop
1209             {
1210 11     11 0 18 my $op = shift;
1211 11         14 my $codeop;
1212 11 50       28 if ( $] < 5.037 ) {
1213 0         0 my $rg = $op;
1214 0 0 0     0 return unless is_unop($rg, "refgen") || is_unop($rg, "srefgen");
1215 0 0       0 $rg = $rg->first if is_unop($rg->first, "null");
1216 0         0 $codeop = $rg->first;
1217             } else {
1218 11         17 $codeop = $op;
1219             }
1220 11 50       19 $codeop = $codeop->sibling if is_pushmark_or_padrange($codeop);
1221 11 50       170 return unless is_svop($codeop, "anoncode");
1222 11         45 return $codeop;
1223             }
1224              
1225             sub try_funcall
1226             {
1227 393     393 0 948 my ($S, $op, %p) = @_;
1228 393         755 my @args;
1229 393 50       9092 if (is_unop($op, "entersub")) {
1230 393         1540 $op = $op->first;
1231 393 100       9231 $op = $op->first if is_unop($op, "null");
1232 393         668 while (1) {
1233 1574 100       35344 last if is_null($op);
1234 1181         2929 push @args, callarg($S, $op);
1235 1181         5648 $op = $op->sibling;
1236             }
1237 393 50       1017 return unless @args;
1238 393         1000 $op = pop @args;
1239 393 100 66     8919 return unless is_svop($op, "gv") || is_padop($op, "gv");
1240 44         157 my $func = get_gv_name( $S, $op);
1241 44 50       134 return unless defined $func;
1242 44 100       151 ${$p{func_name_return}} = $func if $p{func_name_return};
  6         13  
1243 44 100       202 if ($func =~ /^(union|intersect|except)$/) {
1244 9 50       22 return if $p{only_normal_funcs};
1245 9 50 66     34 return unless @args == 1 || @args == 2;
1246 9 50       26 my $codeop = get_codeop($args[0]) or return;
1247 9 50       26 return unless $S->{operation} eq "select";
1248 9         33 my $cv = $codeop->sv;
1249 9 50       25 if (!$$cv) {
1250 9         54 $cv = $S->{padlist}->[1]->ARRAYelt($codeop->targ);
1251             }
1252 9         32 my $subref = $cv->object_2svref;
1253 9         13 my %gen_args = %{$S->{gen_args}};
  9         58  
1254 9         26 $gen_args{prev_S} = $S; # XXX maybe different key than prevS?
1255 9         109 my ($sql, $vals, $nret) = DBIx::Perlish::gen_sql($subref, "select",
1256             %gen_args);
1257             # XXX maybe check for nret validity
1258 9         81 push @{$S->{additions}}, {
1259 9 50 33     25 type => ((($S->{gen_args}->{flavor}||"") eq "oracle" && $func eq 'except') ?
1260             'minus' : $func),
1261             sql => $sql,
1262             vals => $vals,
1263             };
1264 9 100       63 if (@args > 1) {
1265             # must be another union|intersect|except
1266 2         8 my $r = try_funcall($S, $args[1], union_or_friends => $func);
1267             # something went wrong if it is not ""
1268 1 50 33     5 return unless defined $r && $r eq "";
1269             }
1270 8         39 return "";
1271             }
1272 35 100       113 if ($p{union_or_friends}) {
1273 1         6 bailout $S, "missing semicolon after $p{union_or_friends} sub";
1274             }
1275 34 100       163 if ($func eq 'subselect') {
    100          
1276 2 50       4 return if $p{only_normal_funcs};
1277 2 50       5 return unless @args == 1;
1278 2 50       5 my $codeop = get_codeop($args[0]) or return;
1279 2         5 my $sql = handle_subselect($S, $codeop, returns_dont_care => 1);
1280 2         7 return "exists ($sql)";
1281             } elsif ($func eq "sql") {
1282 6 50       32 return if $p{only_normal_funcs};
1283 6 50       20 return unless @args == 1;
1284             # XXX understand more complex expressions here
1285 6         13 my $sql;
1286 6 50       27 return unless $sql = parse_simple_eval($S, $args[0]);
1287 6         29 return $sql;
1288             }
1289 26 100 100     990 if ($S->{parsing_return} && $S->{aggregates}{lc $func}) {
1290 4         24 $S->{autogroup_needed} = 1;
1291 4         11 $S->{inside_aggregate} = 1;
1292             }
1293 26 100 100     200 if (!$S->{parsing_return} && $S->{aggregates}{lc $func}) {
1294 1         2 $S->{this_is_having} = 1;
1295 1         4 $S->{autogroup_needed} = 1;
1296             }
1297              
1298 26         80 my @terms = map { scalar parse_term($S, $_) } @args;
  26         91  
1299              
1300 26 100 100     143 if ($S->{parsing_return} && $S->{aggregates}{lc $func}) {
1301 4         11 $S->{inside_aggregate} = 0;
1302             }
1303              
1304             return "sysdate"
1305 26 100 50     159 if ($S->{gen_args}->{flavor}||"") eq "oracle" &&
      100        
      66        
1306             lc $func eq "sysdate" && !@terms;
1307 25 100 100     119 if (lc $func eq "extract" && @terms == 2) {
1308 3 100       37 if (UNIVERSAL::isa($terms[0], "DBIx::Perlish::Placeholder")) {
1309 2         12 my $val = $terms[0]->undo;
1310 2         23 @terms = ("$val from $terms[1]");
1311             }
1312             }
1313 25 100 66     100 if (lc($func) eq 'cast' && @terms == 2) {
1314 2 50       58 $terms[1] = $terms[1]->undo if UNIVERSAL::isa($terms[1], "DBIx::Perlish::Placeholder");
1315 2         11 return "cast($terms[0] as $terms[1])";
1316             }
1317 23         212 return "$func(" . join(", ", @terms) . ")";
1318             }
1319             }
1320              
1321             sub parse_multi_assign
1322             {
1323 6     6 0 15 my ($S, $op) = @_;
1324              
1325 6         29 my $hashop = $op->first;
1326 6 50       164 unless (is_listop($hashop, "anonhash")) {
1327 0         0 want_unop($S, $hashop, "srefgen");
1328 0         0 $hashop = $hashop->first;
1329 0         0 $hashop = $hashop->first while is_unop($hashop, "null");
1330             }
1331 6         173 want_listop($S, $hashop, "anonhash");
1332              
1333 6         15 my $saved_values = $S->{values};
1334 6         16 $S->{values} = [];
1335              
1336 6         15 my $want_const = 1;
1337 6         11 my $field;
1338 6         15 for my $c (get_all_children($hashop)) {
1339 22 100       59 next if is_pushmark_or_padrange($c);
1340              
1341 16 100       61 if ($want_const) {
1342 10         22 my $hash;
1343 10 100 66     270 if (is_op($c, "padhv")) {
    100          
1344 2         46 $hash = $S->{padlist}->[1]->ARRAYelt($c->targ)->object_2svref;
1345             } elsif (is_unop($c, "rv2hv") && is_op($c->first, "padsv")) {
1346 2         25 $hash = $S->{padlist}->[1]->ARRAYelt($c->first->targ)->object_2svref;
1347 2         8 $hash = $$hash;
1348             }
1349 10 100       33 if ($hash) {
1350 4         25 while (my ($k, $v) = each %$hash) {
1351 8         27 push @{$S->{set_values}}, $v;
  8         26  
1352 8         13 push @{$S->{sets}}, "$k = ?";
  8         45  
1353             }
1354             } else {
1355 6         22 $field = want_const($S, $c);
1356 6         58 $want_const = 0;
1357             }
1358             } else {
1359 6         23 my $set = parse_term($S, $c);
1360 6         14 push @{$S->{set_values}}, @{$S->{values}};
  6         19  
  6         19  
1361 6         12 push @{$S->{sets}}, "$field = $set";
  6         26  
1362 6         31 $S->{values} = [];
1363 6         14 $want_const = 1;
1364 6         17 $field = undef;
1365             }
1366             }
1367              
1368 6         24 $S->{values} = $saved_values;
1369 6 100       197 if ( !is_unop($op, 'padsv_store')) {
1370 2         12 $op = $op->last;
1371             }
1372              
1373 6         14 my $tab;
1374 6 100 100     164 if (is_op($op, "padsv") || is_unop($op, "padsv_store")) {
    50          
1375 5         49 my $var = get_var($S, $op);
1376 5         40 $tab = $S->{vars}{$var};
1377             } elsif (is_unop($op, "entersub")) {
1378 0         0 $op = $op->first;
1379 0 0       0 $op = $op->first if is_unop($op, "null");
1380 0 0       0 $op = $op->sibling if is_pushmark_or_padrange($op);
1381 0 0       0 $op = $op->first if is_unop($op, "rv2cv");
1382 0         0 my $gv = get_gv_name($S, $op);
1383 0 0       0 $tab = $gv if defined $gv;
1384             }
1385 6 100       31 bailout $S, "cannot get a table to update" unless $tab;
1386             }
1387              
1388             my %binop_map = (
1389             eq => "=",
1390             seq => "=",
1391             ne => "<>",
1392             sne => "<>",
1393             slt => "<",
1394             gt => ">",
1395             sgt => ">",
1396             le => "<=",
1397             sle => "<=",
1398             ge => ">=",
1399             sge => ">=",
1400             add => "+",
1401             subtract => "-",
1402             multiply => "*",
1403             divide => "/",
1404             concat => "||",
1405             pow => "^",
1406             );
1407             my %binop2_map = (
1408             add => "+",
1409             subtract => "-",
1410             multiply => "*",
1411             divide => "/",
1412             concat => "||",
1413             multiconcat => "||",
1414             pow => "^",
1415             );
1416              
1417             sub parse_expr
1418             {
1419 240     240 0 624 my ($S, $op) = @_;
1420 240         435 my $sqlop;
1421 240 100 66     2710 if (($op->flags & B::OPf_STACKED) &&
      100        
      66        
1422             !$S->{parsing_return} &&
1423             $binop2_map{$op->name} &&
1424             is_unop($op->first, "entersub"))
1425             {
1426             #printf STDERR "entersub flags: %08x\n", $op->first->flags;
1427             #printf STDERR "entersub private flags: %08x\n", $op->first->private;
1428 11         19 my $is_lvalue;
1429 11 50       84 if ($op->first->private & 128) {
1430 11         23 $is_lvalue = 1;
1431             } else {
1432 0         0 my $lc = $op->first->first;
1433 0         0 $lc = $lc->sibling until is_null($lc->sibling);
1434 0         0 $is_lvalue = is_unop($lc, "rv2cv");
1435             }
1436 11 50       37 if ($is_lvalue) {
1437 11         55 my ($tab, $f) = get_tab_field($S, $op->first, lvalue => 1);
1438             bailout $S, "self-modifications are not understood in $S->{operation}'s query sub"
1439 11 100       43 unless $S->{operation} eq "update";
1440             bailout $S, "self-modifications inside an expression is illegal"
1441 10 100       32 if $S->{in_term};
1442 9         19 my $saved_values = $S->{values};
1443 9         21 $S->{values} = [];
1444 9         17 my $set;
1445 9 100       211 if ( is_unop_aux($op, 'multiconcat')) {
1446 1         3 my $v;
1447 1         6 ($set, $v) = try_special_concat($S, $op, multiconcat => { skip_first => 1 });
1448 1 50       5 bailout $S, "unsupported multiconcat" unless $set;
1449 1         1 push @{$S->{values}}, @$v;
  1         4  
1450             } else {
1451 8         53 $set = parse_term($S, $op->last);
1452             }
1453 9         24 push @{$S->{set_values}}, @{$S->{values}};
  9         39  
  9         26  
1454 9         23 $S->{values} = $saved_values;
1455 9 50       42 if ($op->name eq "pow") {
1456 0   0     0 my $flavor = lc($S->{gen_args}->{flavor} || '');
1457 0 0 0     0 if ($flavor eq "pg" || $flavor eq "pglite") {
1458 0         0 push @{$S->{sets}}, "$f = pow($f, $set)";
  0         0  
1459             } else {
1460 0         0 bailout $S, "exponentiation is not supported for $flavor DB driver";
1461             }
1462             } else {
1463 9         15 push @{$S->{sets}}, "$f = $f $binop2_map{$op->name} $set";
  9         55  
1464             }
1465 9         63 return ();
1466             }
1467             }
1468 229 50 33     5880 if (is_binop($op, "concat") || is_unop_aux($op, "multiconcat")) {
1469 0         0 my ($c, $v) = try_special_concat($S, $op);
1470 0 0       0 if ($c) {
1471 0         0 push @{$S->{values}}, @$v;
  0         0  
1472 0         0 return $c;
1473             }
1474             }
1475 229 100 100     2011 if ($sqlop = $binop_map{$op->name}) {
    100          
    100          
1476 177         1408 my $left = parse_term($S, $op->first);
1477 176         1213 my $right = parse_term($S, $op->last);
1478 175 100 100     999 if ($sqlop eq "=" || $sqlop eq "<>") {
1479 148 100       494 my $not = $sqlop eq "<>" ? " not" : "";
1480 148 100       985 if ($right eq "null") {
    100          
1481 4         27 return "$left is$not null";
1482             } elsif ($left eq "null") {
1483 4         26 return "$right is$not null";
1484             }
1485             }
1486 167 100       1073 if ($op->name eq "pow") {
1487 2   50     12 my $flavor = lc($S->{gen_args}->{flavor} || '');
1488 2 100 66     12 if ($flavor eq "pg" || $flavor eq "pglite") {
1489 1         3 return "pow($left, $right)";
1490             } else {
1491 1         5 bailout $S, "exponentiation is not supported for $flavor DB driver";
1492             }
1493             }
1494 165         938 return "$left $sqlop $right";
1495             } elsif ($op->name eq "lt") {
1496 24 100       656 if (is_unop($op->last, "negate")) {
1497 19         70 my $r = try_parse_subselect($S, $op);
1498 17 50       106 return $r if $r;
1499             }
1500             # if the "subselect theory" fails, try a normal binop
1501 5         34 my $left = parse_term($S, $op->first);
1502 5         37 my $right = parse_term($S, $op->last);
1503 5         33 return "$left < $right";
1504             } elsif ($op->name eq "sassign" || $op->name eq 'padsv_store') {
1505 27         173 parse_assign($S, $op);
1506 23         153 return ();
1507             } else {
1508 1         8 BAILOUT:
1509             bailout $S, "unsupported binop " . $op->name;
1510             }
1511             }
1512              
1513             sub parse_multiconcat
1514             {
1515 17     17 0 96 my ( $S, $aux, %opt) = @_;
1516 17         47 my @concats;
1517              
1518 17         132 my @args = ($aux->first);
1519 17   66     486 push @args, $args[-1]->sibling while !is_null($args[-1]) && !is_null($args[-1]->sibling);
1520 17   66     468 shift @args while @args && is_op($args[0], 'null');
1521 17 100       60 shift @args if $opt{skip_first};
1522              
1523 17         128 my ($nargs, $pv, @lengths) = $aux->aux_list($S->{curr_cv});
1524 17         106 while ( defined (my $l = shift @lengths )) {
1525 38 100       92 if ( $l >= 0 ) {
1526 31         83 my $str = substr( $pv, 0, $l, '');
1527 31         109 push @concats, { str => $str };
1528             }
1529 38 100       134 my $op = shift(@args) or last;
1530 22 100       66 if ( $opt{eval}) {
1531 1         27 my ($rv, $ok) = get_value($S, $op, soft => 1, eval => 1);
1532 1 50       19 bailout $S, "cannot parse expression (near $pv)" unless $ok;
1533 1         8 push @concats, { str => $rv };
1534             } else {
1535 21         115 push @concats, { op => $op };
1536             }
1537             }
1538              
1539 17         88 return @concats;
1540             }
1541              
1542             sub try_special_concat
1543             {
1544 37     37 0 117 my ($S, $op, %opt) = @_;
1545 37         76 my @terms;
1546             my $str;
1547 37 50       1067 if (is_binop($op, "concat")) {
    50          
    100          
    100          
    50          
    100          
    100          
    100          
    50          
1548 0         0 my @t = try_special_concat($S, $op->first, terms_only => 1);
1549 0 0       0 return () unless @t;
1550 0         0 push @terms, @t;
1551 0         0 @t = try_special_concat($S, $op->last, terms_only => 1);
1552 0 0       0 return () unless @t;
1553 0         0 push @terms, @t;
1554             } elsif (($str = is_const($S, $op))) {
1555 0         0 push @terms, {str => $str};
1556             } elsif (is_unop($op, "null")) {
1557 2         13 $op = $op->first;
1558 2         60 while (!is_null($op)) {
1559 2         28 my @t = try_special_concat($S, $op, terms_only => 1);
1560 0 0       0 return () unless @t;
1561 0         0 push @terms, @t;
1562 0         0 $op = $op->sibling;
1563             }
1564             } elsif (is_op($op, "null")) {
1565 1         5 return {skip => 1};
1566             } elsif (is_binop($op, "helem")) {
1567 0         0 my $f = is_const($S, $op->last);
1568 0 0       0 return () unless $f;
1569 0         0 $op = $op->first;
1570 0 0       0 return () unless is_unop($op, "rv2hv");
1571 0         0 $op = $op->first;
1572 0 0       0 return () unless is_op($op, "padsv");
1573 0         0 my $tab = find_aliased_tab($S, $op);
1574 0 0       0 return () unless $tab;
1575 0         0 push @terms, {tab => $tab, field => $f};
1576             } elsif (is_unop($op, "entersub")) {
1577 6         13 my ($t, $f) = eval { get_tab_field($S, $op) };
  6         24  
1578 6 50       22 return () unless $f;
1579 6         31 push @terms, {tab => $t, field => $f};
1580             } elsif (is_op($op, "padsv")) {
1581 10         56 my $tab = find_aliased_tab($S, $op);
1582 10 50       602 return () unless $tab;
1583 10         173 push @terms, {tab => $tab};
1584             } elsif (is_unop_aux($op, "multiconcat")) {
1585 16   100     37 my @subterms = parse_multiconcat($S, $op, %{ $opt{multiconcat} // {}});
  16         211  
1586 16 50       64 return () unless @subterms;
1587 16         80 for my $st (@subterms) {
1588 48 100       169 if ( defined $st->{str} ) {
1589 27         75 push @terms, $st;
1590             } else {
1591 21         158 my @t = try_special_concat($S, $st->{op}, terms_only => 1);
1592 19 50       45 return () unless @t;
1593 19         49 push @terms, @t;
1594             }
1595             }
1596             } elsif (is_unop_aux($op, "multideref")) {
1597 2         10 push @terms, { str => parse_multideref($S, $op ) };
1598             } else {
1599 0         0 return ();
1600             }
1601 30 100       169 return @terms if $opt{terms_only};
1602 12         26 $str = "";
1603 12         27 my @sql;
1604             my @v;
1605 12         31 @terms = grep { !$_->{skip} } @terms;
  42         122  
1606 12         32 while (@terms) {
1607 31         81 my $t = shift @terms;
1608 31 100       139 if (exists $t->{str}) {
    100          
1609 15         57 $str .= $t->{str};
1610             } elsif (exists $t->{field}) {
1611 6 100       28 if (length($str)) {
1612 4         13 push @v, $str;
1613 4         9 push @sql, '?';
1614             }
1615 6 50 33     39 if ($S->{operation} eq "delete" || $S->{operation} eq "update") {
1616 0         0 push @sql, $t->{field};
1617             } else {
1618 6         19 push @sql, "$t->{tab}.$t->{field}";
1619             }
1620 6         24 $str = "";
1621             } else {
1622 10         23 my $t2 = shift @terms;
1623 10 50       33 return () unless $t2;
1624 10 50       31 return () unless defined $t2->{str};
1625 10 50       77 return () unless $t2->{str} =~ s/^->(\w+)//;
1626 10         31 my $f = $1;
1627 10 100       40 if (length($str)) {
1628 9         26 push @v, $str;
1629 9         541 push @sql, '?';
1630             }
1631 10 50 33     63 if ($S->{operation} eq "delete" || $S->{operation} eq "update") {
1632 0         0 push @sql, $f;
1633             } else {
1634 10         31 push @sql, "$t->{tab}.$f";
1635             }
1636 10         44 $str = $t2->{str};
1637             }
1638             }
1639 12 100       37 if (length($str)) {
1640 11         33 push @v, $str;
1641 11         25 push @sql, '?';
1642             }
1643 12         22 my $sql;
1644 12 100 50     89 if (lc($S-> {gen_args}-> {flavor} || '') eq "mysql") {
1645 5         21 $sql = "concat(" . join(", ", @sql) . ")";
1646             } else {
1647 7         28 $sql = join " || ", @sql;
1648             }
1649 12         60 return ($sql, \@v);
1650             }
1651              
1652             sub parse_entersub
1653             {
1654 215     215 0 614 my ($S, $op) = @_;
1655 215         745 my $tab = try_parse_attr_assignment($S, $op);
1656 215 100       1063 return () if $tab;
1657 10         29 return scalar parse_term($S, $op);
1658             }
1659              
1660             sub parse_complex_regex
1661             {
1662 8     8 0 16 my ($S, $op) = @_;
1663              
1664 8 50       134 if (is_unop($op, "regcreset")) {
    50          
    100          
    100          
    50          
1665 0 0       0 if (is_unop($op->first, "null")) {
1666 0         0 my $rx = "";
1667 0         0 my $rxop = $op->first->first;
1668 0         0 while (!is_null($rxop)) {
1669 0 0       0 $rx .= parse_complex_regex($S, $rxop)
1670             unless is_pushmark_or_padrange($rxop);
1671 0         0 $rxop = $rxop->sibling;
1672             }
1673 0         0 return $rx;
1674             } else {
1675 0         0 return parse_complex_regex( $S, $op-> first);
1676             }
1677             } elsif ( is_binop( $op, 'concat')) {
1678 0         0 $op = $op-> first;
1679             return
1680 0         0 parse_complex_regex( $S, $op) .
1681             parse_complex_regex( $S, $op-> sibling)
1682             ;
1683             } elsif ( is_svop( $op, 'const')) {
1684 2         7 return want_const( $S, $op);
1685             } elsif (my ($rx, $ok) = get_value($S, $op, soft => 1)) {
1686 4 100       23 return undef unless $rx;
1687 3         10 $rx =~ s/^\(\?\-\w*\:(.*)\)$/$1/; # (?-xism:moo) -> moo
1688 3         10 return $rx;
1689             } elsif (is_unop($op, "null")) {
1690 2         2 my $rx = "";
1691 2         7 my $rxop = $op->first;
1692 2         30 while (!is_null($rxop)) {
1693 6 100       11 $rx .= parse_complex_regex($S, $rxop)
1694             unless is_pushmark_or_padrange($rxop);
1695 6         124 $rxop = $rxop->sibling;
1696             }
1697 2         6 return $rx;
1698             } else {
1699 0         0 bailout $S, "unsupported op " . ref($op) . '/' . $op->name;
1700             }
1701             }
1702              
1703             sub parse_regex
1704             {
1705 20     20 0 51 my ( $S, $op, $neg) = @_;
1706 20         156 my ( $like, $case) = ( $op->precomp, $op-> pmflags & B::PMf_FOLD);
1707              
1708 20 100       109 unless ( defined $like) {
1709 4         45 my $logop = $op-> first-> sibling;
1710 4 50 33     81 bailout $S, "strange regex " . $op->name
1711             unless $logop and is_logop( $logop, 'regcomp');
1712 4         23 $like = parse_complex_regex( $S, $logop-> first);
1713 4 100       18 return "" unless defined $like; # explicitly nulled like
1714             }
1715              
1716 19         152 my $lhs = parse_term($S, $op->first);
1717              
1718 19   50     121 my $flavor = lc($S-> {gen_args}-> {flavor} || '');
1719 19         35 my $what = 'like';
1720              
1721 19         51 $like =~ s/\(\?\^\w+\:((?:[^\\]|\\.)*)\)/$1/g; # ignore ?^flags:
1722              
1723 19         139 my $can_like = $like =~ /^\^?(?:[-!%\s\w]|\\.)*\$?$/; # like that begins with non-% can use indexes
1724              
1725 19 50 66     132 if ( $flavor eq 'mysql') {
    100          
    50          
1726             # mysql LIKE is case-insensitive
1727 0 0 0     0 goto LIKE if not $case and $can_like;
1728 0         0 $like =~ s/'/''/g;
1729              
1730             return
1731 0 0       0 "$lhs ".
    0          
1732             ( $neg ? 'not ' : '') .
1733             'regexp ' .
1734             ( $case ? '' : 'binary ') .
1735             "'$like'"
1736             ;
1737             } elsif ( $flavor eq 'pg' || $flavor eq "pglite") {
1738             # LIKE is case-sensitive
1739 18 50       44 if ( $can_like) {
1740 18 100       47 $what = 'ilike' if $case;
1741 18         332 goto LIKE;
1742             }
1743 0         0 $like =~ s/'/''/g;
1744             return
1745 0 0       0 "$lhs ".
    0          
1746             ( $neg ? '!' : '') .
1747             '~' .
1748             ( $case ? '*' : '') .
1749             " '$like'"
1750             ;
1751             } elsif ($flavor eq "sqlite") {
1752             # SQLite as it is now is a bit tricky:
1753             # - there is support for REGEXP with a func provided the user
1754             # supplies his own function;
1755             # - LIKE is case-insensitive (for ASCII, anyway, there's a bug there);
1756             # - GLOB is case-sensitive;
1757             # - there is also support for MATCH - with a user func
1758             # - except that in recent version it is used for FTS
1759             # Since it does not appear that SQLite can use indices
1760             # for prefix matches with simple LIKE statements, we
1761             # just use user-defined functions PRE_N and PRE_I for
1762             # case-sensitive and case-insensitive cases.
1763             # If I am wrong on that, or if SQLite gets and ability to
1764             # do index-based prefix matching, this logic can be
1765             # modified accordingly in at a future date.
1766 0 0       0 if ($case) {
1767 0         0 $what = "pre_i";
1768             $S->{gen_args}->{dbh}->func($what, 2, sub {
1769 0     0   0 return scalar $_[1] =~ /$_[0]/i;
1770 0         0 }, "create_function");
1771             } else {
1772 0         0 $what = "pre_n";
1773             $S->{gen_args}->{dbh}->func($what, 2, sub {
1774 0     0   0 return scalar $_[1] =~ /$_[0]/;
1775 0         0 }, "create_function");
1776             }
1777 0         0 push @{$S->{values}}, $like;
  0         0  
1778             # $what = $neg ? "not $what" : $what;
1779             # return "$lhs $what ?";
1780 0 0       0 return ($neg ? "not " : "") . "$what(?, $lhs)";
1781             } else {
1782             # XXX is SQL-standard LIKE case-sensitive or not?
1783 1 50       4 if ($case) {
1784 1         3 $lhs = "lower($lhs)";
1785 1         4 $like = lc $like;
1786             }
1787 1 50       13 bailout $S, "Regex too complex for implementation using LIKE keyword: $like"
1788             if $like =~ /(?
1789 19         57 LIKE:
1790             $like =~ s/'/''/g;
1791 19         56 $like =~ s/\\([^A-Za-z_0-9])/$1/g; # de-quotemeta
1792 19         53 my $escape = "";
1793 19 50 66     80 if ($flavor eq "pg" || $flavor eq "oracle") {
1794             # XXX it is possible that more flavors support like...escape
1795 19         24 my $need_esc;
1796 19 100       86 $need_esc = 1 if $like =~ s/!/!!/g;
1797 19 100       71 $need_esc = 1 if $like =~ s/%/!%/g;
1798 19 100       56 $need_esc = 1 if $like =~ s/_/!_/g;
1799 19 100       90 $escape = " escape '!'" if $need_esc;
1800             } else {
1801 0         0 $like =~ s/%/\\%/g;
1802 0         0 $like =~ s/_/\\_/g;
1803             }
1804 19         46 $like =~ s/\.\*/%/g;
1805 19         39 $like =~ s/(?
1806 19         32 $like =~ s/\\\././g;
1807 19 100       67 $like = "%$like" unless $like =~ s|^\^||;
1808 19 100       62 $like = "$like%" unless $like =~ s|\$$||;
1809 19 100       150 return "$lhs " .
1810             ( $neg ? 'not ' : '') .
1811             "$what '$like'$escape"
1812             ;
1813             }
1814             }
1815              
1816             my %join_map = (
1817             bit_and => "inner",
1818             multiply => "inner",
1819             repeat => "inner",
1820             bit_or => "full outer",
1821             add => "full outer",
1822             lt => "left outer",
1823             gt => "right outer",
1824             );
1825              
1826             sub parse_join
1827             {
1828 40     40 0 102 my ($S, $op) = @_;
1829 40         164 my @op = get_all_children( $op);
1830              
1831              
1832             # allow 2-arg syntax for cross joins:
1833             # join $a * $b
1834             # and 3-arg syntax for all other joins:
1835             # join $a * $b => subselect { ... }
1836 40 50 66     290 bailout $S, "not a valid join() syntax"
      66        
      66        
1837             unless 2 <= @op and 3 >= @op and
1838             is_pushmark_or_padrange($op[0]) and
1839             is_binop( $op[1]);
1840 37         76 my $jointype;
1841            
1842 37 100       259 if ($op[1]-> name eq 'le') {
1843             # support <= as well as =>
1844 6 100       29 bailout $S, "not a valid join() syntax"
1845             unless @op == 2;
1846 5         44 @op[1,2] = ( $op[1]-> first, $op[1]-> last);
1847 5 50       129 bailout $S, "not a valid join() syntax"
1848             unless is_binop( $op[1]);
1849             }
1850              
1851 36 100       139 if ( 2 == @op) {
1852             bailout $S, "not a valid join() syntax: one of &,*,x is expected"
1853             unless
1854             exists $join_map{ $op[1]-> name } and
1855 4 100 66     58 $join_map{ $op[1]-> name } eq 'inner';
1856 3         10 $jointype = 'cross';
1857             } else {
1858             bailout $S, "not a valid join() syntax: one of &,|,x,+,*,<,> is expected"
1859 32 100       226 unless exists $join_map{ $op[1]-> name };
1860 31 100 66     837 bailout $S, "not a valid join() syntax"
1861             unless is_unop( $op[2]) and $op[2]-> name eq 'entersub';
1862 30         140 $jointype = $join_map{ $op[1]-> name };
1863             }
1864              
1865             # table names
1866 33         67 my @tab;
1867 33 100       231 $tab[0] = find_aliased_tab($S, $op[1]-> first) or
1868             bailout $S, "first argument of join() is not a table";
1869 32 100       182 $tab[1] = find_aliased_tab($S, $op[1]-> last) or
1870             bailout $S, "second argument of join() is not a table";
1871            
1872             # subselect
1873 31         80 my ( $condition, $codeop);
1874 31 100       105 if ( $op[2]) {
1875 30         151 $codeop = try_get_subselect( $S, $op[2]);
1876 30 100       158 bailout $S, "third argument to join is not a subselect expression"
1877             unless $codeop;
1878              
1879 29         132 my $cv = $codeop->sv;
1880 29 50       102 if (!$$cv) {
1881 29         250 $cv = $S->{padlist}->[1]->ARRAYelt($codeop->targ);
1882             }
1883 29         102 my $subref = $cv->object_2svref;
1884             my $S2 = init(
1885 29         49 %{$S->{gen_args}},
  29         222  
1886             operation => 'select',
1887             values => [],
1888             join_values => [],
1889             prev_S => $S,
1890             );
1891 29         114 $S2-> {alias} = $S-> {alias};
1892 29         109 parse_sub($S2, $subref);
1893             bailout $S,
1894             "join() subselect expression cannot contain anything ".
1895             "but conditional expressions on already declared tables"
1896 145         306 if scalar( grep { @{ $S2-> {$_} } } qw(
  145         517  
1897             group_by order_by autogroup_by ret_values joins
1898 29 100 100     128 )) or $S2->{alias} ne $S->{alias};
1899              
1900 25 50       44 unless ( @{ $S2->{where}||[] }) {
  25 100       127  
1901 3 100       13 bailout $S,
1902             "join() subselect expression must contain ".
1903             "at least one conditional expression"
1904             unless $jointype eq 'inner';
1905 2         24 $jointype = 'cross';
1906             } else {
1907 22         46 $condition = join(' and ', @{ $S2-> {where} });
  22         91  
1908 22         45 push @{$S->{join_values}}, @{$S2->{values}};
  22         56  
  22         287  
1909             }
1910             }
1911              
1912 25         377 return [ $jointype, @tab, $condition ];
1913             }
1914              
1915             sub try_parse_range
1916             {
1917 13     13 0 30 my ($S, $op) = @_;
1918 13 100       446 return try_parse_range($S, $op->first) if is_unop($op, "null");
1919 7 100       175 return unless is_unop($op, "flop");
1920 6         30 $op = $op->first;
1921 6 50       149 return unless is_unop($op, "flip");
1922 6         32 $op = $op->first;
1923 6 50       157 return unless is_logop($op, "range");
1924 6         74 return (parse_simple_term($S, $op->first),
1925             parse_simple_term($S, $op->first->sibling));
1926             }
1927              
1928             sub parse_or
1929             {
1930 19     19 0 53 my ($S, $op) = @_;
1931 19 100       796 if (is_op($op->first->sibling, "last")) {
    100          
1932             bailout $S, "there should be no \"last\" statements in $S->{operation}'s query sub"
1933 9 100       50 unless $S->{operation} eq "select";
1934 7         48 my ($from, $to) = try_parse_range($S, $op->first);
1935 5 100       25 bailout $S, "range operator expected" unless defined $to;
1936 4         14 $S->{offset} = $from;
1937 4         16 $S->{limit} = $to-$from+1;
1938 4         14 return;
1939             } elsif (my ($val, $ok) = get_value($S, $op->first, soft => 1)) {
1940 4         15 return compile_conditionally($S, $op, !$val);
1941             } else {
1942 6         53 my $left = parse_term($S, $op->first);
1943 6         62 my $right = parse_term($S, $op->first->sibling);
1944 6         34 return "$left or $right";
1945             }
1946             }
1947              
1948             sub parse_and
1949             {
1950 14     14 0 38 my ($S, $op) = @_;
1951 14 100       123 if (my ($val, $ok) = get_value($S, $op->first, soft => 1)) {
1952 10         40 return compile_conditionally($S, $op, $val);
1953             } else {
1954 4         59 my $left = parse_term($S, $op->first);
1955 4         40 my $right = parse_term($S, $op->first->sibling);
1956 4         19 return "$left and $right";
1957             }
1958             }
1959              
1960             sub compile_conditionally
1961             {
1962 14     14 0 37 my ($S, $op, $val) = @_;
1963 14 100       41 if ($val) {
1964 9         64 $op = $op->first->sibling;
1965             # This strangeness is for suppressing () when parsing
1966             # expr via parse_term. There must be a better way.
1967 9 100 66     304 if (is_binop($op) || $op->name eq "sassign") {
    100 33        
    50          
1968 1         35 return parse_expr($S, $op);
1969             } elsif (is_listop($op, "return")) {
1970             # conditional returns are nice
1971 6         26 parse_return($S, $op);
1972 4         20 return ();
1973             } elsif (is_listop($op, "leave") || is_listop($op, "scope")) {
1974 2         11 parse_list($S, $op);
1975 2         12 return ();
1976             } else {
1977 0         0 return scalar parse_term($S, $op);
1978             }
1979             } else {
1980 5         20 return ();
1981             }
1982             }
1983              
1984             sub parse_fieldlist_label
1985             {
1986 3     3 0 11 my ($S, $label, $lop, $op) = @_;
1987              
1988 3         6 my @op;
1989 3 100       73 if (is_listop($op, "list")) {
1990 1         38 @op = get_all_children($op);
1991             } else {
1992 2         4 push @op, $op;
1993             }
1994 3         11 for $op (@op) {
1995 5 100       13 next if is_pushmark_or_padrange($op);
1996 4         14 my ($t, $f) = get_tab_field($S, $op);
1997 4         61 push @{$S->{$label->{key}}},
1998 4 50 33     9 ($S->{operation} eq "delete" || $S->{operation} eq "update") ?
1999             $f : "$t.$f";
2000             }
2001 3         16 $S->{skipnext} = 1;
2002             }
2003              
2004             sub parse_sort
2005             {
2006 3     3 0 8 my ($S, $op) = @_;
2007 3         12 parse_orderby_label($S, "order_by", undef, $op);
2008 3         30 delete $S->{skipnext};
2009             }
2010              
2011             sub parse_orderby_label
2012             {
2013 9     9 0 30 my ($S, $label, $lop, $op) = @_;
2014              
2015 9 100       33 my $key = ref $label ? $label->{key} : $label;
2016              
2017 9         19 my @op;
2018 9 100 100     310 if (is_listop($op, "list") || is_listop($op, "sort")) {
    100          
2019 6         21 @op = get_all_children($op);
2020             } elsif ( is_unop($op, "null")) {
2021 1         5 $op = $op->first;
2022 1   66     50 while ( $op && !is_null($op)) {
2023 3         7 push @op, $op;
2024 3         100 $op = $op->sibling;
2025             }
2026             } else {
2027 2         6 push @op, $op;
2028             }
2029 9         25 my $order = "";
2030 9         22 for $op (@op) {
2031 26 100       65 next if is_pushmark_or_padrange($op);
2032             # XXX next if is_op($op, "null");
2033 20         43 my $term;
2034 20 100       46 $term = parse_term($S, $op, inline_placeholder => 1)
2035             unless $term = is_const($S, $op);
2036 20 100       134 if ($term =~ /^asc/i) {
    100          
2037 2         6 next; # skip "ascending"
2038             } elsif ($term =~ /^desc/i) {
2039 7         19 $order = "desc";
2040 7         20 next;
2041             } else {
2042 11 100       31 if ($order) {
2043 6         13 push @{$S->{$key}}, "$term $order";
  6         29  
2044 6         21 $order = "";
2045             } else {
2046 5         12 push @{$S->{$key}}, $term;
  5         28  
2047             }
2048             }
2049             }
2050 9         70 $S->{skipnext} = 1;
2051             }
2052              
2053             sub parse_numassign_label
2054             {
2055 11     11 0 27 my ($S, $label, $lop, $op) = @_;
2056              
2057             # TODO more generic values
2058 11         35 my ($const,$sv) = is_const($S, $op);
2059 11 100 66     257 if (!$sv && is_op($op, "padsv")) {
2060 6 100       25 if (find_aliased_tab($S, $op)) {
2061 2         86 bailout $S, "cannot use table variable after ", $lop->label;
2062             }
2063 4         31 $sv = $S->{padlist}->[1]->ARRAYelt($op->targ);
2064 4         7 $const = ${$sv->object_2svref};
  4         13  
2065             }
2066 9 100 33     149 bailout $S, "label ", $lop->label, " must be followed by an integer or integer variable"
      66        
      66        
2067             unless $sv && $const && $const =~ /^\d+$/ && $const > 0;
2068 7         33 $S->{$label->{key}} = $const;
2069 7         49 $S->{skipnext} = 1;
2070             }
2071              
2072             sub parse_notice_label
2073             {
2074 1     1 0 2 my ($S, $label, $lop, $op) = @_;
2075 1         4 $S->{$label->{key}}++;
2076             }
2077              
2078             sub parse_table_label
2079             {
2080 6     6 0 31 my ($S, $label, $lop, $op) = @_;
2081              
2082             # prior to 5.37 it's sassign, prior to 5.41 it's padsv_store, later it's mixed
2083 6 100 100     204 bailout $S, "label ", $lop->label, " must be followed by an assignment" unless
2084             $op->name eq "padsv_store" || $op->name eq 'sassign';
2085              
2086 5         39 my $attr = parse_simple_term($S, $op->first);
2087 4         15 my $varn;
2088 4 50       16 if ( $] >= 5.037 ) {
2089 4         17 $varn = padname($S, $op, no_fakes => 1);
2090 4 100       25 bailout $S, "label ", $lop->label, " must be followed by a lexical variable declaration"
2091             unless defined $varn;
2092             } else {
2093 0 0 0     0 bailout $S, "label ", $lop->label, " must be followed by a lexical variable declaration"
2094             unless is_op($op->last, "padsv") && ($varn = padname($S, $op->last, no_fakes => 1));
2095             }
2096 3         15 new_var($S, $varn, $attr);
2097 3         31 $S->{skipnext} = 1;
2098             }
2099              
2100             my $action_orderby = {
2101             kind => 'termlist',
2102             key => 'order_by',
2103             handler => \&parse_orderby_label,
2104             };
2105             my $action_groupby = {
2106             kind => 'fieldlist',
2107             key => 'group_by',
2108             handler => \&parse_fieldlist_label,
2109             };
2110             my $action_limit = {
2111             kind => 'numassign',
2112             key => 'limit',
2113             handler => \&parse_numassign_label,
2114             };
2115             my $action_offset = {
2116             kind => 'numassign',
2117             key => 'offset',
2118             handler => \&parse_numassign_label,
2119             };
2120             my $action_distinct = {
2121             kind => 'notice',
2122             key => 'distinct',
2123             handler => \&parse_notice_label,
2124             };
2125             my %labelmap = (
2126             select => {
2127             orderby => $action_orderby,
2128             order_by => $action_orderby,
2129             order => $action_orderby,
2130             sortby => $action_orderby,
2131             sort_by => $action_orderby,
2132             sort => $action_orderby,
2133              
2134             groupby => $action_groupby,
2135             group_by => $action_groupby,
2136             group => $action_groupby,
2137              
2138             limit => $action_limit,
2139              
2140             offset => $action_offset,
2141              
2142             distinct => $action_distinct,
2143             },
2144             );
2145              
2146             sub parse_labels
2147             {
2148 28     28 0 83 my ($S, $lop) = @_;
2149 28         216 my $label = $labelmap{$S->{operation}}->{lc $lop->label};
2150 28 100 100     156 if (!$label && lc $lop->label eq "table") {
2151 6         41 $label = { kind => 'table', handler => \&parse_table_label };
2152             }
2153 28 100       88 bailout $S, "label ", $lop->label, " is not understood"
2154             unless $label;
2155 27         263 my $op = $lop->sibling;
2156 27 50       102 if ($label->{handler}) {
2157 27         106 $label->{handler}->($S, $label, $lop, $op);
2158             } else {
2159 0         0 bailout $S, "internal error parsing label ", $op->label;
2160             }
2161             }
2162              
2163             sub parse_selfmod
2164             {
2165 5     5 0 13 my ($S, $op, $oper) = @_;
2166              
2167 5         16 my ($tab, $f) = get_tab_field($S, $op, lvalue => 1);
2168             bailout $S, "self-modifications are not understood in $S->{operation}'s query sub"
2169 5 100       23 unless $S->{operation} eq "update";
2170 4         27 return "$f = $f $oper";
2171             }
2172              
2173             sub where_or_having
2174             {
2175 451     451 0 1294 my ($S, @what) = @_;
2176 451 100       844 push @{$S->{$S->{this_is_having} ? "having" : "where"}}, @what;
  451         2084  
2177 451         4214 $S->{this_is_having} = 0;
2178             }
2179              
2180             sub parse_op
2181             {
2182 2562     2562 0 5219 my ($S, $op) = @_;
2183              
2184 2562 50       13121 return if $S->{seen}->{$$op}++;
2185              
2186 2562 100       6573 if ($S->{skipnext}) {
2187 19         65 delete $S->{skipnext};
2188 19         153 return;
2189             }
2190 2543 100 66     90789 if (is_listop($op, "list")) {
    100 66        
    100 100        
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    100          
    100          
    50          
2191 9         40 parse_list($S, $op);
2192             } elsif (is_listop($op, "lineseq")) {
2193 371         1326 parse_list($S, $op);
2194             } elsif (is_binop($op, "leaveloop") &&
2195             is_loop($op->first, "enterloop") &&
2196             is_listop($op->last, "lineseq"))
2197             {
2198 8         37 parse_list($S, $op->last);
2199             } elsif (is_listop($op, "return")) {
2200 97         335 parse_return($S, $op);
2201             } elsif (is_binop($op) || is_unop($op, 'padsv_store') ) {
2202 215         913 where_or_having($S, parse_expr($S, $op));
2203             } elsif (is_unop($op, "not")) {
2204 6         23 where_or_having($S, scalar parse_term($S, $op));
2205             } elsif (is_logop($op, "or")) {
2206 17         78 my $or = parse_or($S, $op);
2207 11 100       58 where_or_having($S, "($or)") if $or;
2208 11         117 $S->{this_is_having} = 0;
2209             } elsif (is_logop($op, "and")) {
2210 12         60 my $and = parse_and($S, $op);
2211 11 100       89 where_or_having($S, $and) if $and;
2212 11         154 $S->{this_is_having} = 0;
2213             } elsif (is_unop($op, "leavesub")) {
2214 377         3034 parse_op($S, $op->first);
2215             } elsif (is_unop($op, "null")) {
2216 226         1605 parse_op($S, $op->first);
2217             } elsif (is_unop($op, "defined")) {
2218 2         8 where_or_having($S, scalar parse_term($S, $op));
2219             } elsif (is_op($op, "padsv")) {
2220             # XXX Skip for now, it is either a variable
2221             # that does not represent a table, or else
2222             # it is already associated with a table in $S.
2223             } elsif (is_op($op, "last")) {
2224             bailout $S, "there should be no \"last\" statements in $S->{operation}'s query sub"
2225 2 50       19 unless $S->{operation} eq "select";
2226 0         0 $S->{limit} = 1;
2227             } elsif (is_pushmark_or_padrange($op)) {
2228             # skip
2229             } elsif (is_op($op, "enter")) {
2230             # skip
2231             } elsif (is_op($op, "null")) {
2232             # skip
2233 197         1420 parse_op($S, $op->sibling);
2234             } elsif (is_cop($op, "nextstate")) {
2235 688         3000 $S->{file} = $op->file;
2236 688         2616 $S->{line} = $op->line;
2237 688         2451 $_cover->($op);
2238 688 100       4380 if ($op->label) {
2239 28         137 parse_labels($S, $op);
2240             }
2241             } elsif (is_cop($op)) {
2242             # XXX any other things?
2243 0         0 $S->{file} = $op->file;
2244 0         0 $S->{line} = $op->line;
2245             # skip
2246             } elsif (is_unop($op, "entersub")) {
2247 215         874 where_or_having($S, parse_entersub($S, $op));
2248             } elsif (is_pmop($op, "match")) {
2249 16         75 where_or_having($S, parse_regex($S, $op, 0));
2250             } elsif ( $op->name eq 'join') {
2251 40         83 push @{$S->{joins}}, parse_join($S, $op);
  40         197  
2252             } elsif ($op->name eq 'sort') {
2253 3         10 parse_sort($S, $op);
2254             } elsif (is_unop($op, "postinc")) {
2255 1         3 push @{$S->{sets}}, parse_selfmod($S, $op->first, "+ 1");
  1         8  
2256             } elsif (is_unop($op, "postdec")) {
2257 0         0 push @{$S->{sets}}, parse_selfmod($S, $op->first, "- 1");
  0         0  
2258             } elsif (is_unop($op, "preinc")) {
2259 2         3 push @{$S->{sets}}, parse_selfmod($S, $op->first, "+ 1");
  2         14  
2260             } elsif (is_unop($op, "predec")) {
2261 2         4 push @{$S->{sets}}, parse_selfmod($S, $op->first, "- 1");
  2         12  
2262             } elsif (is_listop($op, "exec")) {
2263 17         217 $S->{seen_exec}++;
2264             } elsif (is_unop_aux($op, "multiconcat")) {
2265 1         4 where_or_having($S, parse_expr($S, $op));
2266             } else {
2267 0         0 bailout $S, "don't quite know what to do with op \"" . $op->name . "\"";
2268             }
2269             }
2270              
2271             sub parse_sub
2272             {
2273 377     377 0 987 my ($S, $sub) = @_;
2274 377 50       1290 if ($DEVEL) {
2275 0         0 $Carp::Verbose = 1;
2276 0         0 require B::Concise;
2277             #my $walker = B::Concise::compile('-terse', $sub);
2278 0         0 my $walker = B::Concise::compile('-concise', $sub);
2279 0         0 print "CODE DUMP:\n";
2280 0         0 $walker->();
2281 0         0 print "\n\n";
2282             }
2283 377         2046 my $root = B::svref_2object($sub);
2284 377         4528 $S->{padlist} = [$root->PADLIST->ARRAY];
2285 377         1660 $S->{curr_cv} = $root;
2286 377 50       4897 $S->{padlists}->{ $root->PADLIST->id } = $S->{padlist} if $root->PADLIST->can('id');
2287 377         1886 $root = $root->ROOT;
2288 377         1299 parse_op($S, $root);
2289             }
2290              
2291             sub B::OP::foo
2292             {
2293 0     0   0 printf "%s 0x%x\n", _o($_[0]), ${$_[0]};
  0         0  
2294             }
2295              
2296             sub init
2297             {
2298 377     377 0 2090 my %args = @_;
2299             my $S = {
2300             gen_args => \%args,
2301             file => '??',
2302             line => '??',
2303             subselect => 's01',
2304             operation => $args{operation},
2305             values => [],
2306             join_values => [],
2307             sets => [],
2308             set_values => [],
2309             ret_values => [],
2310             where => [],
2311             order_by => [],
2312             group_by => [],
2313             additions => [],
2314             joins => [],
2315             key_field => 1,
2316             aggregates => { avg => 1, count => 1, max => 1, min => 1, sum => 1 },
2317             autogroup_by => [],
2318             autogroup_fields => {},
2319             seen => {},
2320             padlists => $args{prev_S} ? $args{prev_S}->{padlists} : {},
2321 377 100       10558 };
2322 377 100       2328 $S->{alias} = $args{prefix} ? "$args{prefix}_t01" : "t01";
2323 377         1363 $S;
2324             }
2325              
2326             # Borrowed from IO::All by Ingy döt Net.
2327             my $old_warn_handler = $SIG{__WARN__};
2328             $SIG{__WARN__} = sub {
2329             if ($_[0] !~ /^Useless use of .+ in void context/) {
2330             goto &$old_warn_handler if $old_warn_handler;
2331             warn(@_);
2332             }
2333             };
2334              
2335             $_cover = sub {};
2336             if (*Devel::Cover::coverage{CODE}) {
2337             my $Coverage = Devel::Cover::coverage(0);
2338             $_cover = sub { $Coverage->{statement}{Devel::Cover::get_key($_[0])} ||= 1 };
2339             }
2340              
2341             package
2342             DBIx::Perlish::Placeholder;
2343              
2344 26     26   19906 use overload '""' => sub { "?" }, eq => sub { "$_[0]" eq "$_[1]" };
  26     96   51579  
  26         505  
  169         1237  
  74         293  
2345              
2346             sub new
2347             {
2348 100     100   328 my ($class, $S, $pos) = @_;
2349 100         1088 bless { S => $S, position => $pos }, $class;
2350             }
2351              
2352             sub value
2353             {
2354 0     0   0 my $me = shift;
2355 0         0 return $me->{S}{values}[$me->{position}];
2356             }
2357              
2358             sub undo
2359             {
2360 4     4   7 my $me = shift;
2361 4         10 splice @{$me->{S}{values}}, $me->{position}, 1;
  4         63  
2362             }
2363              
2364             "the magic stops here; welcome to the real world";