Commit | Line | Data |
8c194608 |
1 | package DBIx::Class::Storage::DBI::Pg::Sth; |
2 | use strict; |
3 | use warnings; |
4 | use base 'Class::Accessor::Grouped'; |
5 | |
6 | __PACKAGE__->mk_group_accessors('simple' => |
7 | 'storage', |
8 | 'cursor_id', 'cursor_created', |
9 | 'cursor_sth', 'fetch_sth', |
10 | ); |
11 | |
12 | sub new { |
13 | my ($class, $storage, $dbh, $sql) = @_; |
14 | |
15 | if ($sql =~ /^SELECT\b/i) { |
16 | my $self=bless {},$class; |
17 | $self->storage($storage); |
18 | |
19 | my $csr_id=$self->_cursor_name_from_number( |
20 | $storage->_get_next_pg_cursor_number() |
21 | ); |
22 | my $hold= ($sql =~ /\bFOR\s+UPDATE\s*\z/i) ? '' : 'WITH HOLD'; |
23 | $sql="DECLARE $csr_id CURSOR $hold FOR $sql"; |
24 | $self->cursor_id($csr_id); |
25 | $self->cursor_sth($storage->_dbh_sth($dbh,$sql)); |
26 | $self->cursor_created(0); |
27 | return $self; |
28 | } |
29 | else { |
30 | die "Can only be used for SELECTS"; |
31 | } |
32 | } |
33 | |
34 | sub _cursor_name_from_number { |
35 | return 'dbic_pg_cursor_'.$_[1]; |
36 | } |
37 | |
38 | sub _cleanup_sth { |
39 | my ($self)=@_; |
40 | |
41 | if ($self->fetch_sth) { |
42 | $self->fetch_sth->finish(); |
43 | $self->fetch_sth(undef); |
44 | } |
45 | if ($self->cursor_sth) { |
46 | $self->cursor_sth->finish(); |
47 | $self->cursor_sth(undef); |
48 | $self->storage->dbh->do('CLOSE '.$self->cursor_id); |
49 | } |
50 | } |
51 | |
52 | sub DESTROY { |
53 | my ($self) = @_; |
54 | |
55 | eval { $self->_cleanup_sth }; |
56 | |
57 | return; |
58 | } |
59 | |
60 | sub bind_param { |
61 | my ($self,@bind_args)=@_; |
62 | |
63 | return $self->cursor_sth->bind_param(@bind_args); |
64 | } |
65 | |
66 | sub execute { |
67 | my ($self,@bind_values)=@_; |
68 | |
69 | $self->cursor_created(1); |
70 | return $self->cursor_sth->execute(@bind_values); |
71 | } |
72 | |
73 | # bind_param_array & execute_array not used for SELECT statements, so |
74 | # we'll ignore them |
75 | |
76 | sub errstr { |
77 | my ($self)=@_; |
78 | |
79 | return $self->cursor_sth->errstr; |
80 | } |
81 | |
82 | sub finish { |
83 | my ($self)=@_; |
84 | |
85 | $self->fetch_sth->finish if $self->fetch_sth; |
86 | return $self->cursor_sth->finish if $self->cursor_sth; |
87 | return 0; |
88 | } |
89 | |
90 | sub _check_cursor_end { |
91 | my ($self) = @_; |
92 | |
93 | if ($self->fetch_sth->rows == 0) { |
94 | $self->_cleanup_sth; |
95 | return 1; |
96 | } |
97 | return; |
98 | } |
99 | |
100 | sub _run_fetch_sth { |
101 | my ($self)=@_; |
102 | |
103 | if (!$self->cursor_created) { |
104 | $self->cursor_sth->execute(); |
105 | } |
106 | |
107 | $self->fetch_sth->finish if $self->fetch_sth; |
108 | $self->fetch_sth($self->storage->sth("fetch 1000 from ".$self->cursor_id)); |
109 | $self->fetch_sth->execute; |
110 | } |
111 | |
112 | sub fetchrow_array { |
113 | my ($self) = @_; |
114 | |
115 | $self->_run_fetch_sth unless $self->fetch_sth; |
116 | return if $self->_check_cursor_end; |
117 | |
118 | my @row = $self->fetch_sth->fetchrow_array; |
119 | if (!@row) { |
120 | $self->_run_fetch_sth; |
121 | return if $self->_check_cursor_end; |
122 | |
123 | @row = $self->fetch_sth->fetchrow_array; |
124 | } |
125 | return @row; |
126 | } |
127 | |
128 | sub fetchall_arrayref { |
129 | my ($self,$slice,$max_rows) = @_; |
130 | |
131 | my $ret=[]; |
132 | $self->_run_fetch_sth unless $self->fetch_sth; |
133 | return if $self->_check_cursor_end; |
134 | |
135 | while (1) { |
136 | my $batch=$self->fetch_sth->fetchall_arrayref($slice,$max_rows); |
137 | |
138 | push @$ret,@$batch; |
139 | |
140 | if (defined($max_rows) && $max_rows >=0) { |
141 | $max_rows -= @$batch; |
142 | last if $max_rows <=0; |
143 | } |
144 | |
145 | last if @$batch ==0; |
146 | |
147 | $self->_run_fetch_sth; |
148 | last if $self->_check_cursor_end; |
149 | } |
150 | |
151 | return $ret; |
152 | } |
153 | |
154 | 1; |