userver: userver/storages/postgres/exceptions.hpp Source File
Loading...
Searching...
No Matches
exceptions.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/postgres/exceptions.hpp
4/// @brief Postgres errors
5
6#include <optional>
7#include <stdexcept>
8#include <string_view>
9
10#include <fmt/format.h>
11
12#include <userver/storages/postgres/dsn.hpp>
13#include <userver/storages/postgres/io/traits.hpp>
14#include <userver/storages/postgres/message.hpp>
15
16#include <userver/compiler/demangle.hpp>
17#include <userver/utils/underlying_value.hpp>
18
19USERVER_NAMESPACE_BEGIN
20
21namespace storages::postgres {
22
23namespace impl {
24
25// Provides nice to read messages for pattern strings that end on 'type'. For example:
26// fmt::format("Unexpected database type {}", OidPrettyPrint(oid));
27std::string OidPrettyPrint(Oid oid);
28
29} // namespace impl
30
31//@{
32/** @name Generic driver errors */
33
34/// @brief Base class for all exceptions that may be thrown by the driver.
35class Error : public std::runtime_error {
36 using runtime_error::runtime_error;
37};
38
39/// @brief Base Postgres logic error.
40/// Reports errors that are consequences of erroneous driver usage,
41/// such as invalid query syntax, absence of appropriate parsers, out of range
42/// errors etc.
43/// These can be avoided by fixing code.
44class LogicError : public Error {
45 using Error::Error;
46};
47
48/// @brief Base Postgres runtime error.
49/// Reports errors that are consequences of erroneous data, misconfiguration,
50/// network errors etc.
51class RuntimeError : public Error {
52 using Error::Error;
53};
54
55/// @brief Error that was reported by PosgtreSQL server
56/// Contains the message sent by the server.
57/// Templated class because the errors can be both runtime and logic.
58template <typename Base>
59class ServerError : public Base {
60public:
61 explicit ServerError(const Message& msg)
62 : Base(msg.GetMessage()),
63 msg_{msg}
64 {}
65
66 const Message& GetServerMessage() const { return msg_; }
67
68 Message::Severity GetSeverity() const { return msg_.GetSeverity(); }
69 SqlState GetSqlState() const { return msg_.GetSqlState(); }
70
71private:
72 Message msg_;
73};
74
75using ServerLogicError = ServerError<LogicError>;
76using ServerRuntimeError = ServerError<RuntimeError>;
77//@}
78
79//@{
80/** @name Connection errors */
82 using RuntimeError::RuntimeError;
83};
84
85/// @brief Exception is thrown when a single connection fails to connect
87public:
88 explicit ConnectionFailed(const Dsn& dsn);
89 ConnectionFailed(const Dsn& dsn, std::string_view message);
90};
91
92/// @brief Connection error reported by PostgreSQL server.
93/// Doc: https://www.postgresql.org/docs/12/static/errcodes-appendix.html
94/// Class 08 - Connection exception
96 using ServerError::ServerError;
97};
98
99/// @brief Indicates errors during pool operation
100class PoolError : public RuntimeError {
101public:
102 PoolError(std::string_view msg, std::string_view db_name);
103 PoolError(std::string_view msg);
104};
105
107 using ConnectionError::ConnectionError;
108};
109
110/// @brief Error when invoking a libpq function
112 using ConnectionError::ConnectionError;
113};
114
115/// @brief A network operation on a connection has timed out
117 using ConnectionError::ConnectionError;
118};
119
121 using RuntimeError::RuntimeError;
122};
123
124/// @brief An attempt to make a query to server was made while there is another
125/// query in flight.
127 using RuntimeError::RuntimeError;
128};
129
130/// @brief A network operation was interrupted by task cancellation.
132 using RuntimeError::RuntimeError;
133};
134
135//@}
136
137//@{
138/** @name SQL errors */
139//@{
140/** @name Class 03 — SQL Statement Not Yet Complete */
141/// A programming error, a statement is sent before other statement's results
142/// are processed.
143class SqlStatementNotYetComplete : public ServerLogicError {
144 using ServerLogicError::ServerLogicError;
145};
146//@}
147
148//@{
149/** @name Class 09 — Triggered Action Exception */
150class TriggeredActionException : public ServerRuntimeError {
151 using ServerRuntimeError::ServerRuntimeError;
152};
153//@}
154
155//@{
156/** @name Class 0A — Feature Not Supported */
157class FeatureNotSupported : public ServerLogicError {
158 using ServerLogicError::ServerLogicError;
159};
160//@}
161
162//@{
163/** @name Class 0F - Locator Exception */
164class LocatorException : public ServerRuntimeError {
165 using ServerRuntimeError::ServerRuntimeError;
166};
167//@}
168
169//@{
170/** @name Class 0L - Invalid Grantor */
171class InvalidGrantor : public ServerRuntimeError {
172 using ServerRuntimeError::ServerRuntimeError;
173};
174//@}
175
176//@{
177/** @name Class 0P - Invalid Role Specification */
178class InvalidRoleSpecification : public ServerLogicError {
179 using ServerLogicError::ServerLogicError;
180};
181//@}
182
183//@{
184/** @name Class 0Z - Diagnostics Exception */
185class DiagnosticsException : public ServerRuntimeError {
186 using ServerRuntimeError::ServerRuntimeError;
187};
188//@}
189
190//@{
191/** @name Class 21 - Cardinality Violation */
192class CardinalityViolation : public ServerLogicError {
193 using ServerLogicError::ServerLogicError;
194};
195//@}
196
197//@{
198/** @name Class 22 — Data Exception */
199/// @brief Base class for data exceptions
200/// Doc: https://www.postgresql.org/docs/12/static/errcodes-appendix.html
201class DataException : public ServerRuntimeError {
202 using ServerRuntimeError::ServerRuntimeError;
203};
204//@}
205
206//@{
207/** @name Class 23 — Integrity Constraint Violation */
208// TODO Shortcut accessors to respective message fields
209/// @brief Base class for integrity constraint violation errors.
210/// Doc: https://www.postgresql.org/docs/12/static/errcodes-appendix.html
211class IntegrityConstraintViolation : public ServerRuntimeError {
212public:
213 using ServerRuntimeError::ServerRuntimeError;
214
215 std::string GetSchema() const;
216 std::string GetTable() const;
217 std::string GetConstraint() const;
218};
219
221 using IntegrityConstraintViolation::IntegrityConstraintViolation;
222};
223
225 using IntegrityConstraintViolation::IntegrityConstraintViolation;
226};
227
229 using IntegrityConstraintViolation::IntegrityConstraintViolation;
230};
231
233 using IntegrityConstraintViolation::IntegrityConstraintViolation;
234};
235
237 using IntegrityConstraintViolation::IntegrityConstraintViolation;
238};
239
241 using IntegrityConstraintViolation::IntegrityConstraintViolation;
242};
243
244/// Class 27 - Triggered Data Change Violation
246 using IntegrityConstraintViolation::IntegrityConstraintViolation;
247};
248
249/// Class 44 - WITH CHECK OPTION Violation
251 using IntegrityConstraintViolation::IntegrityConstraintViolation;
252};
253//@}
254
255//@{
256/** @name Class 24 - Invalid Cursor State */
257class InvalidCursorState : public ServerRuntimeError {
258 using ServerRuntimeError::ServerRuntimeError;
259};
260//@}
261
262//@{
263/** @name Class 25 — Invalid Transaction State */
264class InvalidTransactionState : public ServerRuntimeError {
265 using ServerRuntimeError::ServerRuntimeError;
266};
267//@}
268
269//@{
270/** @name Class 26 - Invalid SQL Statement Name */
271/// This exception is thrown in case a prepared statement doesn't exist
272class InvalidSqlStatementName : public ServerRuntimeError {
273 using ServerRuntimeError::ServerRuntimeError;
274};
275//@}
276
277//@{
278/** @name Invalid object name, several classes */
279/// @brief Exception class for several Invalid * Name classes.
280/// Class 34 - Invalid Cursor Name
281/// Class 3D - Invalid Catalogue Name
282/// Class 3F - Invalid Schema Name
283/// TODO Add documentation (links) on the error classes
284/// TODO Split exception classes if needed based on documentation
285class InvalidObjectName : public ServerLogicError {
286 using ServerLogicError::ServerLogicError;
287};
288//@}
289
290//@{
291/** @name Class 28 - Invalid Authorisation Specification */
292class InvalidAuthorizationSpecification : public ServerLogicError {
293 using ServerLogicError::ServerLogicError;
294};
295//@}
296
297//@{
298/** @name Class 2B - Dependent Privilege Descriptors Still Exist */
299class DependentPrivilegeDescriptorsStillExist : public ServerRuntimeError {
300 using ServerRuntimeError::ServerRuntimeError;
301};
302//@}
303
304//@{
305/** @name Class 2D - Invalid Transaction Termination */
306class InvalidTransactionTermination : public ServerRuntimeError {
307 using ServerRuntimeError::ServerRuntimeError;
308};
309//@}
310
311//@{
312/** @name Class 38 - External Routine Exception */
313class ExternalRoutineException : public ServerRuntimeError {
314 using ServerRuntimeError::ServerRuntimeError;
315};
316//@}
317
318//@{
319/** @name Class 39 - External Routine Invocation Exception */
320class ExternalRoutineInvocationException : public ServerRuntimeError {
321 using ServerRuntimeError::ServerRuntimeError;
322};
323//@}
324
325//@{
326/** @name Class 3B - Savepoint Exception */
327class SavepointException : public ServerRuntimeError {
328 using ServerRuntimeError::ServerRuntimeError;
329};
330//@}
331
332//@{
333/** @name Class 2F — SQL Routine Exception */
334class SqlRoutineException : public ServerRuntimeError {
335 using ServerRuntimeError::ServerRuntimeError;
336};
337//@}
338
339//@{
340/** @name Class 40 — Transaction Rollback */
341class TransactionRollback : public ServerRuntimeError {
342 using ServerRuntimeError::ServerRuntimeError;
343};
344//@}
345
346//@{
347/** @name Class 42 — Syntax Error or Access Rule Violation */
348class SyntaxError : public ServerLogicError {
349 using ServerLogicError::ServerLogicError;
350};
351
352class AccessRuleViolation : public ServerLogicError {
353 using ServerLogicError::ServerLogicError;
354};
355
356class DuplicatePreparedStatement : public ServerLogicError {
357 using ServerLogicError::ServerLogicError;
358};
359
360//@}
361
362//@{
363/** @name Class 53 - Insufficient Resources */
364class InsufficientResources : public ServerRuntimeError {
365 using ServerRuntimeError::ServerRuntimeError;
366};
367//@}
368
369//@{
370/** @name Class 54 - Program Limit Exceeded */
371class ProgramLimitExceeded : public ServerRuntimeError {
372 using ServerRuntimeError::ServerRuntimeError;
373};
374//@}
375
376//@{
377/** @name Class 55 - Object Not In Prerequisite State */
378class ObjectNotInPrerequisiteState : public ServerRuntimeError {
379 using ServerRuntimeError::ServerRuntimeError;
380};
381//@}
382
383//@{
384/** @name Class 57 - Operator Intervention */
385class OperatorIntervention : public ServerRuntimeError {
386 using ServerRuntimeError::ServerRuntimeError;
387};
388
390 using OperatorIntervention::OperatorIntervention;
391};
392
394 using OperatorIntervention::OperatorIntervention;
395};
396
398 using OperatorIntervention::OperatorIntervention;
399};
400
402 using OperatorIntervention::OperatorIntervention;
403};
404
406 using OperatorIntervention::OperatorIntervention;
407};
408//@}
409
410//@{
411/** @name Class 58 - System Error (errors external to PostgreSQL itself) */
412class SystemError : public ServerRuntimeError {
413 using ServerRuntimeError::ServerRuntimeError;
414};
415//@}
416
417//@{
418/** @name Class 72 — Snapshot Failure */
419class SnapshotFailure : public ServerRuntimeError {
420 using ServerRuntimeError::ServerRuntimeError;
421};
422//@}
423
424//@{
425/** @name Class F0 — Configuration File Error */
426class ConfigurationFileError : public ServerRuntimeError {
427 using ServerRuntimeError::ServerRuntimeError;
428};
429//@}
430
431//@{
432/** @name Class HV — Foreign Data Wrapper Error (SQL/MED) */
433class FdwError : public ServerRuntimeError {
434 using ServerRuntimeError::ServerRuntimeError;
435};
436//@}
437
438//@{
439/** @name Class P0 — PL/pgSQL Error */
440class PlPgSqlError : public ServerRuntimeError {
441 using ServerRuntimeError::ServerRuntimeError;
442};
443//@}
444
445//@{
446/** @name Class XX — Internal Error */
447class InternalServerError : public ServerRuntimeError {
448 using ServerRuntimeError::ServerRuntimeError;
449};
450//@}
451//@}
452
453//@{
454/** @name Transaction errors */
456 using LogicError::LogicError;
457};
458
460public:
461 AlreadyInTransaction();
462};
463
465public:
466 NotInTransaction();
467 NotInTransaction(const std::string& msg);
468};
469
471public:
472 TransactionForceRollback();
473 TransactionForceRollback(const std::string& msg);
474};
475
476//@}
477
478//@{
479/** @name Result set usage errors */
480
482public:
483 ResultSetError(std::string msg);
484
485 void AddMsgSuffix(std::string_view str);
486 void AddMsgPrefix(std::string_view str);
487
488 const char* what() const noexcept override;
489
490private:
491 std::string msg_;
492};
493
494/// @brief Result set has less rows than the requested row index.
496public:
497 RowIndexOutOfBounds(std::size_t index);
498};
499
500/// @brief Result set has less columns that the requested index.
502public:
503 FieldIndexOutOfBounds(std::size_t index);
504};
505
506/// @brief Result set doesn't have field with the requested name.
508public:
509 FieldNameDoesntExist(std::string_view name);
510};
511
512/// @brief Data extraction from a null field value to a non-nullable type
513/// requested.
515public:
516 template <typename T>
517 FieldValueIsNull(std::size_t field_index, std::string_view field_name, const T&)
518 : ResultSetError(fmt::format(
519 "Field #{} name `{}` C++ type `{}` value is null, forgot `std::optional`?",
520 field_index,
521 field_name,
522 compiler::GetTypeName<T>()
523 ))
524 {}
525};
526
527/// @brief A value of a non-nullable type requested to be set null.
528/// Can occur if io::traits::IsNullable for the type is specialised as
529/// true_type, but io::traits::GetSetNull is not specialized appropriately.
531public:
532 TypeCannotBeNull(std::string_view type);
533};
534
535/// @brief Field buffer contains different category of data than expected by
536/// data parser.
538public:
539 InvalidParserCategory(std::string_view type, io::BufferCategory parser, io::BufferCategory buffer);
540};
541
542/// @brief While checking result set types, failed to determine the buffer
543/// category for a type oid.
544/// The context string is formed by the ResultSet and will have the form
545/// of 'result set field `foo` type `my_schema.bar` field `baz` array element'
547public:
548 UnknownBufferCategory(std::string_view context, Oid type_oid);
549 UnknownBufferCategory(Oid type_oid, std::string_view cpp_field_type, std::string_view cpp_composite_type);
550
551 const Oid type_oid;
552};
553
554/// @brief A field in a result set doesn't have a binary parser.
556 using ResultSetError::ResultSetError;
557};
558
559/// @brief Buffer size is invalid for a fixed-size type.
560/// Can occur when a wrong field type is requested for reply.
562 using ResultSetError::ResultSetError;
563};
564
565/// @brief Binary buffer contains invalid data.
566/// Can occur when parsing binary buffers containing multiple fields.
568public:
569 InvalidBinaryBuffer(const std::string& message);
570};
571
572/// @brief A tuple was requested to be parsed out of a row that doesn't have
573/// enough fields.
575public:
576 InvalidTupleSizeRequested(std::size_t field_count, std::size_t tuple_size);
577};
578
579/// @brief A row or result set requested to be treated as a single column, but
580/// contains more than one column.
582public:
583 NonSingleColumnResultSet(std::size_t actual_size, std::string_view type_name, std::string_view func);
584};
585
586/// @brief A result set containing a single row was expected
588public:
589 explicit NonSingleRowResultSet(std::size_t actual_size);
590};
591
592/// @brief A row was requested to be parsed based on field names/indexed,
593/// the count of names/indexes doesn't match the tuple size.
595public:
596 FieldTupleMismatch(std::size_t field_count, std::size_t tuple_size);
597};
598
599/// @brief A binary buffer contains a numeric value that does not fit
600/// into a given C++ value type.
602public:
603 using ResultSetError::ResultSetError;
604};
605
606//@}
607
608//@{
609/// @brief Base error when working with mapped types
610class UserTypeError : public LogicError {
611 using LogicError::LogicError;
612};
613
614/// @brief PostgreSQL composite type has different count of members from
615/// the C++ counterpart.
617public:
618 CompositeSizeMismatch(std::size_t pg_size, std::size_t cpp_size, std::string_view cpp_type);
619};
620
621/// @brief PostgreSQL composite type has different member type that the C++
622/// mapping suggests.
624public:
625 CompositeMemberTypeMismatch(
626 std::string_view pg_type_schema,
627 std::string_view pg_type_name,
628 std::string_view field_name,
629 Oid pg_oid,
630 Oid user_oid
631 );
632};
633
634//@}
635
636//@{
637/** @name Array errors */
638/// @brief Base error when working with array types.
639class ArrayError : public LogicError {
640 using LogicError::LogicError;
641};
642
643/// @brief Array received from postgres has different dimensions from those of
644/// C++ container.
646public:
647 DimensionMismatch();
648};
649
651public:
652 InvalidDimensions(std::size_t expected, std::size_t actual);
653};
654
655//@}
656
657//@{
658/** @name Numeric/decimal datatype errors */
659class NumericError : public LogicError {
660 using LogicError::LogicError;
661};
662
663/// Value in PostgreSQL binary buffer cannot be represented by a given C++ type
665 using NumericError::NumericError;
666};
667
668/// PostgreSQL binary buffer contains NaN value, but the given C++ type doesn't
669/// support NaN value
670class ValueIsNaN : public NumericError {
671 using NumericError::NumericError;
672};
673
674/// Integral representation for a numeric contains invalid data
676 using NumericError::NumericError;
677};
678//@}
679
680/// @brief Invalid format for input data.
681///
682/// Can occur when a numeric string representation cannot be parsed for sending
683/// in binary buffers
685 using LogicError::LogicError;
686};
687
688//@{
689/** @name Enumeration type errors */
691 using LogicError::LogicError;
692};
693
695public:
696 InvalidEnumerationLiteral(std::string_view type_name, std::string_view literal);
697};
698
700public:
701 template <typename Enum>
702 explicit InvalidEnumerationValue(Enum val)
703 : EnumerationError(fmt::format(
704 "Invalid enumeration value '{}' for enum type '{}'",
705 USERVER_NAMESPACE::utils::UnderlyingValue(val),
706 compiler::GetTypeName<Enum>()
707 ))
708 {}
709};
710//@}
711
712/// PostgreSQL interval datatype contains months field, which cannot be
713/// converted to microseconds unambiguously
715public:
716 UnsupportedInterval();
717};
718
719/// PostgreSQL range type has at least one end unbound
721public:
722 BoundedRangeError(std::string_view message);
723};
724
725//@{
726/** @name bit/bit varying type errors */
727
728/// @brief Base error when working with bit string types.
730public:
731 using LogicError::LogicError;
732};
733
734/// Value in PostgreSQL binary buffer cannot be represented by a given C++ type
736public:
737 BitStringOverflow(std::size_t actual, std::size_t expected);
738};
739
740/// Value in PostgreSQL binary buffer cannot be represented as bit string type
742public:
743 InvalidBitStringRepresentation();
744};
745//@}
746
747//@{
748/** @name Misc exceptions */
749class InvalidDSN : public RuntimeError {
750public:
751 InvalidDSN(std::string_view dsn, std::string_view err);
752};
753
755 using RuntimeError::RuntimeError;
756};
757
759 using LogicError::LogicError;
760};
761
762//@}
763
764//@{
765/** @name ip type errors */
767public:
768 using LogicError::LogicError;
769};
770
772public:
773 explicit IpAddressInvalidFormat(std::string_view str);
774};
775//@}
776
777} // namespace storages::postgres
778
779USERVER_NAMESPACE_END