NAME

DBIO::Exception::Server - A refusal by the database server, with its SQLSTATE

VERSION

version 0.900004

DESCRIPTION

The error an async transport fails a Future with when the server refused a statement: a unique violation, a deadlock, a serialization failure, a cancelled statement. It is a DBIO::Exception that also carries what the server said in machine-readable form, so a caller tells 40001, 40P01, 23505 and 57014 apart without parsing text -- text that depends on the server's lc_messages.

It stringifies to the message it was built with, exactly the text the Future failed with before a transport made these objects, and compares as that string: $@ =~ /.../, eq and like keep working.

my $f = $storage->insert_async($source, \%row);
$f->catch(sub {
  my ($error) = @_;
  if (Scalar::Util::blessed($error)
      && $error->isa('DBIO::Exception::Server')
      && ($error->sqlstate // '') eq '23505') {
    ...
  }
});

Core hands such an object on unchanged -- the one the transport failed with, not a copy -- through txn_do_async and pipeline ("WHAT A TRANSPORT FAILS WITH" in DBIO::Future, ADR 0062). Where core puts text in front of it -- a failed BEGIN, COMMIT or ROLLBACK of a transaction -- the caller gets a derived copy of the same class and fields with "context" set, stringifying with that prefix.

The synchronous path raises it too: a statement the DBI handle refused is a DBIO::Exception::Server from DBIO::Storage::DBI, its text the decorated DBI Exception: ... it always was, its sqlstate the handle's state. Every field is undef where the handle gave none.

METHODS

new

my $error = DBIO::Exception::Server->new(
  message    => qq{ERROR:  duplicate key value ...\n},
  sqlstate   => '23505',
  constraint => 'artist_name_key',
  table      => 'artist',
  detail     => 'Key (name)=(Duplicate) already exists.',
);

message is required and is the text the object stringifies to; core does not add to it (no caller, no newline). The other fields (context too, which core sets on a derived copy -- see "with_context") are optional and undef when the server did not report them. Unknown arguments are refused.

throw

DBIO::Exception::Server->throw(message => ..., sqlstate => ...);

new and die, for code that raises it synchronously. Takes the arguments of "new"; unlike "throw" in DBIO::Exception it does not decorate the message with the caller.

sqlstate

The five-character SQLSTATE the server reported (23505), or undef.

constraint

The name of the constraint the statement violated, or undef.

table

The name of the table the error concerns, or undef.

detail

The server's detail line (PostgreSQL DETAIL), or undef.

context

What core was doing when it prefixed the message: BEGIN, COMMIT or ROLLBACK for the failure of that step of a transaction, or undef -- the object is the one the server's refusal made, with no step of core's in front of it. It is set on the derived copy core hands the caller, never on the object a transport failed with.

with_context

my $copy = $error->with_context('COMMIT', "COMMIT failed: $error");

A derived copy: same class (a subclass stays itself), sqlstate, constraint, table and detail unchanged, context set, and -- when $message is given -- the text it stringifies to replaced. The original is not touched. Throws a DBIO::Exception for an empty context or a false message.

AUTHOR

DBIO & DBIx::Class Authors

COPYRIGHT AND LICENSE

Copyright (C) 2026 DBIO Authors Portions Copyright (C) 2005-2025 DBIx::Class Authors Based on DBIx::Class, heavily modified.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.