File Coverage

blib/lib/MonetDB/CLI/MapiPP.pm
Criterion Covered Total %
statement 14 104 13.4
branch 1 58 1.7
condition 0 12 0.0
subroutine 5 21 23.8
pod 0 2 0.0
total 20 197 10.1


line stmt bran cond sub pod time code
1             package MonetDB::CLI::MapiPP;
2              
3 3     3   80656 use IO::Socket::INET();
  3         89090  
  3         76  
4 3     3   2996 use Text::ParseWords();
  3         4532  
  3         66  
5 3     3   21 use strict;
  3         10  
  3         86  
6 3     3   16 use warnings;
  3         6  
  3         5868  
7              
8             our $VERSION = '0.03';
9              
10              
11             my %unescape = ( n => "\n", t => "\t", r => "\r", f => "\f");
12              
13             sub unquote
14             {
15 0     0 0 0 my ($class, $v) = @_;
16              
17 0 0 0     0 return undef if $v eq 'NULL' || $v eq 'nil';
18              
19 0 0       0 if ( $v =~ /^["']/) {
20 0         0 $v =~ s/^["']//;
21 0         0 $v =~ s/["']$//;
22 0 0       0 $v =~ s/\\(.)/$unescape{$1}||$1/eg;
  0         0  
23             }
24 0         0 return $v;
25             }
26              
27              
28             sub connect
29             {
30 2     2 0 1624 my ($class, $host, $port, $user, $pass, $lang) = @_;
31              
32 2 50       26 my $h = IO::Socket::INET->new( PeerAddr => $host, PeerPort => $port )
33             or die "Handle is undefined: $@";
34 0           <$h>;
35 0 0         print $h "$user:$pass:$lang:line\n" or die $!;
36 0           while ( local $_ = <$h> ) {
37 0 0         last if /^\001/;
38             }
39 0           bless { h => $h, lang => $lang },'MonetDB::CLI::MapiPP::Cxn';
40             }
41              
42              
43             package MonetDB::CLI::MapiPP::Cxn;
44              
45             sub query
46             {
47 0     0     my ($self, $statement) = @_;
48              
49 0           my $h = $self->new_handle;
50 0           $h->query( $statement );
51              
52 0           return $h;
53             }
54              
55             sub new_handle
56             {
57 0     0     my ($self) = @_;
58              
59 0           bless { p => $self },'MonetDB::CLI::MapiPP::Req';
60             }
61              
62             sub DESTROY
63             {
64 0     0     my ($self) = @_;
65              
66 0           $self->{h}->close;
67              
68 0           return;
69             }
70              
71              
72             package MonetDB::CLI::MapiPP::Req;
73              
74             sub query
75             {
76 0     0     my ($self, $statement) = @_;
77              
78 0           my $lang = $self->{p}{lang};
79 0           my $h = $self->{p}{h};
80 0 0         my $delim = $lang eq 'sql' ? qr(\s*,\s*) : qr(\s+);
81 0           my @err;
82              
83 0 0         if ( $lang eq 'sql') {
84 0           my @statement = split /\n/, $statement;
85 0           s/--.*// for @statement; # TODO: -- inside '' (or blocked mode?)
86 0           $statement = join ' ', @statement;
87 0 0         $statement .= ';' unless $statement =~ /;$/;
88 0           $statement = 's' . $statement;
89             }
90             else {
91 0           $statement =~ s/\n/ /g;
92             }
93 0 0         print $h $statement,"\n" or die $!;
94              
95 0           $self->finish;
96              
97 0           while ( local $_ = <$h> ) {
98 0           chomp;
99 0 0         if (/^\[/) {
    0          
    0          
    0          
    0          
    0          
    0          
100 0 0         die "Incomplete tuple: $_" unless /\]$/;
101 0           s/^\[\s*//;
102 0           s/\s*\]$//;
103 0           my @a = Text::ParseWords::parse_line( qr(\s*,\s*), 0, $_ );
104 0           push @{$self->{rs}}, [ map { MonetDB::CLI::MapiPP->unquote( $_ ) } @a ];
  0            
  0            
105             }
106             elsif (/^&(\d) (\d+) (\d+) (\d+)/) {
107 0 0         $self->{querytype} = $1 if $self->{querytype} < 0;
108 0 0         $self->{id} = $2 if $self->{id} < 0;
109 0 0         $self->{tuplecount} = $3 if $self->{tuplecount} < 0;
110 0 0         $self->{columncount} = $4 if $self->{columncount} < 0;
111             }
112             elsif (/^&(\d) (\d+)/) {
113 0 0         $self->{querytype} = $1 if $self->{querytype} < 0;
114 0 0         $self->{tuplecount} = $2 if $self->{tuplecount} < 0;
115             }
116             elsif (/^#\s+\b(.*)\b\s+# (name|type|length)$/) {
117 0           $self->{$2} = [ split $delim, $1 ];
118             }
119             elsif (/^!/) {
120 0           push @err, $_;
121             }
122             elsif (/^\001\001/) {
123 0           last;
124             }
125             elsif (/^\001\002/) {
126 0           die "Incomplete query: $statement";
127             }
128             }
129 0 0         $self->{columncount} = @{$self->{name}} if $self->{columncount} < 0;;
  0            
130 0 0 0       $self->{columncount} ||= @{$self->{rs}[0]} if $self->{rs}[0];
  0            
131 0 0         $self->{tuplecount} = @{$self->{rs}} if $lang ne 'sql';
  0            
132              
133 0 0         die join "\n", @err if @err;
134              
135 0           return;
136             }
137              
138             sub querytype
139             {
140 0     0     my ($self) = @_;
141              
142 0           return $self->{querytype};
143             }
144              
145             sub id
146             {
147 0     0     my ($self) = @_;
148              
149 0           return $self->{id};
150             }
151              
152             sub rows_affected
153             {
154 0     0     my ($self) = @_;
155              
156 0           return $self->{tuplecount};
157             }
158              
159             sub columncount
160             {
161 0     0     my ($self) = @_;
162              
163 0           return $self->{columncount};
164             }
165              
166             sub name
167             {
168 0     0     my ($self, $fnr) = @_;
169              
170 0   0       return $self->{name}[$fnr] || '';
171             }
172              
173             sub type
174             {
175 0     0     my ($self, $fnr) = @_;
176              
177 0   0       return $self->{type}[$fnr] || '';
178             }
179              
180             sub length
181             {
182 0     0     my ($self, $fnr) = @_;
183              
184 0   0       return $self->{length}[$fnr] || 0;
185             }
186              
187             sub fetch
188             {
189 0     0     my ($self) = @_;
190              
191 0 0         return if ++$self->{i} > $#{$self->{rs}};
  0            
192 0           return $self->{columncount};
193             }
194              
195             sub field
196             {
197 0     0     my ($self, $fnr) = @_;
198              
199 0           return $self->{rs}[$self->{i}][$fnr];
200             }
201              
202             sub finish
203             {
204 0     0     my ($self) = @_;
205              
206 0           $self->{$_} = -1 for qw(querytype id tuplecount columncount i);
207 0           $self->{$_} = [] for qw(rs name type length);
208              
209 0           return;
210             }
211              
212             sub DESTROY
213             {
214 0     0     my ($self) = @_;
215              
216 0           return;
217             }
218              
219             __PACKAGE__;
220              
221             =head1 NAME
222              
223             MonetDB::CLI::MapiPP - MonetDB::CLI implementation, using the Mapi protocol
224              
225             =head1 DESCRIPTION
226              
227             MonetDB::CLI::MapiPP is an implementation of the MonetDB call level interface
228             L.
229             It's a Pure Perl module.
230             It uses the Mapi protocol - a text based communication layer on top of TCP.
231             Normally, you don't use this module directly, but let L
232             choose an implementation module.
233              
234             =head1 AUTHORS
235              
236             Steffen Goeldner Esgoeldner@cpan.orgE.
237              
238             =head1 COPYRIGHT AND LICENCE
239              
240             The contents of this file are subject to the MonetDB Public License
241             Version 1.1 (the "License"); you may not use this file except in
242             compliance with the License. You may obtain a copy of the License at
243             http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html
244              
245             Software distributed under the License is distributed on an "AS IS"
246             basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
247             License for the specific language governing rights and limitations
248             under the License.
249              
250             The Original Code is the MonetDB Database System.
251              
252             The Initial Developer of the Original Code is CWI.
253             Portions created by CWI are Copyright (C) 1997-2006 CWI.
254             All Rights Reserved.
255              
256             =head1 SEE ALSO
257              
258             =head2 MonetDB
259              
260             Homepage : http://monetdb.cwi.nl
261             SourceForge : http://sourceforge.net/projects/monetdb
262              
263             =head2 Perl modules
264              
265             L
266              
267             =cut