1 package Data::Query::Renderer::SQL::Slice::FetchFirst;
3 use Data::Query::Constants qw(
4 DQ_SELECT DQ_ALIAS DQ_IDENTIFIER DQ_ORDER DQ_SLICE
8 sub _render_slice_limit {
11 ($dq->{from} ? $self->_render($dq->{from}) : ()),
12 $self->_format_keyword('FETCH FIRST'),
13 sprintf("%i", $dq->{limit}{value}),
14 $self->_format_keyword('ROWS ONLY')
18 sub _slice_type { 'FetchFirst' }
22 unless ($dq->{offset}) {
23 return $self->_render_slice_limit($dq);
25 unless ($dq->{order_is_stable}) {
26 die $self->_slice_type." limit style requires a stable order";
28 die "Slice's inner is not a Select"
29 unless (my $orig_select = $dq->{from})->{type} eq DQ_SELECT;
32 my (@inside_select_list, @outside_select_list);
33 my $default_inside_alias;
34 SELECT: foreach my $s (@{$orig_select->{select}}) {
36 if ($s->{type} eq DQ_ALIAS) {
41 if ($s->{type} eq DQ_IDENTIFIER) {
42 if (!$name and @{$s->{elements}} == 2) {
43 $default_inside_alias ||= $s->{elements}[0];
44 if ($s->{elements}[0] eq $default_inside_alias) {
45 $alias_map{join('.',@{$s->{elements}})} = $s;
46 push @inside_select_list, $s;
47 push @outside_select_list, $s;
51 $name ||= join('__', @{$s->{elements}});
52 $key = join('.', @{$s->{elements}});
54 die "XXX not implemented yet" unless $name;
57 $name ||= sprintf("GENSYM__%03i",++$gensym_count);
58 push @inside_select_list, +{
63 push @outside_select_list, $alias_map{$key} = +{
64 type => DQ_IDENTIFIER,
68 my $order = $orig_select->{from};
69 my $order_gensym_count;
70 die "Slice's Select not followed by Order but order_is_stable set"
71 unless $order->{type} eq DQ_ORDER;
72 my (@order_nodes, %order_map);
73 while ($order->{type} eq DQ_ORDER) {
74 my $by = $order->{by};
75 if ($by->{type} eq DQ_IDENTIFIER) {
76 $default_inside_alias ||= $by->{elements}[0]
77 if @{$by->{elements}} == 2;
79 = $alias_map{join('.', @{$by->{elements}})}
82 @{$by->{elements}} == 2
83 and $by->{elements}[0] eq $default_inside_alias
87 my $name = sprintf("ORDER__BY__%03i",++$order_gensym_count);
88 push @inside_select_list, +{
94 type => DQ_IDENTIFIER,
95 elements => [ $name ],
100 die "XXX not implemented yet";
102 push @order_nodes, $order;
103 $order = $order->{from};
105 my $inside_order = $order;
109 reverse => $_->{reverse},
110 from => $inside_order
111 } for reverse @order_nodes;
112 my $inside_select = +{
114 select => \@inside_select_list,
115 from => $inside_order,
117 my $limit_plus_offset = +{
118 %{$dq->{limit}}, value => $dq->{limit}{value} + $dq->{offset}{value}
120 $default_inside_alias ||= 'me';
123 to => $default_inside_alias,
126 limit => $limit_plus_offset,
127 from => $inside_select,
130 my $outside_order = $bridge_from;
133 by => $order_map{$_->{by}},
134 reverse => !$_->{reverse},
135 from => $outside_order
136 } for reverse @order_nodes;
137 my $outside_select = +{
140 $dq->{preserve_order}
142 @outside_select_list,
143 grep @{$_->{elements}} == 1, @order_map{map $_->{by}, @order_nodes}
145 : \@outside_select_list,
147 from => $outside_order,
151 limit => $dq->{limit},
152 from => $outside_select
154 if ($dq->{preserve_order}) {
158 to => $default_inside_alias,
162 by => $order_map{$_->{by}},
163 reverse => $_->{reverse},
165 } for reverse @order_nodes;
168 select => \@outside_select_list,
172 return $self->_render($final);