//! Postgres errors use std::hashmap::HashMap; use super::ssl::error::SslError; macro_rules! make_errors( ($($code:pat => $error:ident),+) => ( /// SQLSTATE error codes #[deriving(ToStr, Eq)] #[allow(missing_doc)] pub enum PostgresSqlState { $($error,)+ UnknownSqlState(~str) } impl FromStr for PostgresSqlState { fn from_str(s: &str) -> Option { Some(match s { $($code => $error,)+ state => UnknownSqlState(state.to_owned()) }) } } ) ) // From http://www.postgresql.org/docs/9.2/static/errcodes-appendix.html make_errors!( // Class 00 — Successful Completion "00000" => SuccessfulCompletion, // Class 01 — Warning "01000" => Warning, "0100C" => DynamicResultSetsReturned, "01008" => ImplicitZeroBitPadding, "01003" => NullValueEliminatedInSetFunction, "01007" => PrivilegeNotGranted, "01006" => PrivilegeNotRevoked, "01004" => StringDataRightTruncationWarning, "01P01" => DeprecatedFeature, // Class 02 — No Data "02000" => NoData, "02001" => NoAdditionalDynamicResultSetsReturned, // Class 03 — SQL Statement Not Yet Complete "03000" => SqlStatementNotYetComplete, // Class 08 — Connection Exception "08000" => ConnectionException, "08003" => ConnectionDoesNotExist, "08006" => ConnectionFailure, "08001" => SqlclientUnableToEstablishSqlconnection, "08004" => SqlserverRejectedEstablishmentOfSqlconnection, "08007" => TransactionResolutionUnknown, "08P01" => ProtocolViolation, // Class 09 — Triggered Action Exception "09000" => TriggeredActionException, // Class 0A — Feature Not Supported "0A000" => FeatureNotSupported, // Class 0B — Invalid Transaction Initiation "0B000" => InvalidTransactionInitiation, // Class 0F — Locator Exception "0F000" => LocatorException, "0F001" => InvalidLocatorException, // Class 0L — Invalid Grantor "0L000" => InvalidGrantor, "0LP01" => InvalidGrantOperation, // Class 0P — Invalid Role Specification "0P000" => InvalidRoleSpecification, // Class 0Z — Diagnostics Exception "0Z000" => DiagnosticsException, "0Z002" => StackedDiagnosticsAccessedWithoutActiveHandler, // Class 20 — Case Not Found "20000" => CaseNotFound, // Class 21 — Cardinality Violation "21000" => CardinalityViolation, // Class 22 — Data Exception "22000" => DataException, "2202E" => ArraySubscriptError, "22021" => CharacterNotInRepertoire, "22008" => DatetimeFieldOverflow, "22012" => DivisionByZero, "22005" => ErrorInAssignment, "2200B" => EscapeCharacterConflict, "22022" => IndicatorOverflow, "22015" => IntervalFieldOverflow, "2201E" => InvalidArgumentForLogarithm, "22014" => InvalidArgumentForNtileFunction, "22016" => InvalidArgumentForNthValueFunction, "2201F" => InvalidArgumentForPowerFunction, "2201G" => InvalidArgumentForWidthBucketFunction, "22018" => InvalidCharacterValueForCast, "22007" => InvalidDatetimeFormat, "22019" => InvalidEscapeCharacter, "2200D" => InvalidEscapeOctet, "22025" => InvalidEscapeSequence, "22P06" => NonstandardUseOfEscapeCharacter, "22010" => InvalidIndicatorParameterValue, "22023" => InvalidParameterValue, "2201B" => InvalidRegularExpression, "2201W" => InvalidRowCountInLimitClause, "2201X" => InvalidRowCountInResultOffsetClause, "22009" => InvalidTimeZoneDisplacementValue, "2200C" => InvalidUseOfEscapeCharacter, "2200G" => MostSpecificTypeMismatch, "22004" => NullValueNotAllowedData, "22002" => NullValueNoIndicatorParameter, "22003" => NumericValueOutOfRange, "22026" => StringDataLengthMismatch, "22001" => StringDataRightTruncationException, "22011" => SubstringError, "22027" => TrimError, "22024" => UnterminatedCString, "2200F" => ZeroLengthCharacterString, "22P01" => FloatingPointException, "22P02" => InvalidTextRepresentation, "22P03" => InvalidBinaryRepresentation, "22P04" => BadCopyFileFormat, "22P05" => UntranslatableCharacter, "2200L" => NotAnXmlDocument, "2200M" => InvalidXmlDocument, "2200N" => InvalidXmlContent, "2200S" => InvalidXmlComment, "2200T" => InvalidXmlProcessingInstruction, // Class 23 — Integrity Constraint Violation "23000" => IntegrityConstraintViolation, "23001" => RestrictViolation, "23502" => NotNullViolation, "23503" => ForeignKeyViolation, "23505" => UniqueViolation, "23514" => CheckViolation, "32P01" => ExclusionViolation, // Class 24 — Invalid Cursor State "24000" => InvalidCursorState, // Class 25 — Invalid Transaction State "25000" => InvalidTransactionState, "25001" => ActiveSqlTransaction, "25002" => BranchTransactionAlreadyActive, "25008" => HeldCursorRequiresSameIsolationLevel, "25003" => InappropriateAccessModeForBranchTransaction, "25004" => InappropriateIsolationLevelForBranchTransaction, "25005" => NoActiveSqlTransactionForBranchTransaction, "25006" => ReadOnlySqlTransaction, "25007" => SchemaAndDataStatementMixingNotSupported, "25P01" => NoActiveSqlTransaction, "25P02" => InFailedSqlTransaction, // Class 26 — Invalid SQL Statement Name "26000" => InvalidSqlStatementName, // Class 27 — Triggered Data Change Violation "27000" => TriggeredDataChangeViolation, // Class 28 — Invalid Authorization Specification "28000" => InvalidAuthorizationSpecification, "28P01" => InvalidPassword, // Class 2B — Dependent Privilege Descriptors Still Exist "2B000" => DependentPrivilegeDescriptorsStillExist, "2BP01" => DependentObjectsStillExist, // Class 2D — Invalid Transaction Termination "2D000" => InvalidTransactionTermination, // Class 2F — SQL Routine Exception "2F000" => SqlRoutineException, "2F005" => FunctionExecutedNoReturnStatement, "2F002" => ModifyingSqlDataNotPermittedSqlRoutine, "2F003" => ProhibitedSqlStatementAttemptedSqlRoutine, "2F004" => ReadingSqlDataNotPermittedSqlRoutine, // Class 34 — Invalid Cursor Name "34000" => InvalidCursorName, // Class 38 — External Routine Exception "38000" => ExternalRoutineException, "38001" => ContainingSqlNotPermitted, "38002" => ModifyingSqlDataNotPermittedExternalRoutine, "38003" => ProhibitedSqlStatementAttemptedExternalRoutine, "38004" => ReadingSqlDataNotPermittedExternalRoutine, // Class 39 — External Routine Invocation Exception "39000" => ExternalRoutineInvocationException, "39001" => InvalidSqlstateReturned, "39004" => NullValueNotAllowedExternalRoutine, "39P01" => TriggerProtocolViolated, "39P02" => SrfProtocolViolated, // Class 3B — Savepoint Exception "3B000" => SavepointException, "3B001" => InvalidSavepointException, // Class 3D — Invalid Catalog Name "3D000" => InvalidCatalogName, // Class 3F — Invalid Schema Name "3F000" => InvalidSchemaName, // Class 40 — Transaction Rollback "40000" => TransactionRollback, "40002" => TransactionIntegrityConstraintViolation, "40001" => SerializationFailure, "40003" => StatementCompletionUnknown, "40P01" => DeadlockDetected, // Class 42 — Syntax Error or Access Rule Violation "42000" => SyntaxErrorOrAccessRuleViolation, "42601" => SyntaxError, "42501" => InsufficientPrivilege, "42846" => CannotCoerce, "42803" => GroupingError, "42P20" => WindowingError, "42P19" => InvalidRecursion, "42830" => InvalidForeignKey, "42602" => InvalidName, "42622" => NameTooLong, "42939" => ReservedName, "42804" => DatatypeMismatch, "42P18" => IndeterminateDatatype, "42P21" => CollationMismatch, "42P22" => IndeterminateCollation, "42809" => WrongObjectType, "42703" => UndefinedColumn, "42883" => UndefinedFunction, "42P01" => UndefinedTable, "42P02" => UndefinedParameter, "42704" => UndefinedObject, "42701" => DuplicateColumn, "42P03" => DuplicateCursor, "42P04" => DuplicateDatabase, "42723" => DuplicateFunction, "42P05" => DuplicatePreparedStatement, "42P06" => DuplicateSchema, "42P07" => DuplicateTable, "42712" => DuplicateAliaas, "42710" => DuplicateObject, "42702" => AmbiguousColumn, "42725" => AmbiguousFunction, "42P08" => AmbiguousParameter, "42P09" => AmbiguousAlias, "42P10" => InvalidColumnReference, "42611" => InvalidColumnDefinition, "42P11" => InvalidCursorDefinition, "42P12" => InvalidDatabaseDefinition, "42P13" => InvalidFunctionDefinition, "42P14" => InvalidPreparedStatementDefinition, "42P15" => InvalidSchemaDefinition, "42P16" => InvalidTableDefinition, "42P17" => InvalidObjectDefinition, // Class 44 — WITH CHECK OPTION Violation "44000" => WithCheckOptionViolation, // Class 53 — Insufficient Resources "53000" => InsufficientResources, "53100" => DiskFull, "53200" => OutOfMemory, "53300" => TooManyConnections, "53400" => ConfigurationLimitExceeded, // Class 54 — Program Limit Exceeded "54000" => ProgramLimitExceeded, "54001" => StatementTooComplex, "54011" => TooManyColumns, "54023" => TooManyArguments, // Class 55 — Object Not In Prerequisite State "55000" => ObjectNotInPrerequisiteState, "55006" => ObjectInUse, "55P02" => CantChangeRuntimeParam, "55P03" => LockNotAvailable, // Class 57 — Operator Intervention "57000" => OperatorIntervention, "57014" => QueryCanceled, "57P01" => AdminShutdown, "57P02" => CrashShutdown, "57P03" => CannotConnectNow, "57P04" => DatabaseDropped, // Class 58 — System Error "58000" => SystemError, "58030" => IoError, "58P01" => UndefinedFile, "58P02" => DuplicateFile, // Class F0 — Configuration File Error "F0000" => ConfigFileError, "F0001" => LockFileExists, // Class HV — Foreign Data Wrapper Error (SQL/MED) "HV000" => FdwError, "HV005" => FdwColumnNameNotFound, "HV002" => FdwDynamicParameterValueNeeded, "HV010" => FdwFunctionSequenceError, "HV021" => FdwInconsistentDescriptorInformation, "HV024" => FdwInvalidAttributeValue, "HV007" => FdwInvalidColumnName, "HV008" => FdwInvalidColumnNumber, "HV004" => FdwInvalidDataType, "HV006" => FdwInvalidDataTypeDescriptors, "HV091" => FdwInvalidDescriptorFieldIdentifier, "HV00B" => FdwInvalidHandle, "HV00C" => FdwInvalidOptionIndex, "HV00D" => FdwInvalidOptionName, "HV090" => FdwInvalidStringLengthOrBufferLength, "HV00A" => FdwInvalidStringFormat, "HV009" => FdwInvalidUseOfNullPointer, "HV014" => FdwTooManyHandles, "HV001" => FdwOutOfMemory, "HV00P" => FdwNoSchemas, "HV00J" => FdwOptionNameNotFound, "HV00K" => FdwReplyHandle, "HV00Q" => FdwSchemaNotFound, "HV00R" => FdwTableNotFound, "HV00L" => FdwUnableToCreateExcecution, "HV00M" => FdwUnableToCreateReply, "HV00N" => FdwUnableToEstablishConnection, // Class P0 — PL/pgSQL Error "P0000" => PlpgsqlError, "P0001" => RaiseException, "P0002" => NoDataFound, "P0003" => TooManyRows, // Class XX — Internal Error "XX000" => InternalError, "XX001" => DataCorrupted, "XX002" => IndexCorrupted ) /// Reasons a new Postgres connection could fail #[deriving(ToStr)] pub enum PostgresConnectError { /// The provided URL could not be parsed InvalidUrl, /// The URL was missing a user MissingUser, /// DNS lookup failed DnsError, /// There was an error opening a socket to the server SocketError, /// An error from the Postgres server itself DbError(PostgresDbError), /// A password was required but not provided in the URL MissingPassword, /// The Postgres server requested an authentication method not supported /// by the driver UnsupportedAuthentication, /// The Postgres server does not support SSL encryption NoSslSupport, /// There was an error initializing the SSL session SslError(SslError) } /// Represents the position of an error in a query #[deriving(ToStr)] pub enum PostgresErrorPosition { /// A position in the original query Position(uint), /// A position in an internally generated query InternalPosition { /// The byte position position: uint, /// A query generated by the Postgres server query: ~str } } /// Encapsulates a Postgres error or notice. #[deriving(ToStr)] pub struct PostgresDbError { /// The field contents are ERROR, FATAL, or PANIC (in an error message), /// or WARNING, NOTICE, DEBUG, INFO, or LOG (in a notice message), or a /// localized translation of one of these. severity: ~str, /// The SQLSTATE code for the error. code: PostgresSqlState, /// The primary human-readable error message. This should be accurate but /// terse (typically one line). message: ~str, /// An optional secondary error message carrying more detail about the /// problem. Might run to multiple lines. detail: Option<~str>, /// An optional suggestion what to do about the problem. This is intended /// to differ from Detail in that it offers advice (potentially /// inappropriate) rather than hard facts. Might run to multiple lines. hint: Option<~str>, /// An optional error cursor position into either the original query string /// or an internally generated query. position: Option, /// An indication of the context in which the error occurred. Presently /// this includes a call stack traceback of active procedural language /// functions and internally-generated queries. The trace is one entry per /// line, most recent first. where: Option<~str>, /// If the error was associated with a specific database object, the name /// of the schema containing that object, if any. (PostgreSQL 9.3+) schema: Option<~str>, /// If the error was associated with a specific table, the name of the /// table. (Refer to the schema name field for the name of the table's /// schema.) (PostgreSQL 9.3+) table: Option<~str>, /// If the error was associated with a specific table column, the name of /// the column. (Refer to the schema and table name fields to identify the /// table.) (PostgreSQL 9.3+) column: Option<~str>, /// If the error was associated with a specific data type, the name of the /// data type. (Refer to the schema name field for the name of the data /// type's schema.) (PostgreSQL 9.3+) datatype: Option<~str>, /// If the error was associated with a specific constraint, the name of the /// constraint. Refer to fields listed above for the associated table or /// domain. (For this purpose, indexes are treated as constraints, even if /// they weren't created with constraint syntax.) (PostgreSQL 9.3+) constraint: Option<~str>, /// The file name of the source-code location where the error was reported. file: ~str, /// The line number of the source-code location where the error was /// reported. line: uint, /// The name of the source-code routine reporting the error. routine: ~str } impl PostgresDbError { #[doc(hidden)] pub fn new(fields: ~[(u8, ~str)]) -> PostgresDbError { // move_rev_iter is more efficient than move_iter let mut map: HashMap = fields.move_rev_iter().collect(); PostgresDbError { severity: map.pop(&('S' as u8)).unwrap(), code: FromStr::from_str(map.pop(&('C' as u8)).unwrap()).unwrap(), message: map.pop(&('M' as u8)).unwrap(), detail: map.pop(&('D' as u8)), hint: map.pop(&('H' as u8)), position: match map.pop(&('P' as u8)) { Some(pos) => Some(Position(FromStr::from_str(pos).unwrap())), None => match map.pop(&('p' as u8)) { Some(pos) => Some(InternalPosition { position: FromStr::from_str(pos).unwrap(), query: map.pop(&('q' as u8)).unwrap() }), None => None } }, where: map.pop(&('W' as u8)), schema: map.pop(&('s' as u8)), table: map.pop(&('t' as u8)), column: map.pop(&('c' as u8)), datatype: map.pop(&('d' as u8)), constraint: map.pop(&('n' as u8)), file: map.pop(&('F' as u8)).unwrap(), line: FromStr::from_str(map.pop(&('L' as u8)).unwrap()).unwrap(), routine: map.pop(&('R' as u8)).unwrap() } } #[doc(hidden)] pub fn pretty_error(&self, query: &str) -> ~str { match self.position { Some(Position(pos)) => format!("{}: {} at position {} in\n{}", self.severity, self.message, pos, query), Some(InternalPosition { position, query: ref inner_query }) => format!("{}: {} at position {} in\n{} called from\n{}", self.severity, self.message, position, *inner_query, query), None => format!("{}: {} in\n{}", self.severity, self.message, query) } } }