view release on metacpan or search on metacpan
lib/Net/Wire10.pm view on Meta::CPAN
my $self = shift;
my $sql = shift;
return Net::Wire10::PreparedStatement->new($self, $sql);
}
# Sends a wire protocol ping
sub ping {
my $self = shift;
$self->_check_streaming;
$self->_check_connected;
$self->_reset_command_state;
$self->_reset_timeout($self->{connect_timeout});
return $self->_execute_command(COMMAND_PING, '', undef);
}
# Close the database connection
sub disconnect {
my $self = shift;
lib/Net/Wire10.pm view on Meta::CPAN
$self->_fatal_error("Timeout while receiving data") if $remaining < 1;
return $remaining;
}
# Fail if not connected anymore, due for example to a fatal error
sub _check_connected {
my $self = shift;
$self->_fatal_error("Not connected") unless defined($self->{socket});
}
# Fail if currently connected to a streaming data reader
sub _check_streaming {
my $self = shift;
$self->_vanilla_error("Connection is busy streaming") if $self->{streaming};
}
# Connects to the database server
sub _connect {
my $self = shift;
$self->_vanilla_error("Already connected") if defined($self->{socket});
$self->_fatal_error("No host given") if length($self->{host}) == 0;
$self->_fatal_error("No port given") if length($self->{port}) == 0;
lib/Net/Wire10.pm view on Meta::CPAN
) . "\0";
$self->_send_mackets($body, 3, MACKET_AUTHENTICATE);
}
# Execute a SQL command
sub _execute_query {
my $self = shift;
my $sql = shift;
my $wantstream = shift;
$self->_check_streaming;
$self->_check_connected;
$self->_reset_command_state;
$self->_reset_timeout($self->{query_timeout});
$self->{streaming} = 1 if $wantstream;
my $iterator = Net::Wire10::Results->new($self);
$self->{streaming_iterator} = $iterator if $wantstream;
# The protocol is configured to always use UTF-8 during handskake, to
# avoid messing with all the local character sets. Therefore any input
# string needs to be automatically converted if it is not already UTF-8.
utf8::upgrade($sql) if defined($sql) and not utf8::is_utf8($sql);
printf "Executing query: %s%s\n", substr($sql, 0, 100), length($sql) >= 100 ? " ..." : "" if $self->{debug} & 1;
$self->_execute_command(COMMAND_QUERY, $sql, $iterator);
return $iterator;
lib/Net/Wire10.pm view on Meta::CPAN
if ($macket->{type} == MACKET_ERROR) {
$self->_detach_results($iterator);
$self->_parse_error_macket($macket);
$self->_vanilla_error;
}
if ($macket->{type} == MACKET_RESULT_SET_HEADER) {
my $pos = MACKET_HEADER_LENGTH;
$self->_parse_result_set_header_macket($macket, \$pos);
$self->_retrieve_column_info($iterator);
$self->_retrieve_results($iterator) unless $self->{streaming};
}
if ($macket->{type} == MACKET_OK) {
$self->_parse_ok_macket($macket, $iterator);
$self->_detach_results($iterator);
}
}
# Reads and interprets result set header
sub _parse_result_set_header_macket {
my $self = shift;
lib/Net/Wire10.pm view on Meta::CPAN
$self->_detach_results($iterator);
# No more data available.
return 0;
}
}
# Disconnect result set from driver, must only be done after all results have been read
sub _detach_results {
my $self = shift;
my $iterator = shift;
$iterator->{wire}->{streaming_iterator} = undef;
$iterator->{wire}->{streaming} = 0;
$iterator->{wire} = undef;
}
# Reads and interprets OK, saving the number of affected rows,
# the insert id, and the server message. Returns the number of
# affected rows
sub _parse_ok_macket {
my $self = shift;
my $macket = shift;
my $iterator = shift;
lib/Net/Wire10.pm view on Meta::CPAN
my $result = eval {
return Net::Wire10::Util::decode_string($buf, $pos);
};
$self->_fatal_error($@) if $@;
return $result;
}
# Resets the command execution status
sub _reset_command_state {
my $self = shift;
# Disconnect streaming iterator.
$self->_detach_results($self->{streaming_iterator}) if defined($self->{streaming_iterator});
# Reset internal column counter.
$self->{no_of_columns} = undef;
# Reset error state.
$self->{error} = undef;
# Reset cancel flag.
$self->{cancelling} = 0;
}
# Reset entire connection
sub _reset_connection_state {
lib/Net/Wire10.pm view on Meta::CPAN
my @result;
my $row;
my $wire = $self->{wire};
# Note: A die() from this context often brings an application down.
# For disconnected result sets, row data could be integrity
# checked during query() to simplify error handling for
# applications.
if (defined($wire)) {
# In streaming mode, fetch a row
return undef unless $wire->_retrieve_row_data($self);
}
# Return unless there is another row available
return undef if scalar(@{$self->{row_data}}) == 0;
$row = shift(@{$self->{row_data}});
my $pos = 0;
for (my $i = 1; $i <= scalar(@{$self->{column_info}}); $i++) {
my $fieldvalue = eval {
lib/Net/Wire10.pm view on Meta::CPAN
return $wire->stream($prepared) if $wantstream;
return $wire->query($prepared);
}
# Run the prepared statement and spool results.
sub query {
my $self = shift;
return $self->_execute(0);
}
# Run the prepared statement and return a result object for streaming.
sub stream {
my $self = shift;
return $self->_execute(1);
}
package Net::Wire10::Error;
use strict;
lib/Net/Wire10.pm view on Meta::CPAN
Use query() when a small amount of records is needed for use at an arbitrary later point in time. If you want to stream data to a live result set, including large amounts of data, see stream().
=head3 stream
The stream() method transmits the specified SQL string to the server, and obtains initial information about the response, but does not begin downloading data.
A result set is returned. The obtained result set will be live with the driver. After retrieving the result set, you must traverse all of its rows before you can fire another query.
Use stream() for large result sets, as it has a smaller memory footprint compared to query(). If you want to download data to a disconnected result set, use query().
Note that stream() will lock the driver until the whole result set has been retrieved. To fetch another set of results while streaming to a live result set, create another driver object.
Also note that if you are using MySQL with the default storage engine, MyISAM, the entire table on the server will be locked for the duration of the live result set, that is until all rows have been retrieved.
=head3 prepare
Given a SQL string, returns a prepared statement.
Prepared statements are useful for:
=over 4
lib/Net/Wire10.pm view on Meta::CPAN
Returns the number of "?" tokens found in the SQL initially used to create the prepared statement.
=head3 query
Execute the prepared statement using the parameters previously set with set_parameter().
All results are spooled before the call returns.
=head3 stream
Execute the prepared statement using the parameters previously set with set_parameter().
As soon as the initial metadata arrives from the database server, the call returns, and the results can be traversed in a streaming fashion.
=head2 Features in the I<Net::Wire10::Results> iterator
A Net::Wire10::Results object is returned when calling query() or stream(). Depending on which was used to execute the SQL, either a disconnected result set or a live (streaming) result set is returned.
=head3 next_array
The next_array() method returns a whole row, with individual field values packed into an array.
C<undef> is returned once all rows has been extracted.
while (my $row = $results->next_array) {
printf
"Value 1: %s Value 2: %s Value 3: %s\n",
$row->[0],
lib/Net/Wire10.pm view on Meta::CPAN
$row->{name},
$row->{data};
}
Using next_hash() instead of next_array() usually makes the code a bit more readable, especially in cases where a SELECT with column names is not nearby.
After calling next_hash(), the row has been consumed. There is currently no way to rewind and re-read a row, even for a disconnected result set.
=head3 spool
Reads the remaining rows of the result set, in effect turning a streaming result set into a disconnected result set.
=head3 flush
Reads the remaining rows of the result set and discards them. When done on a live result set, this frees the driver for use.
=head3 get_column_info
Return the names and other information of the result set's columns as an array.
If you want all information, call get_column_info with no parameters:
lib/Net/Wire10.pm view on Meta::CPAN
my $affected = $wire->get_no_of_affected_rows;
=head3 get_no_of_selected_rows
Returns the number of rows in the result set of a SELECT or similar query.
my $selected = $wire->get_no_of_selected_rows;
After consuming a row, the number of available rows will decrease, and get_no_of_selected_rows() will return one less.
Supported only for disconnected result sets, live/streaming result sets are unaware of the total number of records. A streaming result set can be turned into a disconnected result set using spool(), after which the number of available rows becomes k...
=head3 get_insert_id
MySQL and Drizzle has the ability to choose unique key values automatically, by enabling auto_increment for a column. When this happens, the newly assigned id value for the last inserted row is stored in this attribute.
=head3 get_warning_count
After a query, this returns the number of warnings generated on the server. If the query is streaming to a live result set, an additional warning count is available after the last row of data has been read.
=head2 Features in the I<Net::Wire10::Error> object
After an error has occurred, call $wire->C<get_error_info()> to retrieve an Error object containing details of the problem.
=head3 get_error_code
Returns the server-reported (1xxx) error code, or a client (2xxx) error code.
=head3 get_error_state
lib/Net/Wire10.pm view on Meta::CPAN
A detail in the protocol specification is that results from non-prepared statements are pushed to the client, whereas results from prepared statements are pulled by the client. The pull mechanism makes it possible to stop in the middle of a result s...
Another, related detail in the protocol specification is that prepared statements are assigned a number each, whereas non-prepared statements are not. Multiple prepared statements can therefore be active, running over the same connection at the same...
In short, protocol-level prepared statements would be very nice to have, but are currently not implemented. Protocol details are described in the manual, but with gaps in the documentation.
There is also a purely SQL-driven interface to prepared statements, using the PREPARE, EXECUTE and DEALLOCATE PREPARE commands. The SQL-driven interface does not have the same performance benefits as the protocol-level one does. It can however be u...
There is also a client-side prepared statement interface in the driver, which it is highly recommended to use.
=head3 High-granularity streaming
Streaming data along the way as it is consumed or delivered by the client application can lead to dramatical decreases in memory usage.
Streaming outgoing data can be accomplished with server-side prepared statements, because the wire protocol allows prepared statement parameters to be sent one at a time, and even in chunks. Chunking data presumably allows you to interleave data to ...
The driver API currently allows client applications to stream incoming data one row at a time. The highest supported granularity for streaming is one whole row at a time. Streaming at a higher granularity and interleaving chunks of incoming data is...
Streaming incoming data in a row-by-row fashion is also known in some drivers as "use_result mode".
=head3 Server-side cursors
Cursors provide a way of keeping open, navigating and optionally modifying a result set on the server, rather than having to transfer the entire result set to the client.
MySQL Server supports only a particular class of cursors known as read-only, forward-only cursors. As the name implies, this kind of cursor cannot be navigated (also called "scrolled") or modified.
The semantics are exactly the same as when streaming incoming data with the L<stream>() call. With cursors however, the server automatically creates a temporary table behind the scenes from which the data is read, thereby always using extra resource...
There is also a purely SQL-driven interface to cursors, which can be useful inside stored procedures.
Server-side cursors are part of the prepared statement protocol features (see above), and are therefore currently not supported.
=head3 Multiple statements per query
Currently unsupported. Multiple statements can often cause more trouble than gain by making SQL injection (a security risk) much easier and in return providing diminutive performance gains when compared to other approaches.
If you want to run multiple queries, one method is to create two separate connections. This can also give a performance boost, because one query does not wait for the other to finish. Another related advantage is that multi-core servers can actuall...