File Coverage

blib/lib/DBIx/Perlish/Parse.pm
Criterion Covered Total %
statement 1100 1341 82.0
branch 694 1018 68.1
condition 227 394 57.6
subroutine 98 105 93.3
pod 0 90 0.0
total 2119 2948 71.8


line stmt bran cond sub pod time code
1             package DBIx::Perlish::Parse;
2 25     25   543 use 5.014;
  25         88  
3 25     25   137 use warnings;
  25         49  
  25         740  
4 25     25   119 use strict;
  25         50  
  25         1024  
5              
6             our $DEVEL;
7             our $_cover;
8              
9 25     25   160 use B;
  25         48  
  25         1075  
10 25     25   172 use Carp;
  25         44  
  25         1348  
11 25     25   10057 use Devel::Caller qw(caller_cv);
  25         67361  
  25         441856  
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 180 my ($S, @rest) = @_;
18 57 50       125 if ($DEVEL) {
19 0         0 confess @rest;
20             } else {
21 57         155 my $args = join '', @rest;
22 57 50       118 $args = "Something's wrong" unless $args;
23 57         109 my $file = $S->{file};
24 57         117 my $line = $S->{line};
25 57 100       251 $args .= " at $file line $line.\n"
26             unless substr($args, length($args) -1) eq "\n";
27 57         1031 CORE::die($args);
28             }
29             }
30              
31             # "is" checks
32              
33             sub is
34             {
35 55383     55383 0 99279 my ($optype, $op, $name) = @_;
36 55383 100       659860 return 0 unless ref($op) eq $optype;
37 17298 100       48333 return 1 unless $name;
38 15413         174620 return $op->name eq $name;
39             }
40              
41             sub gen_is
42             {
43 350     350 0 739 my ($optype) = @_;
44 350         937 my $pkg = "B::" . uc($optype);
45 350 50   5259 0 13081 eval qq[ sub is_$optype { is("$pkg", \@_) } ] unless __PACKAGE__->can("is_$optype");
  5259     1272 0 14221  
  1272     7306 0 3462  
  7306     3951 0 19836  
  3951     8 0 10322  
  8     812 0 38  
  812     3365 0 2395  
  3365     13336 0 8784  
  13336     818 0 34378  
  818     138 0 2305  
  138     54 0 476  
  54     2568 0 174  
  2568     16198 0 6927  
  16198     298 0 41542  
  298         925  
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 1553     1553 0 2708 my ($S, $op) = @_;
66 1553 100       29395 return () unless is_svop($op, "const");
67 976         3214 my $sv = $op->sv;
68 976 50       2271 if (!$$sv) {
69 0         0 $sv = $S->{padlist}->[1]->ARRAYelt($op->targ);
70             }
71 976 100       1853 if (wantarray) {
72 124         176 return (${$sv->object_2svref}, $sv);
  124         641  
73             } else {
74 852         1116 return ${$sv->object_2svref};
  852         3134  
75             }
76             }
77              
78             # "want" helpers
79              
80             sub gen_want
81             {
82 125     125 0 323 my ($optype, $return) = @_;
83 125 100       672 if (!$return) {
    100          
84 50         399 $return = '$op';
85             } elsif ($return =~ /^\w+$/) {
86 50         136 $return = '$op->' . $return;
87             }
88 125 50   6 0 11027 eval <can("want_$optype");
  6 0   380 0 27  
  6 50   0 0 106  
  0 0   8 0 0  
  0 50   1035 0 0  
  6 0       33  
  380 0       1088  
  380 0       6822  
  0 50       0  
  0 0       0  
  380 50       934  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  8         35  
  8         158  
  0         0  
  0         0  
  8         74  
  1035         2697  
  1035         18206  
  0         0  
  0         0  
  1035         5038  
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 3408     3408 0 5597 my $op = shift;
109 3408   100     60991 return is_op($op, "pushmark") || is_op($op, "padrange");
110             }
111              
112             sub want_pushmark_or_padrange
113             {
114 380     380 0 737 my ($S, $op) = @_;
115 380 50       674 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 21 my ($S, $op) = @_;
123 8         159 my $sv = want_svop($S, $op, "const");
124 8 50       27 if (!$$sv) {
125 0         0 $sv = $S->{padlist}->[1]->ARRAYelt($op->targ);
126             }
127 8         14 ${$sv->object_2svref};
  8         40  
128             }
129              
130             sub want_variable_method
131             {
132 2     2 0 3 my ($S, $op) = @_;
133 2 50 33     38 return unless is_unop($op, "method") || is_methop($op, "method");
134 2         8 $op = $op->first;
135 2 50       41 return unless is_null($op->sibling);
136 2         15 my ($name, $ok) = get_value($S, $op, soft => 1);
137 2 50       22 return unless $ok;
138 2         6 return $name;
139             }
140              
141             sub want_method
142             {
143 595     595 0 1090 my ($S, $op) = @_;
144 595         822 my $sv;
145 595 100       11818 if ( is_methop($op, "method_named")) {
    50          
146 593         1919 $sv = $op->meth_sv;
147             } elsif ( is_svop($op, "method_named")) {
148 0         0 $sv = $op->sv;
149             } else {
150 2         7 my $r = want_variable_method($S, $op);
151 2 50       5 bailout $S, "method call syntax expected" unless $r;
152 2         6 return $r;
153             }
154 593 50       1450 if (!$$sv) {
155 0         0 $sv = $S->{padlist}->[1]->ARRAYelt($op->targ);
156             }
157 593         865 ${$sv->object_2svref};
  593         1965  
158             }
159              
160             # getters
161              
162             sub get_all_children
163             {
164 553     553 0 970 my ($op) = @_;
165 553         2292 my $c = $op->children;
166 553         963 my @op;
167 553 50       1160 return @op unless $c;
168 553         1900 push @op, $op->first;
169 553         1808 while (--$c) {
170 1287         4864 push @op, $op[-1]->sibling;
171             }
172 553         1555 @op;
173             }
174              
175             sub padname
176             {
177 595     595 0 1122 my ($S, $op, %p) = @_;
178              
179 595         2935 my $padname = $S->{padlist}->[0]->ARRAYelt($op->targ);
180 595 50 33     3786 if ($padname && !$padname->isa("B::SPECIAL")) {
181 595 100 100     1614 return if $p{no_fakes} && $padname->FLAGS & B::SVf_FAKE;
182 594 100       1772 return unless defined $padname->PVX;
183 592         2470 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 19 my ($S, $n) = @_;
192 6         35 my $padlist = $S->{padlist};
193 6         35 my @n = $padlist->[0]->ARRAY;
194 6         21 for (my $k = 0; $k < @n; $k++) {
195 34 50       94 next if $n[$k]->isa("B::SPECIAL");
196 34 50       88 next if $n[$k]->isa("B::NULL");
197 34 100 100     152 if (($n[$k]->PVX // '') eq $n) {
198 6         25 my $v = $padlist->[1]->ARRAYelt($k);
199 6 100       30 if (!$v->isa("B::SPECIAL")) {
200 3         15 return $v;
201             }
202 3 50       15 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       16 unless $S->{gen_args}->{prev_S};
205 3         18 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 122 my ($S, $i, $ref_only) = @_;
216 51         101 my $padlist = $S->{padlist};
217 51         190 my $v = $padlist->[1]->ARRAYelt($i);
218 51 50       174 bailout $S, "internal error: no such pad element" unless $v;
219 51 100       311 if ($v->isa("B::SPECIAL")) {
220 3         65 my $n = $padlist->[0]->ARRAYelt($i);
221 3 50       20 if ($n->FLAGS & B::SVf_FAKE) {
222 3         17 $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         175 $v = $v->object_2svref;
228 51 100       117 return $v if $ref_only;
229 44         115 return $$v;
230             }
231              
232             sub bailout_multiref_vivify($)
233             {
234 5     5 0 14 my $S = shift;
235 5         36 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 54     54 0 102 my ( $S ) = @_;
243              
244 54         165 my $inner = $S->{curr_cv}->PADLIST;
245             return {
246 54         804 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 62     62 0 127 my ( $store, $index ) = @_;
259              
260 62 50       173 unless ( defined $store->{padlist}->[$index] ) {
261 62         96 my $padname = $store->{names}->[$index];
262 62 100 100     374 if ( $padname->FLAGS & B::SVf_FAKE && $store->{inner}->outid > 1) {
263 3 50       11 unless ($store->{outer_padlist}) {
264 3         15 $store->{outer_padlist} = $store->{S}->{padlists}->{$store->{inner}->outid};
265 3 100       20 unless ($store->{outer_padlist}) {
266             # hacky hacky - look up the caller stack to get their padlists, maybe?
267 1         2 my $id = 0;
268 1         2 while ( 1 ) {
269 14 50       33 my $sub = caller_cv($id++) or last;
270 14         138 my $padlist = B::svref_2object($sub)->PADLIST;
271 14   100     142 $store->{S}->{padlists}->{$padlist->id} //= [$padlist->ARRAY];
272 14 100       48 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         24 $store->{outer_padlist_array} = [$store->{outer_padlist}->[1]->ARRAY];
279             }
280 3         24 $store->{padlist}->[$index] = $store->{outer_padlist_array}->[ $padname->PARENT_PAD_INDEX ];
281             } else {
282             DEFAULT_PADLIST:
283 59         239 $store->{padlist}->[$index] = $store->{orig_pads}->ARRAYelt($index);
284             }
285             }
286              
287 62         246 return $store->{padlist}->[$index];
288             }
289              
290             sub parse_multideref
291             {
292 54     54 0 112 my ( $S, $aux ) = @_;
293 54         261 my @items = $aux->aux_list($S->{curr_cv});
294 54         87 my @ret;
295              
296 54         109 my $AUX = aux_init_padsv($S);
297              
298 54         177 ITEMS: while ( @items ) {
299 54         102 my $actions = shift @items;
300              
301 54         97 my ($ref, $reftype);
302 54 50       125 my $sv = shift(@items) or return undef;
303              
304 54         125 while ( @items ) {
305 73         107 my $ptr = shift @items;
306 73         127 my $access = $actions & B::MDEREF_ACTION_MASK();
307 73 50       161 if ( $access == B::MDEREF_reload() ) { # XXX
308 0         0 $actions = $sv;
309 0         0 next;
310             }
311 73 100       153 unless ($ref) {
312 55 100 66     426 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 50         119 $ref = aux_get_padsv($AUX, $sv)->object_2svref;
319 50 100 66     257 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       13 bailout_multiref_vivify $S unless ref($sv);
327 2         11 $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         17 $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 68 100 100     486 $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 68         112 my $key;
358 68         100 my $index = $actions & B::MDEREF_INDEX_MASK();
359              
360 68 50       141 if ( $index != B::MDEREF_INDEX_none() ) {
361 68 100       131 if ( $index == B::MDEREF_INDEX_const() ) {
    50          
    0          
362 56 100       173 $key = ref($ptr) ? $ptr->object_2svref : $ptr;
363             } elsif ( $index == B::MDEREF_INDEX_padsv() ) {
364 12         23 $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 68 100       422 $ref = $$ref if ref($ref) =~ /REF|SCALAR/;
370 68 100       320 $key = $$key if ref($key) =~ /REF|SCALAR/;
371              
372 68 100       154 if ( $reftype eq 'ARRAY') {
373 20         50 $ref = $ref->[$key];
374             } else {
375 48         101 $ref = $ref->{$key};
376             }
377              
378 68 100 66     220 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         3 push @ret, undef;
387 2         7 last ITEMS;
388             }
389             }
390 66 50 33     251 if ($index == B::MDEREF_INDEX_none() || $index & B::MDEREF_FLAG_last()) {
391 0         0 push @ret, $ref;
392 0         0 last;
393             }
394 66         223 $actions >>= B::MDEREF_SHIFT();
395             }
396              
397 47 50       169 push @ret, $ref unless @ret;
398             }
399              
400 49 50       104 bailout $S, "cannot infer single multideref value" unless 1 == @ret;
401              
402 49         225 return $ret[0];
403             }
404              
405             sub get_concat_value
406             {
407 2     2 0 17 my ( $S, @args) = @_;
408 2         8 my $val = '';
409 2         16 for my $op ( @args ) {
410 4         8 my ($rv, $ok);
411 4 100       11 if ( $rv = is_const($S, $op)) {
412             } else {
413 2         45 ($rv, $ok) = get_value($S, $op, soft => 1, eval => 1);
414 2 50       9 bailout $S, "cannot parse expression (near $val)" unless $ok;
415             }
416 4         11 $val .= $rv;
417             }
418 2         7 return $val;
419             }
420              
421             sub get_value
422             {
423 280     280 0 831 my ($S, $op, %p) = @_;
424              
425 280         430 my $val;
426 280 100 66     5244 if (is_op($op, "padsv")) {
    50 66        
    50 66        
    100 100        
    100 66        
    100 33        
    100 66        
    50          
    50          
    100          
427 44 50       141 if (find_aliased_tab($S, $op)) {
428 0         0 bailout $S, "cannot use a table variable as a value";
429             }
430 44         216 $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         7 my $gv = get_gv($S, $op, bailout => 1);
503 1         2 $val = ${$gv->SV->object_2svref};
  1         5  
504             } elsif (is_unop($op, "null") && (is_svop($op->first, "gvsv") || is_padop($op->first, "gvsv"))) {
505 1         13 my $gv = get_gv($S, $op->first, bailout => 1);
506 1         3 $val = ${$gv->SV->object_2svref};
  1         9  
507             } elsif (is_unop($op, "null") && is_unop_aux($op->first, "multideref")) {
508 13         54 $val = parse_multideref($S, $op->first);
509             } elsif ( $p{eval} && is_binop($op, "concat")) {
510 2         40 my @args = ($op->first);
511 2   66     72 push @args, $args[-1]->sibling while !is_null($args[-1]) && !is_null($args[-1]->sibling);
512 2         16 $val = get_concat_value($S, @args);
513             } elsif ( $p{eval} && is_unop_aux($op, "multiconcat")) {
514 0 0       0 my @terms = parse_multiconcat($S, $op, eval => 1) or goto BAILOUT;
515 0         0 $val = join('', map { $_->{str} } @terms);
  0         0  
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       62 $S->{padlist}->[1]->ARRAYelt($op->padix) :
    50          
524             $op->sv or goto BAILOUT;
525 2 50       16 $sv = $sv->object_2svref or goto BAILOUT;
526 2 50       5 $sv = ${$sv} or goto BAILOUT;
  2         9  
527 2         11 $val = $sv->[$op->private];
528             } else {
529             BAILOUT:
530 217 50       4574 return () if $p{soft};
531 0         0 bailout $S, "cannot parse \"", $op->name, "\" op as a value or value reference";
532             }
533 63         358 return ($val, 1);
534             }
535              
536             sub get_var
537             {
538 5     5 0 23 my ($S, $op) = @_;
539 5 50 33     99 if (is_op($op, "padsv") || is_unop($op, "padsv_store")) {
    0          
540 5         20 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 371     371 0 728 my ($S, $op) = @_;
559 371         786 my $var = padname($S, $op);
560 371 100       881 return "" unless defined $var;
561              
562 369         561 my $ss = $S;
563 369         793 while ($ss) {
564 417         561 my $tab;
565 417 50       875 if ($ss->{operation} eq "select") {
566 417         971 $tab = $ss->{var_alias}{$var};
567             } else {
568 0         0 $tab = $ss->{vars}{$var};
569             }
570 417 100       1286 return $tab if $tab;
571 96         303 $ss = $ss->{gen_args}->{prev_S};
572             }
573 48         146 return "";
574             }
575              
576             sub get_tab_field
577             {
578 380     380 0 824 my ($S, $unop, %p) = @_;
579 380         7243 my $op = want_unop($S, $unop, "entersub");
580 380 50       6899 $op = $op->first if is_unop($op, 'null');
581 380         1165 want_pushmark_or_padrange($S, $op);
582 380         1348 $op = $op->sibling;
583 380         783 my $tab = is_const($S, $op);
584 380 100       4774 if ($tab) {
    50          
585 150         319 $tab = new_tab($S, $tab);
586             } elsif (is_op($op, "padsv")) {
587 230         599 $tab = find_aliased_tab($S, $op);
588             }
589 380 50       821 unless ($tab) {
590 0         0 bailout $S, "cannot get a table";
591             }
592 380         1301 $op = $op->sibling;
593 380         813 my $field = want_method($S, $op);
594 380         1220 $op = $op->sibling;
595 380 50 66     1485 if ($p{lvalue} && is_unop($op, "rv2cv")) {
596 0         0 want_unop($S, $op, "rv2cv");
597 0         0 $op = $op->sibling;
598             }
599 380         7578 want_null($S, $op);
600 380 100 100     1201 if ($S->{parsing_return} && !$S->{inside_aggregate}) {
601 86 50       318 my $ff = $S->{operation} eq "select" ? "$tab.$field" : $field;
602 86 100       313 push @{$S->{autogroup_by}}, $ff unless $S->{autogroup_fields}{$ff}++;
  85         238  
603             }
604 380         1397 ($tab, $field);
605             }
606              
607             # helpers
608              
609             sub maybe_one_table_only
610             {
611 355     355 0 631 my ($S) = @_;
612 355 100       946 return if $S->{operation} eq "select";
613 27 50 66     93 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 355     355 0 679 my ($s) = @_;
621 355         1936 my ($prefix, $suffix) = $s =~ /^(.*_)?(.*)$/;
622 355   100     1699 $prefix ||= "";
623 355         592 $suffix++;
624 355         1074 return "$prefix$suffix";
625             }
626              
627             sub new_tab
628             {
629 150     150 0 305 my ($S, $tab) = @_;
630 150 100       461 unless ($S->{tabs}{$tab}) {
631 137         379 maybe_one_table_only($S);
632 137         326 $S->{tabs}{$tab} = 1;
633 137         349 $S->{tab_alias}{$tab} = $S->{alias};
634 137         287 $S->{alias} = incr_string($S->{alias});
635             }
636 150         336 $S->{tab_alias}{$tab};
637             }
638              
639             sub new_var
640             {
641 218     218 0 486 my ($S, $var, $tab) = @_;
642 218         529 maybe_one_table_only($S);
643             bailout $S, "cannot reuse $var for table $tab, it's already used by $S->{vars}{$var}"
644 218 50       647 if $S->{vars}{$var};
645 218         702 $S->{vars}{$var} = $tab;
646 218         629 $S->{var_alias}{$var} = $S->{alias};
647 218         454 $S->{alias} = incr_string($S->{alias});
648             }
649              
650             # parsers
651              
652             sub try_parse_attr_assignment
653             {
654 225     225 0 494 my ($S, $op, $realname, %opt) = @_;
655 225 50       4307 return unless is_unop($op, "entersub");
656 225         4329 $op = want_unop($S, $op);
657 225 100       535 return unless is_pushmark_or_padrange($op);
658 216         1070 $op = $op->sibling;
659 216         515 my $c = is_const($S, $op);
660 216 100 66     968 return unless $c && $c eq "attributes";
661 215         796 $op = $op->sibling;
662 215 50       460 return unless is_const($S, $op);
663 215         776 $op = $op->sibling;
664 215 50       4112 return unless is_unop($op, "srefgen");
665 215         3941 my $op1 = want_unop($S, $op);
666 215 50       4049 $op1 = want_unop($S, $op1) if is_unop($op1, "null");
667 215 50       4040 return unless is_op($op1, "padsv");
668 215         630 my $varn = padname($S, $op1);
669 215         794 $op = $op->sibling;
670 215         480 my $attr = is_const($S, $op);
671 215 50       508 return unless $attr;
672 215         827 my @attr = grep { length($_) } split /(?:[\(\)])/, $attr;
  218         759  
673 215 50       549 return unless @attr;
674 215         753 $op = $op->sibling;
675 215 50 33     4288 return unless is_methop($op, "method_named") || is_svop($op, "method_named");
676 215 50       572 return unless want_method($S, $op, "import");
677 215 100       516 if ($realname) {
678 12 50       57 if (lc $attr[0] eq "table") {
679 12         40 @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 203 100 100     673 shift @attr if lc $attr[0] eq "table" && @attr > 1;
685             }
686 215         533 $attr = join ".", @attr;
687 215         614 new_var($S, $varn, $attr);
688 215         794 return $varn;
689             }
690              
691             sub parse_list
692             {
693 388     388 0 807 my ($S, $op) = @_;
694 388         858 my @op = get_all_children($op);
695 388         816 for $op (@op) {
696 1377         2982 parse_op($S, $op);
697             }
698             }
699              
700             sub parse_return
701             {
702 103     103 0 233 my ($S, $op) = @_;
703 103         252 my @op = get_all_children($op);
704             bailout $S, "there should be no \"return\" statements in $S->{operation}'s query sub"
705 103 50       390 unless $S->{operation} eq "select";
706 103 100       250 bailout $S, "there should be at most one return statement" if $S->{returns};
707 100         268 $S->{returns} = [];
708 100         161 my $last_alias;
709 100         232 for $op (@op) {
710 251         568 my %rv = parse_return_value($S, $op);
711 240 100       839 if (exists $rv{table}) {
    100          
    100          
712 15 50       47 bailout $S, "cannot alias the whole table"
713             if defined $last_alias;
714 15         26 push @{$S->{returns}}, "$rv{table}.*";
  15         65  
715 15         117 $S->{no_autogroup} = 1;
716             } elsif (exists $rv{field}) {
717 109 100       273 if (defined $last_alias) {
718 9 100       51 bailout $S, "a key field cannot be aliased" if $rv{key_field};
719 8         14 push @{$S->{returns}}, "$rv{field} as $last_alias";
  8         29  
720 8         41 undef $last_alias;
721             } else {
722 100 100       231 if ($rv{key_field}) {
723 11         25 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         18 $S->{key_field}++;
728 11         15 push @{$S->{returns}}, "$rv{field} as \"$kf\"";
  11         35  
729 11         16 push @{$S->{key_fields}}, $kf;
  11         52  
730             } else {
731 89         130 push @{$S->{returns}}, $rv{field};
  89         584  
732             }
733             }
734             } elsif (exists $rv{alias}) {
735 16 100       52 if (defined $last_alias) {
736             # XXX maybe check whether it is a number and inline it?
737 3         9 push @{$S->{ret_values}}, $rv{alias};
  3         8  
738 3         6 push @{$S->{returns}}, "? as $last_alias";
  3         9  
739 3         8 undef $last_alias;
740 3         21 next;
741             }
742             bailout $S, "bad alias name \"$rv{alias}\""
743 13 50       64 unless $rv{alias} =~ /^\w+$/;
744 13 100       44 if (lc $rv{alias} eq "distinct") {
745 1 50       3 bailout $S, "\"$rv{alias}\" is not a valid alias name" if @{$S->{returns}};
  1         5  
746 1         2 $S->{distinct}++;
747 1         2 next;
748             }
749 12         30 $last_alias = $rv{alias};
750             }
751             }
752             }
753              
754             sub parse_return_value
755             {
756 265     265 0 484 my ($S, $op) = @_;
757              
758 265 100       5303 if (is_op($op, "padsv")) {
    100          
    100          
    100          
759 16         88 return table => find_aliased_tab($S, $op);
760             } elsif (my $const = is_const($S, $op)) {
761 17         57 return alias => $const;
762             } elsif (is_pushmark_or_padrange($op)) {
763 100         339 return ();
764             } elsif (is_unop($op, "ftsvtx")) {
765 14         62 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       47 unless $r{field};
768 12 50       31 $r{key_field} = 1 unless $S->{gen_args}->{prev_S};
769 12         55 return %r;
770             } else {
771 118         288 my $saved_values = $S->{values};
772 118         265 $S->{values} = [];
773 118         252 $S->{parsing_return} = 1;
774 118         279 my $ret = parse_term($S, $op);
775 109         267 $S->{parsing_return} = 0;
776 109         167 push @{$S->{ret_values}}, @{$S->{values}};
  109         230  
  109         208  
777 109         202 $S->{values} = $saved_values;
778 109         411 return field => $ret;
779             }
780             }
781              
782             sub parse_term
783             {
784 694     694 0 1507 my ($S, $op, %p) = @_;
785              
786 694         979 my $placeholder;
787 694         1654 local $S->{in_term} = 1;
788 694 100       13663 if (is_unop($op, "entersub")) {
    50          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
789 383         1079 my $funcall = try_funcall($S, $op);
790 382 100       1037 return $funcall if defined $funcall;
791 347         826 my ($t, $f) = get_tab_field($S, $op);
792 347 100 66     1551 if ($S->{operation} eq "delete" || $S->{operation} eq "update") {
793 7         31 return $f;
794             } else {
795 340         1522 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         33 my $term = parse_term($S, $op->first);
805 1         8 return "abs($term)";
806             } elsif (is_unop($op, "null")) {
807 55         395 return parse_term($S, $op->first, %p);
808             } elsif (is_op($op, "null")) {
809 8         171 return parse_term($S, $op->sibling, %p);
810             } elsif (is_op($op, "undef")) {
811 4         17 return "null";
812             } elsif (is_unop($op, "not")) {
813 15         71 my $subop = $op-> first;
814 15 100       318 if (is_pmop($subop, "match")) {
815 2         8 return parse_regex( $S, $subop, 1);
816             } else {
817 13         108 my ($term, $with_not) = parse_term($S, $subop);
818 13 100       63 if ($p{not_after}) {
    100          
819 7         35 return "$term not";
820             } elsif ($with_not) {
821 2         10 return $with_not;
822             } else {
823 4         35 return "not $term";
824             }
825             }
826             } elsif (is_unop($op, "defined")) {
827 4         46 my $term = parse_term($S, $op->first);
828             return wantarray ?
829 4 100       37 ("$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     103 return 'null' if !defined($placeholder) && $S->{gen_args}->{inline};
833 24         758 goto PLACEHOLDER;
834             } elsif (is_unop($op, "backtick")) {
835 4         25 my $fop = $op->first;
836 4         83 $fop = $fop->sibling while is_op($fop, "null");
837 4         10 my $sql = is_const($S, $fop);
838 4 50       29 return $sql if $sql;
839             } elsif (is_binop($op)) {
840 36         170 my $expr = parse_expr($S, $op);
841 32         163 return "($expr)";
842             } elsif (is_logop($op, "or")) {
843 2         7 my $or = parse_or($S, $op);
844 2 50       18 bailout $S, "looks like a limiting range or a conditional inside an expression\n"
845             unless $or;
846 2         16 return "($or)";
847             } elsif (is_logop($op, "and")) {
848 2         14 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 98 100 66     980 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         238 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 43         95 $placeholder = $const;
864 43         1289 goto PLACEHOLDER;
865             }
866             } elsif (is_pvop($op, "next")) {
867 12         39 my $seq = $op->pv;
868 12   50     33 my $flavor = $S->{gen_args}->{flavor}||"";
869 12 100 66     37 if ($flavor eq "oracle") {
    100          
870 5 100       21 bailout $S, "Sequence name looks wrong" unless $seq =~ /^\w+$/;
871 4         23 return "$seq.nextval";
872             } elsif ($flavor eq "pg" || $flavor eq "pglite") {
873 6 100       21 bailout $S, "Sequence name looks wrong" if $seq =~ /'/; # XXX well, I am lazy
874 5         26 return "nextval('$seq')";
875             } else {
876 1         3 bailout $S, "Sequences do not seem to be supported for this DBI flavor";
877             }
878             } elsif (is_pmop($op, "match")) {
879 2         15 return parse_regex($S, $op, 0);
880             } elsif (is_unop_aux($op, "multideref")) {
881 39         112 $placeholder = parse_multideref($S, $op);
882 36         1054 goto PLACEHOLDER;
883             } elsif (is_unop_aux($op, "multiconcat")) {
884 0         0 my ($c, $v) = try_special_concat($S, $op);
885 0 0       0 if ($c) {
886 0         0 push @{$S->{values}}, @$v;
  0         0  
887 0         0 return "($c)";
888             }
889 0         0 bailout $S, "unsupported multiconcat";
890             } else {
891 1         6 BAILOUT:
892             bailout $S, "cannot reconstruct term from operation \"",
893             $op->name, '"';
894             }
895              
896             PLACEHOLDER:
897 103 100       333 if ( $p{inline_placeholder}) {
898 4 50       16 bailout $S, "cannot inline undefined value" unless defined $placeholder;
899 4         17 return $placeholder;
900             } else {
901 99         239 return placeholder_value($S, $placeholder);
902             }
903             }
904              
905             sub placeholder_value
906             {
907 99     99 0 216 my ($S, $val) = @_;
908 99         147 my $pos = @{$S->{values}};
  99         227  
909 99         149 push @{$S->{values}}, $val;
  99         255  
910 99         364 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 57 my ($S, $op) = @_;
918 16 100       87 if (my ($const,$sv) = is_const($S, $op)) {
    100          
919 9         66 return $const;
920             } elsif (my ($val, $ok) = get_value($S, $op, soft => 1)) {
921 4         14 return $val;
922             } else {
923 3         18 bailout $S, "cannot reconstruct simple term from operation \"",
924             $op->name, '"';
925             }
926             }
927              
928             sub parse_simple_eval
929             {
930 6     6 0 15 my ($S, $op) = @_;
931 6 100       18 if (my ($const,$sv) = is_const($S, $op)) {
    50          
932 5         20 return $const;
933             } elsif (my ($val, $ok) = get_value($S, $op, eval => 1)) {
934 1         9 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 262 my ($S, $op, %p) = @_;
944              
945 83         162 my ($gv_on_pad, $gv_idx);
946 83 50 66     1576 if (is_svop($op, "gv") || is_svop($op, "gvsv")) {
    0 0        
947 83         310 $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       1687 goto BAIL_OUT unless is_null($op->sibling);
955              
956 83 50       401 my $gv = $gv_on_pad ? "" : $op->sv;
957 83 50 33     390 if (!$gv || !$$gv) {
958 0         0 $gv = $S->{padlist}->[1]->ARRAYelt($gv_idx);
959             }
960 83 100 66     518 if ( $p{get_name} && $gv->isa("B::IV")) {
961 81         250 my $subref = $gv->object_2svref;
962 81 50 33     272 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       237 goto BAIL_OUT unless $gv->isa("B::GV");
968 83 100       565 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 218 sub get_gv_name { get_gv(@_, get_name => 1) }
975              
976             sub try_get_subselect
977             {
978 44     44 0 93 my ($S, $sub) = @_;
979              
980 44 50       920 return unless is_unop($sub, "entersub");
981 44 50       937 $sub = $sub->first if is_unop($sub->first, "null");
982 44 50       190 return unless is_pushmark_or_padrange($sub->first);
983              
984 44         233 my $rg = $sub->first->sibling;
985 44 50       834 return if is_null($rg);
986 44         181 my $dbfetch = $rg->sibling;
987 44 100       840 return if is_null($dbfetch);
988 43 50       903 return unless is_null($dbfetch->sibling);
989              
990 43         101 my $codeop;
991 43 50       109 if ( $] < 5.037 ) {
992 43 100 66     813 return unless is_unop($rg, "refgen") || is_unop($rg, "srefgen");
993 37 50       754 $rg = $rg->first if is_unop($rg->first, "null");
994 37         143 $codeop = $rg->first;
995             } else {
996 0         0 $codeop = $sub->first->sibling;
997             }
998 37 50       112 $codeop = $codeop->sibling if is_pushmark_or_padrange($codeop);
999 37 50       685 return unless is_svop($codeop, "anoncode");
1000              
1001 37 50       776 $dbfetch = $dbfetch->first if is_unop($dbfetch->first, "null");
1002 37         188 $dbfetch = $dbfetch->first;
1003 37 50 50     95 return unless (get_gv_name($S, $dbfetch) // '') eq 'subselect';
1004              
1005 37         110 return $codeop;
1006             }
1007              
1008             sub try_parse_funcall
1009             {
1010 6     6 0 19 my ($S, $sub, %opt) = @_;
1011 6   100     27 $opt{select} //= 1;
1012 6         19 my $fn;
1013 6         17 my $sql = try_funcall($S, $sub, only_normal_funcs => 1, func_name_return => \$fn);
1014 6 50       25 return unless $sql;
1015 6 100 50     27 if (($S->{gen_args}->{flavor}||"") eq "oracle") {
    100          
1016 3         6 my $cast;
1017 3 50       9 if ($cast = $S->{gen_args}{quirks}{oracle_table_func_cast}{$fn}) {
1018 0         0 $sql = "cast($sql as $cast)";
1019             }
1020 3         9 $sql = "table($sql)";
1021 3 100       8 $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         5 $sql = "select $sql";
1025             }
1026 6         24 return $sql;
1027             }
1028              
1029             sub in_list
1030             {
1031 10     10 0 23 my ( $S, $sop, $list ) = @_;
1032 10   50     23 $list //= [];
1033              
1034 10         24 my $sql = '';
1035 10         41 my $left = parse_term($S, $sop->first, not_after => 1);
1036 10 50       44 return '1=0' unless @$list;
1037              
1038             my $arg_limit =
1039             $S->{gen_args}->{in_arg_limit} //
1040 10 50 50     63 ((($S->{gen_args}->{flavor}||"") eq "oracle") ? 500 : 2_000_000_000);
      33        
1041 10         27 my @args = @$list;
1042 10         39 while ( @args ) {
1043 10         31 my @placeholders;
1044 10         30 for my $val ( splice(@args, 0, $arg_limit) ) {
1045 30 100 50     88 if (( ref($val) // '') =~ /SCALAR/) {
1046 7         16 push @placeholders, $$val;
1047             } else {
1048 23         35 push @placeholders, '?';
1049 23         29 push @{$S->{values}}, $val;
  23         57  
1050             }
1051             }
1052 10 0       30 $sql .= $left =~ / not$/ ? ' and ' : ' or ' if length $sql;
    50          
1053 10         59 $sql .= "$left in (" . join(',', @placeholders) . ")";
1054             }
1055              
1056 10         41 return $sql;
1057             }
1058              
1059             sub try_parse_subselect
1060             {
1061 19     19 0 63 my ($S, $sop) = @_;
1062 19         37 my $sql;
1063             my @vals;
1064              
1065 19         125 my $sub = $sop->last->first;
1066              
1067 19 100 66     378 if (is_op($sub, "padav")) {
    100 33        
    100 33        
      66        
1068 6         38 my $ary = get_padlist_scalar($S, $sub->targ, "ref only");
1069 6         18 return in_list( $S, $sop, $ary);
1070             } elsif (is_unop($sub, "rv2av") && is_op($sub->first, "padsv")) {
1071 1         16 my $ary = get_padlist_scalar($S, $sub->first->targ, "ref only");
1072 1   50     8 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       56 my $alist = is_listop($sub, "anonlist") ? $sub : $sub->first->first;
1080 3         10 for my $v (get_all_children($alist)) {
1081 12 100       23 next if is_pushmark_or_padrange($v);
1082 9 100       30 if (my ($const,$sv) = is_const($S, $v)) {
1083 7 50 33     57 if (
      0        
      33        
1084             ($sv->isa("B::IV") && !$sv->isa("B::PVIV")) ||
1085             ($sv->isa("B::NV") && !$sv->isa("B::PVNV"))
1086             ) {
1087 7         25 push @what, \$const;
1088             } else {
1089 0         0 push @what, $const;
1090             }
1091             } else {
1092 2         12 my ($val, $ok) = get_value($S, $v);
1093 2         6 push @what, $val;
1094             }
1095             }
1096 3         12 return in_list($S, $sop, \@what);
1097             } else {
1098 9         55 my $codeop = try_get_subselect( $S, $sub);
1099 9 100       39 if ($codeop) {
1100 5         18 $sql = handle_subselect($S, $codeop);
1101             } else {
1102 4         9 $sql = try_parse_funcall($S, $sub);
1103             }
1104 7 50       21 bailout $S, "unsupported syntax in subselect" unless $sql;
1105             }
1106              
1107 7         54 my $left = parse_term($S, $sop->first, not_after => 1);
1108 7         18 push @{$S->{values}}, @vals;
  7         32  
1109 7         29 return "$left in ($sql)";
1110             }
1111              
1112             sub handle_subselect
1113             {
1114 10     10 0 51 my ($S, $codeop, %p) = @_;
1115              
1116 10         37 my $cv = $codeop->sv;
1117 10 50       41 if (!$$cv) {
1118 10         65 $cv = $S->{padlist}->[1]->ARRAYelt($codeop->targ);
1119             }
1120 10         41 my $subref = $cv->object_2svref;
1121              
1122 10         21 my %gen_args = %{$S->{gen_args}};
  10         61  
1123 10         29 $gen_args{prev_S} = $S;
1124 10 50       29 if ($gen_args{prefix}) {
1125 0         0 $gen_args{prefix} = "$gen_args{prefix}_$S->{subselect}";
1126             } else {
1127 10         39 $gen_args{prefix} = $S->{subselect};
1128             }
1129 10         24 $S->{subselect}++;
1130 10         105 my ($sql, $vals, $nret, %flags) = DBIx::Perlish::gen_sql($subref, "select",
1131             %gen_args);
1132 10 100 100     89 if ($nret != 1 && !$p{returns_dont_care} && !$flags{returns_dont_care}) {
      66        
1133 2         7 bailout $S, "subselect query sub must return exactly one value\n";
1134             }
1135              
1136 8         19 push @{$S->{values}}, @$vals;
  8         21  
1137 8         33 return $sql;
1138             }
1139              
1140             sub parse_assign
1141             {
1142 27     27 0 89 my ($S, $op) = @_;
1143 27 50 66     694 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         100 my ($val, $ok) = get_value($S, $op->first, soft => 1);
1150 12 100 33     73 if ($ok) {
    100          
    100          
    50          
1151 6         40 my $tab = try_parse_attr_assignment($S,
1152             $op->last->first->sibling, $val);
1153 6 50       21 return if $tab;
1154             } elsif ($val = is_const($S, $op->first)) {
1155 1         8 my $tab = try_parse_attr_assignment($S,
1156             $op->last->first->sibling, $val);
1157 1 50       5 return if $tab;
1158             } elsif (my $codeop = try_get_subselect($S, $op->first)) {
1159 3         9 my $sql = handle_subselect($S, $codeop, returns_dont_care => 1);
1160 3         30 my $tab = try_parse_attr_assignment($S,
1161             $op->last->first->sibling, "($sql)");
1162 3 50       12 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         23 my $tab = try_parse_attr_assignment($S,
1169             $op->last->first->sibling, $sql);
1170 2 50       25 if ( $tab ) {
1171 2         19 my $alias = $S->{var_alias}->{$tab};
1172 2         9 $S->{returns_dont_care}->{$alias} = 1;
1173 2         7 return;
1174             }
1175             }
1176             }
1177             bailout $S, "assignments are not understood in $S->{operation}'s query sub"
1178 15 100       122 unless $S->{operation} eq "update";
1179 13 100 66     293 if (is_unop($op->first, "srefgen") || is_listop($op->first, "anonhash")) {
1180 6         27 parse_multi_assign($S, $op);
1181             } else {
1182 7         30 parse_simple_assign($S, $op);
1183             }
1184             }
1185              
1186             sub parse_simple_assign
1187             {
1188 7     7 0 17 my ($S, $op) = @_;
1189              
1190 7         33 my ($tab, $f) = get_tab_field($S, $op->last, lvalue => 1);
1191 7         21 my $saved_values = $S->{values};
1192 7         17 $S->{values} = [];
1193 7         32 my $set = parse_term($S, $op->first);
1194 7         24 push @{$S->{set_values}}, @{$S->{values}};
  7         22  
  7         18  
1195 7         14 $S->{values} = $saved_values;
1196 7         10 push @{$S->{sets}}, "$f = $set";
  7         31  
1197             }
1198              
1199             sub callarg
1200             {
1201 1175     1175 0 2005 my ($S, $op) = @_;
1202 1175 100       21200 $op = $op->first if is_unop($op, "null");
1203 1175 100 66     20881 $op = $op->sibling if !is_null($op) && is_op($op, "null");
1204 1175 100       2456 return () if is_pushmark_or_padrange($op);
1205 784         1549 return $op;
1206             }
1207              
1208             sub get_codeop
1209             {
1210 11     11 0 21 my $op = shift;
1211 11         15 my $codeop;
1212 11 50       25 if ( $] < 5.037 ) {
1213 11         17 my $rg = $op;
1214 11 50 33     246 return unless is_unop($rg, "refgen") || is_unop($rg, "srefgen");
1215 11 50       226 $rg = $rg->first if is_unop($rg->first, "null");
1216 11         67 $codeop = $rg->first;
1217             } else {
1218 0         0 $codeop = $op;
1219             }
1220 11 50       25 $codeop = $codeop->sibling if is_pushmark_or_padrange($codeop);
1221 11 50       202 return unless is_svop($codeop, "anoncode");
1222 11         69 return $codeop;
1223             }
1224              
1225             sub try_funcall
1226             {
1227 391     391 0 799 my ($S, $op, %p) = @_;
1228 391         666 my @args;
1229 391 50       7256 if (is_unop($op, "entersub")) {
1230 391         1646 $op = $op->first;
1231 391 100       7281 $op = $op->first if is_unop($op, "null");
1232 391         684 while (1) {
1233 1566 100       28877 last if is_null($op);
1234 1175         2578 push @args, callarg($S, $op);
1235 1175         4351 $op = $op->sibling;
1236             }
1237 391 50       1001 return unless @args;
1238 391         743 $op = pop @args;
1239 391 100 66     7077 return unless is_svop($op, "gv") || is_padop($op, "gv");
1240 44         175 my $func = get_gv_name( $S, $op);
1241 44 50       120 return unless defined $func;
1242 44 100       110 ${$p{func_name_return}} = $func if $p{func_name_return};
  6         14  
1243 44 100       188 if ($func =~ /^(union|intersect|except)$/) {
1244 9 50       27 return if $p{only_normal_funcs};
1245 9 50 66     31 return unless @args == 1 || @args == 2;
1246 9 50       24 my $codeop = get_codeop($args[0]) or return;
1247 9 50       29 return unless $S->{operation} eq "select";
1248 9         30 my $cv = $codeop->sv;
1249 9 50       22 if (!$$cv) {
1250 9         61 $cv = $S->{padlist}->[1]->ARRAYelt($codeop->targ);
1251             }
1252 9         30 my $subref = $cv->object_2svref;
1253 9         15 my %gen_args = %{$S->{gen_args}};
  9         51  
1254 9         24 $gen_args{prev_S} = $S; # XXX maybe different key than prevS?
1255 9         74 my ($sql, $vals, $nret) = DBIx::Perlish::gen_sql($subref, "select",
1256             %gen_args);
1257             # XXX maybe check for nret validity
1258 9         101 push @{$S->{additions}}, {
1259 9 50 33     35 type => ((($S->{gen_args}->{flavor}||"") eq "oracle" && $func eq 'except') ?
1260             'minus' : $func),
1261             sql => $sql,
1262             vals => $vals,
1263             };
1264 9 100       30 if (@args > 1) {
1265             # must be another union|intersect|except
1266 2         14 my $r = try_funcall($S, $args[1], union_or_friends => $func);
1267             # something went wrong if it is not ""
1268 1 50 33     9 return unless defined $r && $r eq "";
1269             }
1270 8         37 return "";
1271             }
1272 35 100       97 if ($p{union_or_friends}) {
1273 1         7 bailout $S, "missing semicolon after $p{union_or_friends} sub";
1274             }
1275 34 100       126 if ($func eq 'subselect') {
    100          
1276 2 50       9 return if $p{only_normal_funcs};
1277 2 50       8 return unless @args == 1;
1278 2 50       7 my $codeop = get_codeop($args[0]) or return;
1279 2         7 my $sql = handle_subselect($S, $codeop, returns_dont_care => 1);
1280 2         11 return "exists ($sql)";
1281             } elsif ($func eq "sql") {
1282 6 50       15 return if $p{only_normal_funcs};
1283 6 50       60 return unless @args == 1;
1284             # XXX understand more complex expressions here
1285 6         14 my $sql;
1286 6 50       20 return unless $sql = parse_simple_eval($S, $args[0]);
1287 6         20 return $sql;
1288             }
1289 26 100 100     108 if ($S->{parsing_return} && $S->{aggregates}{lc $func}) {
1290 4         11 $S->{autogroup_needed} = 1;
1291 4         16 $S->{inside_aggregate} = 1;
1292             }
1293 26 100 100     104 if (!$S->{parsing_return} && $S->{aggregates}{lc $func}) {
1294 1         4 $S->{this_is_having} = 1;
1295 1         5 $S->{autogroup_needed} = 1;
1296             }
1297              
1298 26         57 my @terms = map { scalar parse_term($S, $_) } @args;
  26         57  
1299              
1300 26 100 100     125 if ($S->{parsing_return} && $S->{aggregates}{lc $func}) {
1301 4         10 $S->{inside_aggregate} = 0;
1302             }
1303              
1304             return "sysdate"
1305 26 100 50     117 if ($S->{gen_args}->{flavor}||"") eq "oracle" &&
      100        
      66        
1306             lc $func eq "sysdate" && !@terms;
1307 25 100 100     78 if (lc $func eq "extract" && @terms == 2) {
1308 3 100       16 if (UNIVERSAL::isa($terms[0], "DBIx::Perlish::Placeholder")) {
1309 2         7 my $val = $terms[0]->undo;
1310 2         14 @terms = ("$val from $terms[1]");
1311             }
1312             }
1313 25 100 66     82 if (lc($func) eq 'cast' && @terms == 2) {
1314 2 50       17 $terms[1] = $terms[1]->undo if UNIVERSAL::isa($terms[1], "DBIx::Perlish::Placeholder");
1315 2         12 return "cast($terms[0] as $terms[1])";
1316             }
1317 23         230 return "$func(" . join(", ", @terms) . ")";
1318             }
1319             }
1320              
1321             sub parse_multi_assign
1322             {
1323 6     6 0 20 my ($S, $op) = @_;
1324              
1325 6         16 my $hashop = $op->first;
1326 6 50       116 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         142 want_listop($S, $hashop, "anonhash");
1332              
1333 6         22 my $saved_values = $S->{values};
1334 6         14 $S->{values} = [];
1335              
1336 6         13 my $want_const = 1;
1337 6         23 my $field;
1338 6         16 for my $c (get_all_children($hashop)) {
1339 22 100       69 next if is_pushmark_or_padrange($c);
1340              
1341 16 100       46 if ($want_const) {
1342 10         17 my $hash;
1343 10 100 66     178 if (is_op($c, "padhv")) {
    100          
1344 2         29 $hash = $S->{padlist}->[1]->ARRAYelt($c->targ)->object_2svref;
1345             } elsif (is_unop($c, "rv2hv") && is_op($c->first, "padsv")) {
1346 2         13 $hash = $S->{padlist}->[1]->ARRAYelt($c->first->targ)->object_2svref;
1347 2         6 $hash = $$hash;
1348             }
1349 10 100       37 if ($hash) {
1350 4         26 while (my ($k, $v) = each %$hash) {
1351 8         12 push @{$S->{set_values}}, $v;
  8         17  
1352 8         10 push @{$S->{sets}}, "$k = ?";
  8         36  
1353             }
1354             } else {
1355 6         21 $field = want_const($S, $c);
1356 6         14 $want_const = 0;
1357             }
1358             } else {
1359 6         51 my $set = parse_term($S, $c);
1360 6         12 push @{$S->{set_values}}, @{$S->{values}};
  6         16  
  6         14  
1361 6         12 push @{$S->{sets}}, "$field = $set";
  6         27  
1362 6         16 $S->{values} = [];
1363 6         9 $want_const = 1;
1364 6         18 $field = undef;
1365             }
1366             }
1367              
1368 6         17 $S->{values} = $saved_values;
1369 6 50       125 if ( !is_unop($op, 'padsv_store')) {
1370 6         37 $op = $op->last;
1371             }
1372              
1373 6         25 my $tab;
1374 6 100 66     124 if (is_op($op, "padsv") || is_unop($op, "padsv_store")) {
    50          
1375 5         28 my $var = get_var($S, $op);
1376 5         20 $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       51 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 251     251 0 576 my ($S, $op) = @_;
1420 251         387 my $sqlop;
1421 251 100 100     1709 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         18 my $is_lvalue;
1429 11 50       76 if ($op->first->private & 128) {
1430 11         24 $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       31 if ($is_lvalue) {
1437 11         41 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       49 unless $S->{operation} eq "update";
1440             bailout $S, "self-modifications inside an expression is illegal"
1441 10 100       28 if $S->{in_term};
1442 9         16 my $saved_values = $S->{values};
1443 9         19 $S->{values} = [];
1444 9         14 my $set;
1445 9 50       172 if ( is_unop_aux($op, 'multiconcat')) {
1446 0         0 my $v;
1447 0         0 ($set, $v) = try_special_concat($S, $op, multiconcat => { skip_first => 1 });
1448 0 0       0 bailout $S, "unsupported multiconcat" unless $set;
1449 0         0 push @{$S->{values}}, @$v;
  0         0  
1450             } else {
1451 9         47 $set = parse_term($S, $op->last);
1452             }
1453 9         18 push @{$S->{set_values}}, @{$S->{values}};
  9         21  
  9         21  
1454 9         19 $S->{values} = $saved_values;
1455 9 50       34 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         14 push @{$S->{sets}}, "$f = $f $binop2_map{$op->name} $set";
  9         79  
1464             }
1465 9         43 return ();
1466             }
1467             }
1468 240 100 66     4612 if (is_binop($op, "concat") || is_unop_aux($op, "multiconcat")) {
1469 13         57 my ($c, $v) = try_special_concat($S, $op);
1470 11 50       32 if ($c) {
1471 11         16 push @{$S->{values}}, @$v;
  11         31  
1472 11         33 return $c;
1473             }
1474             }
1475 227 100 66     1381 if ($sqlop = $binop_map{$op->name}) {
    100          
    100          
1476 175         921 my $left = parse_term($S, $op->first);
1477 174         946 my $right = parse_term($S, $op->last);
1478 173 100 100     719 if ($sqlop eq "=" || $sqlop eq "<>") {
1479 146 100       398 my $not = $sqlop eq "<>" ? " not" : "";
1480 146 100       751 if ($right eq "null") {
    100          
1481 4         32 return "$left is$not null";
1482             } elsif ($left eq "null") {
1483 4         19 return "$right is$not null";
1484             }
1485             }
1486 165 100       833 if ($op->name eq "pow") {
1487 2   50     15 my $flavor = lc($S->{gen_args}->{flavor} || '');
1488 2 100 66     12 if ($flavor eq "pg" || $flavor eq "pglite") {
1489 1         4 return "pow($left, $right)";
1490             } else {
1491 1         9 bailout $S, "exponentiation is not supported for $flavor DB driver";
1492             }
1493             }
1494 163         776 return "$left $sqlop $right";
1495             } elsif ($op->name eq "lt") {
1496 24 100       530 if (is_unop($op->last, "negate")) {
1497 19         104 my $r = try_parse_subselect($S, $op);
1498 17 50       110 return $r if $r;
1499             }
1500             # if the "subselect theory" fails, try a normal binop
1501 5         56 my $left = parse_term($S, $op->first);
1502 5         56 my $right = parse_term($S, $op->last);
1503 5         35 return "$left < $right";
1504             } elsif ($op->name eq "sassign" || $op->name eq 'padsv_store') {
1505 27         105 parse_assign($S, $op);
1506 23         92 return ();
1507             } else {
1508 1         9 BAILOUT:
1509             bailout $S, "unsupported binop " . $op->name;
1510             }
1511             }
1512              
1513             sub parse_multiconcat
1514             {
1515 0     0 0 0 my ( $S, $aux, %opt) = @_;
1516 0         0 my @concats;
1517              
1518 0         0 my @args = ($aux->first);
1519 0   0     0 push @args, $args[-1]->sibling while !is_null($args[-1]) && !is_null($args[-1]->sibling);
1520 0   0     0 shift @args while @args && is_op($args[0], 'null');
1521 0 0       0 shift @args if $opt{skip_first};
1522              
1523 0         0 my ($nargs, $pv, @lengths) = $aux->aux_list($S->{curr_cv});
1524 0         0 while ( defined (my $l = shift @lengths )) {
1525 0 0       0 if ( $l >= 0 ) {
1526 0         0 my $str = substr( $pv, 0, $l, '');
1527 0         0 push @concats, { str => $str };
1528             }
1529 0 0       0 my $op = shift(@args) or last;
1530 0 0       0 if ( $opt{eval}) {
1531 0         0 my ($rv, $ok) = get_value($S, $op, soft => 1, eval => 1);
1532 0 0       0 bailout $S, "cannot parse expression (near $pv)" unless $ok;
1533 0         0 push @concats, { str => $rv };
1534             } else {
1535 0         0 push @concats, { op => $op };
1536             }
1537             }
1538              
1539 0         0 return @concats;
1540             }
1541              
1542             sub try_special_concat
1543             {
1544 83     83 0 230 my ($S, $op, %opt) = @_;
1545 83         134 my @terms;
1546             my $str;
1547 83 100       1631 if (is_binop($op, "concat")) {
    100          
    100          
    100          
    50          
    100          
    100          
    50          
    50          
1548 33         381 my @t = try_special_concat($S, $op->first, terms_only => 1);
1549 31 50       93 return () unless @t;
1550 31         63 push @terms, @t;
1551 31         150 @t = try_special_concat($S, $op->last, terms_only => 1);
1552 29 50       86 return () unless @t;
1553 29         53 push @terms, @t;
1554             } elsif (($str = is_const($S, $op))) {
1555 26         89 push @terms, {str => $str};
1556             } elsif (is_unop($op, "null")) {
1557 4         38 $op = $op->first;
1558 4         98 while (!is_null($op)) {
1559 6         42 my @t = try_special_concat($S, $op, terms_only => 1);
1560 4 50       11 return () unless @t;
1561 4         8 push @terms, @t;
1562 4         85 $op = $op->sibling;
1563             }
1564             } elsif (is_op($op, "null")) {
1565 2         17 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         20 my ($t, $f) = eval { get_tab_field($S, $op) };
  6         18  
1578 6 50       22 return () unless $f;
1579 6         27 push @terms, {tab => $t, field => $f};
1580             } elsif (is_op($op, "padsv")) {
1581 10         34 my $tab = find_aliased_tab($S, $op);
1582 10 50       32 return () unless $tab;
1583 10         37 push @terms, {tab => $tab};
1584             } elsif (is_unop_aux($op, "multiconcat")) {
1585 0   0     0 my @subterms = parse_multiconcat($S, $op, %{ $opt{multiconcat} // {}});
  0         0  
1586 0 0       0 return () unless @subterms;
1587 0         0 for my $st (@subterms) {
1588 0 0       0 if ( defined $st->{str} ) {
1589 0         0 push @terms, $st;
1590             } else {
1591 0         0 my @t = try_special_concat($S, $st->{op}, terms_only => 1);
1592 0 0       0 return () unless @t;
1593 0         0 push @terms, @t;
1594             }
1595             }
1596             } elsif (is_unop_aux($op, "multideref")) {
1597 2         31 push @terms, { str => parse_multideref($S, $op ) };
1598             } else {
1599 0         0 return ();
1600             }
1601 73 100       248 return @terms if $opt{terms_only};
1602 11         23 $str = "";
1603 11         24 my @sql;
1604             my @v;
1605 11         23 @terms = grep { !$_->{skip} } @terms;
  42         91  
1606 11         32 while (@terms) {
1607 30         49 my $t = shift @terms;
1608 30 100       71 if (exists $t->{str}) {
    100          
1609 14         47 $str .= $t->{str};
1610             } elsif (exists $t->{field}) {
1611 6 100       18 if (length($str)) {
1612 4         9 push @v, $str;
1613 4         9 push @sql, '?';
1614             }
1615 6 50 33     29 if ($S->{operation} eq "delete" || $S->{operation} eq "update") {
1616 0         0 push @sql, $t->{field};
1617             } else {
1618 6         16 push @sql, "$t->{tab}.$t->{field}";
1619             }
1620 6         19 $str = "";
1621             } else {
1622 10         25 my $t2 = shift @terms;
1623 10 50       35 return () unless $t2;
1624 10 50       25 return () unless defined $t2->{str};
1625 10 50       58 return () unless $t2->{str} =~ s/^->(\w+)//;
1626 10         24 my $f = $1;
1627 10 100       25 if (length($str)) {
1628 9         17 push @v, $str;
1629 9         28 push @sql, '?';
1630             }
1631 10 50 33     65 if ($S->{operation} eq "delete" || $S->{operation} eq "update") {
1632 0         0 push @sql, $f;
1633             } else {
1634 10         37 push @sql, "$t->{tab}.$f";
1635             }
1636 10         34 $str = $t2->{str};
1637             }
1638             }
1639 11 100       39 if (length($str)) {
1640 10         19 push @v, $str;
1641 10         18 push @sql, '?';
1642             }
1643 11         15 my $sql;
1644 11 100 50     61 if (lc($S-> {gen_args}-> {flavor} || '') eq "mysql") {
1645 5         17 $sql = "concat(" . join(", ", @sql) . ")";
1646             } else {
1647 6         17 $sql = join " || ", @sql;
1648             }
1649 11         47 return ($sql, \@v);
1650             }
1651              
1652             sub parse_entersub
1653             {
1654 213     213 0 423 my ($S, $op) = @_;
1655 213         500 my $tab = try_parse_attr_assignment($S, $op);
1656 213 100       870 return () if $tab;
1657 10         28 return scalar parse_term($S, $op);
1658             }
1659              
1660             sub parse_complex_regex
1661             {
1662 8     8 0 23 my ($S, $op) = @_;
1663              
1664 8 50       163 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         18 return want_const( $S, $op);
1685             } elsif (my ($rx, $ok) = get_value($S, $op, soft => 1)) {
1686 4 100       22 return undef unless $rx;
1687 3         11 $rx =~ s/^\(\?\-\w*\:(.*)\)$/$1/; # (?-xism:moo) -> moo
1688 3         10 return $rx;
1689             } elsif (is_unop($op, "null")) {
1690 2         8 my $rx = "";
1691 2         8 my $rxop = $op->first;
1692 2         38 while (!is_null($rxop)) {
1693 6 100       13 $rx .= parse_complex_regex($S, $rxop)
1694             unless is_pushmark_or_padrange($rxop);
1695 6         138 $rxop = $rxop->sibling;
1696             }
1697 2         7 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         148 my ( $like, $case) = ( $op->precomp, $op-> pmflags & B::PMf_FOLD);
1707              
1708 20 100       74 unless ( defined $like) {
1709 4         25 my $logop = $op-> first-> sibling;
1710 4 50 33     88 bailout $S, "strange regex " . $op->name
1711             unless $logop and is_logop( $logop, 'regcomp');
1712 4         34 $like = parse_complex_regex( $S, $logop-> first);
1713 4 100       18 return "" unless defined $like; # explicitly nulled like
1714             }
1715              
1716 19         102 my $lhs = parse_term($S, $op->first);
1717              
1718 19   50     75 my $flavor = lc($S-> {gen_args}-> {flavor} || '');
1719 19         35 my $what = 'like';
1720              
1721 19         39 $like =~ s/\(\?\^\w+\:((?:[^\\]|\\.)*)\)/$1/g; # ignore ?^flags:
1722              
1723 19         129 my $can_like = $like =~ /^\^?(?:[-!%\s\w]|\\.)*\$?$/; # like that begins with non-% can use indexes
1724              
1725 19 50 66     96 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       39 if ( $can_like) {
1740 18 100       37 $what = 'ilike' if $case;
1741 18         169 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       5 if ($case) {
1784 1         4 $lhs = "lower($lhs)";
1785 1         3 $like = lc $like;
1786             }
1787 1 50       4 bailout $S, "Regex too complex for implementation using LIKE keyword: $like"
1788             if $like =~ /(?
1789 19         69 LIKE:
1790             $like =~ s/'/''/g;
1791 19         38 $like =~ s/\\([^A-Za-z_0-9])/$1/g; # de-quotemeta
1792 19         33 my $escape = "";
1793 19 50 66     63 if ($flavor eq "pg" || $flavor eq "oracle") {
1794             # XXX it is possible that more flavors support like...escape
1795 19         35 my $need_esc;
1796 19 100       62 $need_esc = 1 if $like =~ s/!/!!/g;
1797 19 100       49 $need_esc = 1 if $like =~ s/%/!%/g;
1798 19 100       46 $need_esc = 1 if $like =~ s/_/!_/g;
1799 19 100       39 $escape = " escape '!'" if $need_esc;
1800             } else {
1801 0         0 $like =~ s/%/\\%/g;
1802 0         0 $like =~ s/_/\\_/g;
1803             }
1804 19         31 $like =~ s/\.\*/%/g;
1805 19         29 $like =~ s/(?
1806 19         30 $like =~ s/\\\././g;
1807 19 100       71 $like = "%$like" unless $like =~ s|^\^||;
1808 19 100       56 $like = "$like%" unless $like =~ s|\$$||;
1809 19 100       124 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 90 my ($S, $op) = @_;
1829 40         87 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     229 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         84 my $jointype;
1841            
1842 37 100       206 if ($op[1]-> name eq 'le') {
1843             # support <= as well as =>
1844 6 100       37 bailout $S, "not a valid join() syntax"
1845             unless @op == 2;
1846 5         37 @op[1,2] = ( $op[1]-> first, $op[1]-> last);
1847 5 50       98 bailout $S, "not a valid join() syntax"
1848             unless is_binop( $op[1]);
1849             }
1850              
1851 36 100       114 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     52 $join_map{ $op[1]-> name } eq 'inner';
1856 3         19 $jointype = 'cross';
1857             } else {
1858             bailout $S, "not a valid join() syntax: one of &,|,x,+,*,<,> is expected"
1859 32 100       146 unless exists $join_map{ $op[1]-> name };
1860 31 100 66     641 bailout $S, "not a valid join() syntax"
1861             unless is_unop( $op[2]) and $op[2]-> name eq 'entersub';
1862 30         134 $jointype = $join_map{ $op[1]-> name };
1863             }
1864              
1865             # table names
1866 33         64 my @tab;
1867 33 100       141 $tab[0] = find_aliased_tab($S, $op[1]-> first) or
1868             bailout $S, "first argument of join() is not a table";
1869 32 100       139 $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         64 my ( $condition, $codeop);
1874 31 100       73 if ( $op[2]) {
1875 30         75 $codeop = try_get_subselect( $S, $op[2]);
1876 30 100       76 bailout $S, "third argument to join is not a subselect expression"
1877             unless $codeop;
1878              
1879 29         108 my $cv = $codeop->sv;
1880 29 50       75 if (!$$cv) {
1881 29         135 $cv = $S->{padlist}->[1]->ARRAYelt($codeop->targ);
1882             }
1883 29         72 my $subref = $cv->object_2svref;
1884             my $S2 = init(
1885 29         47 %{$S->{gen_args}},
  29         164  
1886             operation => 'select',
1887             values => [],
1888             join_values => [],
1889             prev_S => $S,
1890             );
1891 29         80 $S2-> {alias} = $S-> {alias};
1892 29         94 parse_sub($S2, $subref);
1893             bailout $S,
1894             "join() subselect expression cannot contain anything ".
1895             "but conditional expressions on already declared tables"
1896 145         183 if scalar( grep { @{ $S2-> {$_} } } qw(
  145         413  
1897             group_by order_by autogroup_by ret_values joins
1898 29 100 100     104 )) or $S2->{alias} ne $S->{alias};
1899              
1900 25 50       36 unless ( @{ $S2->{where}||[] }) {
  25 100       102  
1901 3 100       20 bailout $S,
1902             "join() subselect expression must contain ".
1903             "at least one conditional expression"
1904             unless $jointype eq 'inner';
1905 2         16 $jointype = 'cross';
1906             } else {
1907 22         34 $condition = join(' and ', @{ $S2-> {where} });
  22         62  
1908 22         33 push @{$S->{join_values}}, @{$S2->{values}};
  22         35  
  22         161  
1909             }
1910             }
1911              
1912 25         212 return [ $jointype, @tab, $condition ];
1913             }
1914              
1915             sub try_parse_range
1916             {
1917 13     13 0 34 my ($S, $op) = @_;
1918 13 100       266 return try_parse_range($S, $op->first) if is_unop($op, "null");
1919 7 100       152 return unless is_unop($op, "flop");
1920 6         39 $op = $op->first;
1921 6 50       118 return unless is_unop($op, "flip");
1922 6         57 $op = $op->first;
1923 6 50       140 return unless is_logop($op, "range");
1924 6         44 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 51 my ($S, $op) = @_;
1931 19 100       467 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       58 unless $S->{operation} eq "select";
1934 7         40 my ($from, $to) = try_parse_range($S, $op->first);
1935 5 100       39 bailout $S, "range operator expected" unless defined $to;
1936 4         15 $S->{offset} = $from;
1937 4         12 $S->{limit} = $to-$from+1;
1938 4         11 return;
1939             } elsif (my ($val, $ok) = get_value($S, $op->first, soft => 1)) {
1940 4         23 return compile_conditionally($S, $op, !$val);
1941             } else {
1942 6         40 my $left = parse_term($S, $op->first);
1943 6         50 my $right = parse_term($S, $op->first->sibling);
1944 6         23 return "$left or $right";
1945             }
1946             }
1947              
1948             sub parse_and
1949             {
1950 14     14 0 42 my ($S, $op) = @_;
1951 14 100       97 if (my ($val, $ok) = get_value($S, $op->first, soft => 1)) {
1952 10         35 return compile_conditionally($S, $op, $val);
1953             } else {
1954 4         50 my $left = parse_term($S, $op->first);
1955 4         38 my $right = parse_term($S, $op->first->sibling);
1956 4         18 return "$left and $right";
1957             }
1958             }
1959              
1960             sub compile_conditionally
1961             {
1962 14     14 0 31 my ($S, $op, $val) = @_;
1963 14 100       26 if ($val) {
1964 9         50 $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     222 if (is_binop($op) || $op->name eq "sassign") {
    100 33        
    50          
1968 1         5 return parse_expr($S, $op);
1969             } elsif (is_listop($op, "return")) {
1970             # conditional returns are nice
1971 6         47 parse_return($S, $op);
1972 4         13 return ();
1973             } elsif (is_listop($op, "leave") || is_listop($op, "scope")) {
1974 2         15 parse_list($S, $op);
1975 2         17 return ();
1976             } else {
1977 0         0 return scalar parse_term($S, $op);
1978             }
1979             } else {
1980 5         16 return ();
1981             }
1982             }
1983              
1984             sub parse_fieldlist_label
1985             {
1986 3     3 0 17 my ($S, $label, $lop, $op) = @_;
1987              
1988 3         5 my @op;
1989 3 100       70 if (is_listop($op, "list")) {
1990 1         4 @op = get_all_children($op);
1991             } else {
1992 2         16 push @op, $op;
1993             }
1994 3         12 for $op (@op) {
1995 5 100       15 next if is_pushmark_or_padrange($op);
1996 4         41 my ($t, $f) = get_tab_field($S, $op);
1997 4         77 push @{$S->{$label->{key}}},
1998 4 50 33     25 ($S->{operation} eq "delete" || $S->{operation} eq "update") ?
1999             $f : "$t.$f";
2000             }
2001 3         20 $S->{skipnext} = 1;
2002             }
2003              
2004             sub parse_sort
2005             {
2006 3     3 0 6 my ($S, $op) = @_;
2007 3         9 parse_orderby_label($S, "order_by", undef, $op);
2008 3         20 delete $S->{skipnext};
2009             }
2010              
2011             sub parse_orderby_label
2012             {
2013 9     9 0 26 my ($S, $label, $lop, $op) = @_;
2014              
2015 9 100       28 my $key = ref $label ? $label->{key} : $label;
2016              
2017 9         15 my @op;
2018 9 100 100     208 if (is_listop($op, "list") || is_listop($op, "sort")) {
    100          
2019 6         16 @op = get_all_children($op);
2020             } elsif ( is_unop($op, "null")) {
2021 1         20 $op = $op->first;
2022 1   66     43 while ( $op && !is_null($op)) {
2023 3         8 push @op, $op;
2024 3         73 $op = $op->sibling;
2025             }
2026             } else {
2027 2         14 push @op, $op;
2028             }
2029 9         26 my $order = "";
2030 9         20 for $op (@op) {
2031 26 100       53 next if is_pushmark_or_padrange($op);
2032             # XXX next if is_op($op, "null");
2033 20         36 my $term;
2034 20 100       42 $term = parse_term($S, $op, inline_placeholder => 1)
2035             unless $term = is_const($S, $op);
2036 20 100       96 if ($term =~ /^asc/i) {
    100          
2037 2         4 next; # skip "ascending"
2038             } elsif ($term =~ /^desc/i) {
2039 7         14 $order = "desc";
2040 7         18 next;
2041             } else {
2042 11 100       28 if ($order) {
2043 6         11 push @{$S->{$key}}, "$term $order";
  6         22  
2044 6         17 $order = "";
2045             } else {
2046 5         9 push @{$S->{$key}}, $term;
  5         20  
2047             }
2048             }
2049             }
2050 9         40 $S->{skipnext} = 1;
2051             }
2052              
2053             sub parse_numassign_label
2054             {
2055 11     11 0 37 my ($S, $label, $lop, $op) = @_;
2056              
2057             # TODO more generic values
2058 11         26 my ($const,$sv) = is_const($S, $op);
2059 11 100 66     161 if (!$sv && is_op($op, "padsv")) {
2060 6 100       28 if (find_aliased_tab($S, $op)) {
2061 2         11 bailout $S, "cannot use table variable after ", $lop->label;
2062             }
2063 4         24 $sv = $S->{padlist}->[1]->ARRAYelt($op->targ);
2064 4         9 $const = ${$sv->object_2svref};
  4         9  
2065             }
2066 9 100 33     122 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         26 $S->{$label->{key}} = $const;
2069 7         30 $S->{skipnext} = 1;
2070             }
2071              
2072             sub parse_notice_label
2073             {
2074 1     1 0 5 my ($S, $label, $lop, $op) = @_;
2075 1         5 $S->{$label->{key}}++;
2076             }
2077              
2078             sub parse_table_label
2079             {
2080 6     6 0 21 my ($S, $label, $lop, $op) = @_;
2081              
2082 6 50       17 if ( $] >= 5.037 ) {
2083 0 0       0 bailout $S, "label ", $lop->label, " must be followed by an assignment"
2084             unless $op->name eq "padsv_store";
2085             } else {
2086 6 100       29 bailout $S, "label ", $lop->label, " must be followed by an assignment"
2087             unless $op->name eq "sassign";
2088             }
2089 5         26 my $attr = parse_simple_term($S, $op->first);
2090 4         13 my $varn;
2091 4 50       15 if ( $] >= 5.037 ) {
2092 0         0 $varn = padname($S, $op, no_fakes => 1);
2093 0 0       0 bailout $S, "label ", $lop->label, " must be followed by a lexical variable declaration"
2094             unless defined $varn;
2095             } else {
2096 4 100 66     108 bailout $S, "label ", $lop->label, " must be followed by a lexical variable declaration"
2097             unless is_op($op->last, "padsv") && ($varn = padname($S, $op->last, no_fakes => 1));
2098             }
2099 3         15 new_var($S, $varn, $attr);
2100 3         23 $S->{skipnext} = 1;
2101             }
2102              
2103             my $action_orderby = {
2104             kind => 'termlist',
2105             key => 'order_by',
2106             handler => \&parse_orderby_label,
2107             };
2108             my $action_groupby = {
2109             kind => 'fieldlist',
2110             key => 'group_by',
2111             handler => \&parse_fieldlist_label,
2112             };
2113             my $action_limit = {
2114             kind => 'numassign',
2115             key => 'limit',
2116             handler => \&parse_numassign_label,
2117             };
2118             my $action_offset = {
2119             kind => 'numassign',
2120             key => 'offset',
2121             handler => \&parse_numassign_label,
2122             };
2123             my $action_distinct = {
2124             kind => 'notice',
2125             key => 'distinct',
2126             handler => \&parse_notice_label,
2127             };
2128             my %labelmap = (
2129             select => {
2130             orderby => $action_orderby,
2131             order_by => $action_orderby,
2132             order => $action_orderby,
2133             sortby => $action_orderby,
2134             sort_by => $action_orderby,
2135             sort => $action_orderby,
2136              
2137             groupby => $action_groupby,
2138             group_by => $action_groupby,
2139             group => $action_groupby,
2140              
2141             limit => $action_limit,
2142              
2143             offset => $action_offset,
2144              
2145             distinct => $action_distinct,
2146             },
2147             );
2148              
2149             sub parse_labels
2150             {
2151 28     28 0 72 my ($S, $lop) = @_;
2152 28         155 my $label = $labelmap{$S->{operation}}->{lc $lop->label};
2153 28 100 100     121 if (!$label && lc $lop->label eq "table") {
2154 6         25 $label = { kind => 'table', handler => \&parse_table_label };
2155             }
2156 28 100       98 bailout $S, "label ", $lop->label, " is not understood"
2157             unless $label;
2158 27         102 my $op = $lop->sibling;
2159 27 50       89 if ($label->{handler}) {
2160 27         90 $label->{handler}->($S, $label, $lop, $op);
2161             } else {
2162 0         0 bailout $S, "internal error parsing label ", $op->label;
2163             }
2164             }
2165              
2166             sub parse_selfmod
2167             {
2168 5     5 0 11 my ($S, $op, $oper) = @_;
2169              
2170 5         13 my ($tab, $f) = get_tab_field($S, $op, lvalue => 1);
2171             bailout $S, "self-modifications are not understood in $S->{operation}'s query sub"
2172 5 100       23 unless $S->{operation} eq "update";
2173 4         26 return "$f = $f $oper";
2174             }
2175              
2176             sub where_or_having
2177             {
2178 447     447 0 1010 my ($S, @what) = @_;
2179 447 100       629 push @{$S->{$S->{this_is_having} ? "having" : "where"}}, @what;
  447         1449  
2180 447         2513 $S->{this_is_having} = 0;
2181             }
2182              
2183             sub parse_op
2184             {
2185 2546     2546 0 4500 my ($S, $op) = @_;
2186              
2187 2546 50       10550 return if $S->{seen}->{$$op}++;
2188              
2189 2546 100       5637 if ($S->{skipnext}) {
2190 19         44 delete $S->{skipnext};
2191 19         84 return;
2192             }
2193 2527 100 66     52951 if (is_listop($op, "list")) {
    100 66        
    100 66        
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    100          
    50          
    0          
2194 9         58 parse_list($S, $op);
2195             } elsif (is_listop($op, "lineseq")) {
2196 369         957 parse_list($S, $op);
2197             } elsif (is_binop($op, "leaveloop") &&
2198             is_loop($op->first, "enterloop") &&
2199             is_listop($op->last, "lineseq"))
2200             {
2201 8         69 parse_list($S, $op->last);
2202             } elsif (is_listop($op, "return")) {
2203 97         365 parse_return($S, $op);
2204             } elsif (is_binop($op) || is_unop($op, 'padsv_store') ) {
2205 214         675 where_or_having($S, parse_expr($S, $op));
2206             } elsif (is_unop($op, "not")) {
2207 6         38 where_or_having($S, scalar parse_term($S, $op));
2208             } elsif (is_logop($op, "or")) {
2209 17         110 my $or = parse_or($S, $op);
2210 11 100       95 where_or_having($S, "($or)") if $or;
2211 11         103 $S->{this_is_having} = 0;
2212             } elsif (is_logop($op, "and")) {
2213 12         55 my $and = parse_and($S, $op);
2214 11 100       35 where_or_having($S, $and) if $and;
2215 11         83 $S->{this_is_having} = 0;
2216             } elsif (is_unop($op, "leavesub")) {
2217 375         1957 parse_op($S, $op->first);
2218             } elsif (is_unop($op, "null")) {
2219 224         1103 parse_op($S, $op->first);
2220             } elsif (is_unop($op, "defined")) {
2221 2         10 where_or_having($S, scalar parse_term($S, $op));
2222             } elsif (is_op($op, "padsv")) {
2223             # XXX Skip for now, it is either a variable
2224             # that does not represent a table, or else
2225             # it is already associated with a table in $S.
2226             } elsif (is_op($op, "last")) {
2227             bailout $S, "there should be no \"last\" statements in $S->{operation}'s query sub"
2228 2 50       14 unless $S->{operation} eq "select";
2229 0         0 $S->{limit} = 1;
2230             } elsif (is_pushmark_or_padrange($op)) {
2231             # skip
2232             } elsif (is_op($op, "enter")) {
2233             # skip
2234             } elsif (is_op($op, "null")) {
2235             # skip
2236 195         969 parse_op($S, $op->sibling);
2237             } elsif (is_cop($op, "nextstate")) {
2238 684         2388 $S->{file} = $op->file;
2239 684         2017 $S->{line} = $op->line;
2240 684         1876 $_cover->($op);
2241 684 100       3247 if ($op->label) {
2242 28         127 parse_labels($S, $op);
2243             }
2244             } elsif (is_cop($op)) {
2245             # XXX any other things?
2246 0         0 $S->{file} = $op->file;
2247 0         0 $S->{line} = $op->line;
2248             # skip
2249             } elsif (is_unop($op, "entersub")) {
2250 213         648 where_or_having($S, parse_entersub($S, $op));
2251             } elsif (is_pmop($op, "match")) {
2252 16         59 where_or_having($S, parse_regex($S, $op, 0));
2253             } elsif ( $op->name eq 'join') {
2254 40         73 push @{$S->{joins}}, parse_join($S, $op);
  40         120  
2255             } elsif ($op->name eq 'sort') {
2256 3         10 parse_sort($S, $op);
2257             } elsif (is_unop($op, "postinc")) {
2258 1         3 push @{$S->{sets}}, parse_selfmod($S, $op->first, "+ 1");
  1         9  
2259             } elsif (is_unop($op, "postdec")) {
2260 0         0 push @{$S->{sets}}, parse_selfmod($S, $op->first, "- 1");
  0         0  
2261             } elsif (is_unop($op, "preinc")) {
2262 2         17 push @{$S->{sets}}, parse_selfmod($S, $op->first, "+ 1");
  2         11  
2263             } elsif (is_unop($op, "predec")) {
2264 2         8 push @{$S->{sets}}, parse_selfmod($S, $op->first, "- 1");
  2         11  
2265             } elsif (is_listop($op, "exec")) {
2266 17         134 $S->{seen_exec}++;
2267             } elsif (is_unop_aux($op, "multiconcat")) {
2268 0         0 where_or_having($S, parse_expr($S, $op));
2269             } else {
2270 0         0 bailout $S, "don't quite know what to do with op \"" . $op->name . "\"";
2271             }
2272             }
2273              
2274             sub parse_sub
2275             {
2276 375     375 0 773 my ($S, $sub) = @_;
2277 375 50       917 if ($DEVEL) {
2278 0         0 $Carp::Verbose = 1;
2279 0         0 require B::Concise;
2280             #my $walker = B::Concise::compile('-terse', $sub);
2281 0         0 my $walker = B::Concise::compile('-concise', $sub);
2282 0         0 print "CODE DUMP:\n";
2283 0         0 $walker->();
2284 0         0 print "\n\n";
2285             }
2286 375         1325 my $root = B::svref_2object($sub);
2287 375         2100 $S->{padlist} = [$root->PADLIST->ARRAY];
2288 375         924 $S->{curr_cv} = $root;
2289 375 50       2849 $S->{padlists}->{ $root->PADLIST->id } = $S->{padlist} if $root->PADLIST->can('id');
2290 375         1436 $root = $root->ROOT;
2291 375         912 parse_op($S, $root);
2292             }
2293              
2294             sub B::OP::foo
2295             {
2296 0     0   0 printf "%s 0x%x\n", _o($_[0]), ${$_[0]};
  0         0  
2297             }
2298              
2299             sub init
2300             {
2301 375     375 0 1796 my %args = @_;
2302             my $S = {
2303             gen_args => \%args,
2304             file => '??',
2305             line => '??',
2306             subselect => 's01',
2307             operation => $args{operation},
2308             values => [],
2309             join_values => [],
2310             sets => [],
2311             set_values => [],
2312             ret_values => [],
2313             where => [],
2314             order_by => [],
2315             group_by => [],
2316             additions => [],
2317             joins => [],
2318             key_field => 1,
2319             aggregates => { avg => 1, count => 1, max => 1, min => 1, sum => 1 },
2320             autogroup_by => [],
2321             autogroup_fields => {},
2322             seen => {},
2323             padlists => $args{prev_S} ? $args{prev_S}->{padlists} : {},
2324 375 100       5335 };
2325 375 100       1303 $S->{alias} = $args{prefix} ? "$args{prefix}_t01" : "t01";
2326 375         979 $S;
2327             }
2328              
2329             # Borrowed from IO::All by Ingy döt Net.
2330             my $old_warn_handler = $SIG{__WARN__};
2331             $SIG{__WARN__} = sub {
2332             if ($_[0] !~ /^Useless use of .+ in void context/) {
2333             goto &$old_warn_handler if $old_warn_handler;
2334             warn(@_);
2335             }
2336             };
2337              
2338             $_cover = sub {};
2339             if (*Devel::Cover::coverage{CODE}) {
2340             my $Coverage = Devel::Cover::coverage(0);
2341             $_cover = sub { $Coverage->{statement}{Devel::Cover::get_key($_[0])} ||= 1 };
2342             }
2343              
2344             package
2345             DBIx::Perlish::Placeholder;
2346              
2347 25     25   31310 use overload '""' => sub { "?" }, eq => sub { "$_[0]" eq "$_[1]" };
  25     100   25906  
  25         355  
  166         854  
  72         177  
2348              
2349             sub new
2350             {
2351 99     99   220 my ($class, $S, $pos) = @_;
2352 99         662 bless { S => $S, position => $pos }, $class;
2353             }
2354              
2355             sub value
2356             {
2357 0     0   0 my $me = shift;
2358 0         0 return $me->{S}{values}[$me->{position}];
2359             }
2360              
2361             sub undo
2362             {
2363 4     4   5 my $me = shift;
2364 4         9 splice @{$me->{S}{values}}, $me->{position}, 1;
  4         49  
2365             }
2366              
2367             "the magic stops here; welcome to the real world";