line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
17
|
|
|
17
|
|
284
|
use 5.010; |
|
17
|
|
|
|
|
49
|
|
2
|
17
|
|
|
17
|
|
99
|
use strict; |
|
17
|
|
|
|
|
28
|
|
|
17
|
|
|
|
|
361
|
|
3
|
17
|
|
|
17
|
|
96
|
use warnings; |
|
17
|
|
|
|
|
31
|
|
|
17
|
|
|
|
|
457
|
|
4
|
17
|
|
|
17
|
|
83
|
use utf8; |
|
17
|
|
|
|
|
35
|
|
|
17
|
|
|
|
|
70
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package Neo4j::Driver::Net::Bolt; |
7
|
|
|
|
|
|
|
# ABSTRACT: Network controller for Neo4j Bolt |
8
|
|
|
|
|
|
|
$Neo4j::Driver::Net::Bolt::VERSION = '0.40'; |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
# This package is not part of the public Neo4j::Driver API. |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
13
|
17
|
|
|
17
|
|
1047
|
use Carp qw(croak); |
|
17
|
|
|
|
|
37
|
|
|
17
|
|
|
|
|
1306
|
|
14
|
|
|
|
|
|
|
our @CARP_NOT = qw(Neo4j::Driver::Transaction Neo4j::Driver::Transaction::Bolt); |
15
|
|
|
|
|
|
|
|
16
|
17
|
|
|
17
|
|
109
|
use Try::Tiny; |
|
17
|
|
|
|
|
46
|
|
|
17
|
|
|
|
|
1140
|
|
17
|
17
|
|
|
17
|
|
133
|
use URI 1.25; |
|
17
|
|
|
|
|
318
|
|
|
17
|
|
|
|
|
455
|
|
18
|
|
|
|
|
|
|
|
19
|
17
|
|
|
17
|
|
6643
|
use Neo4j::Driver::Result::Bolt; |
|
17
|
|
|
|
|
42
|
|
|
17
|
|
|
|
|
574
|
|
20
|
17
|
|
|
17
|
|
6448
|
use Neo4j::Driver::ServerInfo; |
|
17
|
|
|
|
|
35
|
|
|
17
|
|
|
|
|
487
|
|
21
|
17
|
|
|
17
|
|
8731
|
use Neo4j::Error; |
|
17
|
|
|
|
|
45911
|
|
|
17
|
|
|
|
|
23953
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# Neo4j::Bolt < 0.10 didn't report human-readable error messages |
25
|
|
|
|
|
|
|
# (perlbolt#24), so we re-create the most common ones here |
26
|
|
|
|
|
|
|
my %BOLT_ERROR = ( |
27
|
|
|
|
|
|
|
61 => "Connection refused", |
28
|
|
|
|
|
|
|
-13 => "Unknown host", |
29
|
|
|
|
|
|
|
-14 => "Could not agree on a protocol version", |
30
|
|
|
|
|
|
|
-15 => "Username or password is invalid", |
31
|
|
|
|
|
|
|
-22 => "Statement evaluation failed", |
32
|
|
|
|
|
|
|
); |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
my $RESULT_MODULE = 'Neo4j::Driver::Result::Bolt'; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
sub new { |
38
|
|
|
|
|
|
|
# uncoverable pod |
39
|
13
|
|
|
13
|
0
|
35
|
my ($class, $driver) = @_; |
40
|
|
|
|
|
|
|
|
41
|
13
|
100
|
|
|
|
33
|
croak "Concurrent transactions are unsupported in Bolt; use multiple sessions" if $driver->config('concurrent_tx'); |
42
|
|
|
|
|
|
|
|
43
|
12
|
|
|
|
|
40
|
my $uri = $driver->config('uri'); |
44
|
12
|
100
|
|
|
|
100
|
if (my $auth = $driver->config('auth')) { |
45
|
6
|
100
|
|
|
|
60
|
croak "Only Basic Authentication is supported" if $auth->{scheme} ne 'basic'; |
46
|
5
|
|
|
|
|
20
|
$uri = $uri->clone; |
47
|
5
|
|
|
|
|
54
|
$uri->userinfo( $auth->{principal} . ':' . $auth->{credentials} ); |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
11
|
|
100
|
|
|
314
|
my $net_module = $driver->config('net_module') || 'Neo4j::Bolt'; |
51
|
11
|
100
|
|
|
|
51
|
if ($net_module eq 'Neo4j::Bolt') { |
52
|
|
|
|
|
|
|
croak "Protocol scheme 'bolt' is not supported (Neo4j::Bolt not installed)\n" |
53
|
|
|
|
|
|
|
. "Neo4j::Driver will support 'bolt' URLs if the Neo4j::Bolt module is installed.\n" |
54
|
1
|
50
|
|
|
|
3
|
unless eval { require Neo4j::Bolt; 1 }; |
|
1
|
|
|
|
|
276
|
|
|
0
|
|
|
|
|
0
|
|
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
10
|
|
|
|
|
16
|
my $cxn; |
58
|
10
|
100
|
|
|
|
21
|
if ($driver->config('encrypted')) { |
59
|
1
|
|
|
|
|
8
|
$cxn = $net_module->connect_tls("$uri", { |
60
|
|
|
|
|
|
|
timeout => $driver->config('timeout'), |
61
|
|
|
|
|
|
|
ca_file => $driver->config('trust_ca'), |
62
|
|
|
|
|
|
|
}); |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
else { |
65
|
9
|
|
|
|
|
37
|
$cxn = $net_module->connect( "$uri", $driver->config('timeout') ); |
66
|
|
|
|
|
|
|
} |
67
|
10
|
100
|
|
|
|
93
|
$class->_trigger_bolt_error( $cxn, $driver->{plugins} ) unless $cxn->connected; |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
return bless { |
70
|
|
|
|
|
|
|
net_module => $net_module, |
71
|
|
|
|
|
|
|
connection => $cxn, |
72
|
|
|
|
|
|
|
uri => $uri, |
73
|
|
|
|
|
|
|
result_module => $net_module->can('result_handlers') ? ($net_module->result_handlers)[0] : $RESULT_MODULE, |
74
|
|
|
|
|
|
|
server_info => $driver->{server_info}, |
75
|
9
|
100
|
|
|
|
103
|
cypher_types => $driver->config('cypher_types'), |
76
|
|
|
|
|
|
|
active_tx => 0, |
77
|
|
|
|
|
|
|
}, $class; |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# Trigger an error using the given event handler. |
82
|
|
|
|
|
|
|
# Meant to only be called after a failure has occurred. |
83
|
|
|
|
|
|
|
# May also be called as class method. |
84
|
|
|
|
|
|
|
# $ref may be a Neo4j::Bolt ResultStream, Cxn, Txn. |
85
|
|
|
|
|
|
|
# $error_handler may be a coderef or the event manager. |
86
|
|
|
|
|
|
|
sub _trigger_bolt_error { |
87
|
13
|
|
|
13
|
|
13978
|
my ($self, $ref, $error_handler, $connection) = @_; |
88
|
13
|
|
|
|
|
20
|
my $error = 'Neo4j::Error'; |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
$error = $error->append_new( Server => { |
91
|
|
|
|
|
|
|
code => scalar $ref->server_errcode, |
92
|
|
|
|
|
|
|
message => scalar $ref->server_errmsg, |
93
|
5
|
|
|
5
|
|
393
|
raw => scalar try { $ref->get_failure_details }, # Neo4j::Bolt >= 0.41 |
94
|
13
|
100
|
|
13
|
|
65
|
}) if try { $ref->server_errcode || $ref->server_errmsg }; |
|
13
|
100
|
|
|
|
603
|
|
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
$error = $error->append_new( Network => { |
97
|
|
|
|
|
|
|
code => scalar $ref->client_errnum, |
98
|
|
|
|
|
|
|
message => scalar $ref->client_errmsg // $BOLT_ERROR{$ref->client_errnum}, |
99
|
|
|
|
|
|
|
as_string => $self->_bolt_error($ref), |
100
|
13
|
100
|
66
|
13
|
|
11994
|
}) if try { $ref->client_errnum || $ref->client_errmsg }; |
|
13
|
100
|
|
|
|
564
|
|
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
$error = $error->append_new( Network => { |
103
|
|
|
|
|
|
|
code => scalar $ref->errnum, |
104
|
|
|
|
|
|
|
message => scalar $ref->errmsg // $BOLT_ERROR{$ref->errnum}, |
105
|
|
|
|
|
|
|
as_string => $self->_bolt_error($ref), |
106
|
13
|
100
|
100
|
13
|
|
3809
|
}) if try { $ref->errnum || $ref->errmsg }; |
|
13
|
100
|
|
|
|
507
|
|
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
try { |
109
|
13
|
|
66
|
13
|
|
665
|
my $cxn = $connection // $self->{connection}; |
110
|
|
|
|
|
|
|
$error = $error->append_new( Network => { |
111
|
|
|
|
|
|
|
code => scalar $cxn->errnum, |
112
|
|
|
|
|
|
|
message => scalar $cxn->errmsg // $BOLT_ERROR{$cxn->errnum}, |
113
|
|
|
|
|
|
|
as_string => $self->_bolt_error($cxn), |
114
|
6
|
100
|
33
|
|
|
24
|
}) if try { $cxn->errnum || $cxn->errmsg } && $cxn != $ref; |
|
6
|
100
|
100
|
|
|
260
|
|
115
|
6
|
|
|
|
|
771
|
$cxn->reset_cxn; |
116
|
|
|
|
|
|
|
$error = $error->append_new( Internal => { # perlbolt#51 |
117
|
|
|
|
|
|
|
code => scalar $cxn->errnum, |
118
|
|
|
|
|
|
|
message => scalar $cxn->errmsg // $BOLT_ERROR{$cxn->errnum}, |
119
|
|
|
|
|
|
|
as_string => $self->_bolt_error($cxn), |
120
|
6
|
100
|
66
|
|
|
43
|
}) if try { $cxn->errnum || $cxn->errmsg }; |
|
6
|
100
|
|
|
|
251
|
|
121
|
13
|
|
|
|
|
6837
|
}; |
122
|
|
|
|
|
|
|
|
123
|
13
|
100
|
|
|
|
5084
|
return $error_handler->($error) if ref $error_handler eq 'CODE'; |
124
|
1
|
|
|
|
|
5
|
$error_handler->trigger(error => $error); |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub _bolt_error { |
129
|
15
|
|
|
15
|
|
3045
|
my (undef, $ref) = @_; |
130
|
|
|
|
|
|
|
|
131
|
15
|
|
|
|
|
24
|
my ($errnum, $errmsg); |
132
|
15
|
50
|
|
|
|
78
|
($errnum, $errmsg) = ($ref->errnum, $ref->errmsg) if $ref->can('errnum'); |
133
|
15
|
100
|
|
|
|
125
|
($errnum, $errmsg) = ($ref->client_errnum, $ref->client_errmsg) if $ref->can('client_errnum'); |
134
|
|
|
|
|
|
|
|
135
|
15
|
|
100
|
|
|
90
|
$errmsg //= $BOLT_ERROR{$errnum}; |
136
|
15
|
100
|
|
|
|
75
|
return "Bolt error $errnum: $errmsg" if $errmsg; |
137
|
8
|
|
|
|
|
44
|
return "Bolt error $errnum"; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
sub _server { |
142
|
9
|
|
|
9
|
|
17
|
my ($self) = @_; |
143
|
|
|
|
|
|
|
|
144
|
9
|
|
|
|
|
19
|
my $cxn = $self->{connection}; |
145
|
|
|
|
|
|
|
return $self->{server_info} = Neo4j::Driver::ServerInfo->new({ |
146
|
|
|
|
|
|
|
uri => $self->{uri}, |
147
|
9
|
100
|
|
|
|
32
|
version => $cxn->server_id, |
148
|
|
|
|
|
|
|
protocol => $cxn->can('protocol_version') ? $cxn->protocol_version : '', |
149
|
|
|
|
|
|
|
}); |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# Update requested database name. |
154
|
|
|
|
|
|
|
sub _set_database { |
155
|
9
|
|
|
9
|
|
18
|
my ($self, $database) = @_; |
156
|
|
|
|
|
|
|
|
157
|
9
|
|
|
|
|
26
|
$self->{database} = $database; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# Send statements to the Neo4j server and return a list of all results. |
162
|
|
|
|
|
|
|
sub _run { |
163
|
13
|
|
|
13
|
|
27
|
my ($self, $tx, @statements) = @_; |
164
|
|
|
|
|
|
|
|
165
|
13
|
100
|
|
|
|
37
|
die "multiple statements not supported for Bolt" if @statements > 1; |
166
|
12
|
|
|
|
|
20
|
my ($statement) = @statements; |
167
|
|
|
|
|
|
|
|
168
|
12
|
|
|
|
|
43
|
my $statement_json = { |
169
|
|
|
|
|
|
|
statement => $statement->[0], |
170
|
|
|
|
|
|
|
parameters => $statement->[1], |
171
|
|
|
|
|
|
|
}; |
172
|
|
|
|
|
|
|
|
173
|
12
|
100
|
|
|
|
33
|
my $query_runner = $tx->{bolt_txn} ? $tx->{bolt_txn} : $self->{connection}; |
174
|
|
|
|
|
|
|
|
175
|
12
|
|
|
|
|
21
|
my ($stream, $result); |
176
|
12
|
100
|
|
|
|
22
|
if ($statement->[0]) { |
177
|
10
|
|
|
|
|
98
|
$stream = $query_runner->run_query( @$statement, $self->{database} ); |
178
|
|
|
|
|
|
|
|
179
|
7
|
100
|
66
|
|
|
82
|
if (! $stream || $stream->failure) { |
180
|
|
|
|
|
|
|
# failure() == -1 is an error condition because run_query_() |
181
|
|
|
|
|
|
|
# always calls update_errstate_rs_obj() |
182
|
|
|
|
|
|
|
|
183
|
2
|
|
|
|
|
9
|
$tx->{closed} = 1; |
184
|
2
|
|
|
|
|
3
|
$self->{active_tx} = 0; |
185
|
2
|
|
|
|
|
6
|
$self->_trigger_bolt_error( $stream, $tx->{error_handler} ); |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
$result = $self->{result_module}->new({ |
189
|
|
|
|
|
|
|
bolt_stream => $stream, |
190
|
|
|
|
|
|
|
bolt_connection => $self->{connection}, |
191
|
|
|
|
|
|
|
statement => $statement_json, |
192
|
|
|
|
|
|
|
cypher_types => $self->{cypher_types}, |
193
|
|
|
|
|
|
|
server_info => $self->{server_info}, |
194
|
|
|
|
|
|
|
error_handler => $tx->{error_handler}, |
195
|
5
|
|
|
|
|
59
|
}); |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
7
|
|
|
|
|
28
|
return ($result); |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
sub _new_tx { |
203
|
11
|
|
|
11
|
|
20
|
my ($self, $driver_tx) = @_; |
204
|
|
|
|
|
|
|
|
205
|
11
|
|
|
|
|
18
|
my $params = {}; |
206
|
11
|
100
|
|
|
|
45
|
$params->{mode} = lc substr $driver_tx->{mode}, 0, 1 if $driver_tx->{mode}; |
207
|
|
|
|
|
|
|
|
208
|
11
|
|
|
|
|
24
|
my $transaction = "$self->{net_module}::Txn"; |
209
|
11
|
100
|
|
|
|
79
|
return unless $transaction->can('new'); |
210
|
10
|
|
|
|
|
47
|
return $transaction->new( $self->{connection}, $params, $self->{database} ); |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
1; |