Skip to content

Commit

Permalink
Use newer mysql_exec_statement API whenever possible
Browse files Browse the repository at this point in the history
There are a very small number of statements which fail under this API, such as LOCK TABLE. In nearly every other case it provides an improved interface for correctness. For consistency in things like NULL handling, which are tricky to fully test otherwise, always try this API and fallback if it fails with the specific 'This command is not supported in the prepared statement protocol yet' message.
  • Loading branch information
rbt committed Apr 8, 2022
1 parent a15ff9d commit fef8b69
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 12 deletions.
32 changes: 21 additions & 11 deletions lib/DBDish/mysql/Connection.pm6
Expand Up @@ -29,12 +29,12 @@ method prepare(Str $statement, *%args) {
self.protect-connection: {
with $!mysql-client.mysql_stmt_init -> $stmt {
with self!handle-errors(
$stmt.mysql_stmt_prepare($statement, $statement.encode.bytes)
) {
$stmt.mysql_stmt_prepare($statement, $statement.encode.bytes)
) {
DBDish::mysql::StatementHandle.new(
:$!mysql-client, :parent(self), :$stmt
:$statement, :$!RaiseError, |%args
);
:$!mysql-client, :parent(self), :$stmt
:$statement, :$!RaiseError, |%args
);
} else { .fail }
} else {
self!set-err(-1, "Can't allocate memory");
Expand All @@ -44,15 +44,25 @@ method prepare(Str $statement, *%args) {

# Override DBIish::Connection.execute as statements such as LOCK TABLE cannot
# be prepared in MySQL.
# Avoid looking into the query string by using a simple parameter count
# and skipping the prepare step for queries without parameters.
method execute(Str $statement, **@params, *%args) {
if @params.elems == 0 {
return DBDish::mysql::StatementHandle.new(
:$!mysql-client, :parent(self), :$statement, :$!RaiseError, |%args).execute;
} else {
try {
# Copied from the DBIish::Connection.execute
return self.prepare($statement, |%args).execute(|@params);

# A small number of statements cannot be executed using prepare/execute. Handle these
# by calling the older protocol. We try very hard to use the newer protocol first as
# it has several bug and minor behaviour fixes such as the handling of NULLs.
CATCH {
when X::DBDish::DBError {
when $_.code == 1 and $_.native-message eq 'This command is not supported in the prepared statement protocol yet' {
return DBDish::mysql::StatementHandle.new(
:$!mysql-client, :parent(self), :$statement, :$!RaiseError, |%args).execute;
}
default {
.rethrow;
}
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/DBDish/mysql/StatementHandle.pm6
Expand Up @@ -141,7 +141,7 @@ method execute(*@params --> DBDish::StatementHandle) {
}
without self!handle-errors { .fail }
}
else { # Unprepared path
else { # Unprepared path, seldome used.
$!parent.protect-connection: {
my $status = $!mysql-client.mysql_query($!statement)
and self!set-err($status, $!mysql-client.mysql_error).fail;
Expand Down

0 comments on commit fef8b69

Please sign in to comment.