File Coverage

blib/lib/DBIx/Perlish/Parse.pm
Criterion Covered Total %
statement 1094 1327 82.4
branch 690 1006 68.5
condition 219 382 57.3
subroutine 97 103 94.1
pod 0 89 0.0
total 2100 2907 72.2


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