1use std::ffi::{CStr, CString};
20use std::os::raw::c_int;
21use std::{fmt, io};
22
23use failure::_core::fmt::{Display, Formatter};
24use num_traits::{FromPrimitive, ToPrimitive};
25use rmp::decode::ValueReadError;
26use rmp_serde::decode::Error as DecodeError;
27use rmp_serde::encode::Error as EncodeError;
28
29#[derive(Debug, Fail)]
31pub enum Error {
32 #[fail(display = "Tarantool error: {}", _0)]
33 Tarantool(TarantoolError),
34
35 #[fail(display = "IO error: {}", _0)]
36 IO(io::Error),
37
38 #[fail(display = "Failed to encode tuple: {}", _0)]
39 Encode(EncodeError),
40
41 #[fail(display = "Failed to decode tuple: {}", _0)]
42 Decode(DecodeError),
43
44 #[fail(display = "Value read error: {}", _0)]
45 ValueRead(ValueReadError),
46
47 #[fail(display = "Transaction issue: {}", _0)]
48 Transaction(TransactionError),
49}
50
51impl From<io::Error> for Error {
52 fn from(error: io::Error) -> Self {
53 Error::IO(error)
54 }
55}
56
57impl From<EncodeError> for Error {
58 fn from(error: EncodeError) -> Self {
59 Error::Encode(error)
60 }
61}
62
63impl From<DecodeError> for Error {
64 fn from(error: DecodeError) -> Self {
65 Error::Decode(error)
66 }
67}
68
69impl From<ValueReadError> for Error {
70 fn from(error: ValueReadError) -> Self {
71 Error::ValueRead(error)
72 }
73}
74
75#[derive(Debug, Fail)]
77pub enum TransactionError {
78 #[fail(display = "Transaction has already been started")]
79 AlreadyStarted,
80
81 #[fail(display = "Failed to commit")]
82 FailedToCommit,
83
84 #[fail(display = "Failed to rollback")]
85 FailedToRollback,
86}
87
88impl From<TransactionError> for Error {
89 fn from(error: TransactionError) -> Self {
90 Error::Transaction(error)
91 }
92}
93
94#[derive(Derivative)]
96#[derivative(Debug)]
97pub struct TarantoolError {
98 code: TarantoolErrorCode,
99 message: String,
100 #[derivative(Debug = "ignore")]
101 error_ptr: Box<ffi::BoxError>,
102}
103
104impl TarantoolError {
105 pub fn maybe_last() -> Result<(), Self> {
108 let error_ptr = unsafe { ffi::box_error_last() };
109 if error_ptr.is_null() {
110 return Ok(());
111 }
112
113 let code = unsafe { ffi::box_error_code(error_ptr) };
114 let code = match TarantoolErrorCode::from_u32(code) {
115 Some(code) => code,
116 None => TarantoolErrorCode::Unknown,
117 };
118
119 let message = unsafe { CStr::from_ptr(ffi::box_error_message(error_ptr)) };
120 let message = message.to_string_lossy().into_owned();
121
122 Err(TarantoolError {
123 code,
124 message,
125 error_ptr: unsafe { Box::from_raw(error_ptr) },
126 })
127 }
128
129 pub fn last() -> Self {
131 TarantoolError::maybe_last().err().unwrap()
132 }
133
134 pub fn error_code(&self) -> TarantoolErrorCode {
136 self.code.clone()
137 }
138
139 pub fn error_type(&self) -> String {
141 let result = unsafe { ffi::box_error_type(&*self.error_ptr) };
142 unsafe { CStr::from_ptr(result) }
143 .to_string_lossy()
144 .to_string()
145 }
146}
147
148impl Display for TarantoolError {
149 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
150 write!(f, "{:?}: {}", self.code, self.message)
151 }
152}
153
154impl From<TarantoolError> for Error {
155 fn from(error: TarantoolError) -> Self {
156 Error::Tarantool(error)
157 }
158}
159
160#[repr(u32)]
162#[derive(Debug, Clone, PartialEq, ToPrimitive, FromPrimitive)]
163pub enum TarantoolErrorCode {
164 Unknown = 0,
165 IllegalParams = 1,
166 MemoryIssue = 2,
167 TupleFound = 3,
168 TupleNotFound = 4,
169 Unsupported = 5,
170 NonMaster = 6,
171 Readonly = 7,
172 Injection = 8,
173 CreateSpace = 9,
174 SpaceExists = 10,
175 DropSpace = 11,
176 AlterSpace = 12,
177 IndexType = 13,
178 ModifyIndex = 14,
179 LastDrop = 15,
180 TupleFormatLimit = 16,
181 DropPrimaryKey = 17,
182 KeyPartType = 18,
183 ExactMatch = 19,
184 InvalidMsgpack = 20,
185 ProcRet = 21,
186 TupleNotArray = 22,
187 FieldType = 23,
188 IndexPartTypeMismatch = 24,
189 Splice = 25,
190 UpdateArgType = 26,
191 FormatMismatchIndexPart = 27,
192 UnknownUpdateOp = 28,
193 UpdateField = 29,
194 FunctionTxActive = 30,
195 KeyPartCount = 31,
196 ProcLua = 32,
197 NoSuchProc = 33,
198 NoSuchTrigger = 34,
199 NoSuchIndexID = 35,
200 NoSuchSpace = 36,
201 NoSuchFieldNo = 37,
202 ExactFieldCount = 38,
203 FieldMissing = 39,
204 WalIo = 40,
205 MoreThanOneTuple = 41,
206 AccessDenied = 42,
207 CreateUser = 43,
208 DropUser = 44,
209 NoSuchUser = 45,
210 UserExists = 46,
211 PasswordMismatch = 47,
212 UnknownRequestType = 48,
213 UnknownSchemaObject = 49,
214 CreateFunction = 50,
215 NoSuchFunction = 51,
216 FunctionExists = 52,
217 BeforeReplaceRet = 53,
218 MultistatementTransaction = 54,
219 TriggerExists = 55,
220 UserMax = 56,
221 NoSuchEngine = 57,
222 ReloadCfg = 58,
223 Cfg = 59,
224 SavepointEmptyTx = 60,
225 NoSuchSavepoint = 61,
226 UnknownReplica = 62,
227 ReplicasetUuidMismatch = 63,
228 InvalidUuid = 64,
229 ReplicasetUuidIsRo = 65,
230 InstanceUuidMismatch = 66,
231 ReplicaIDIsReserved = 67,
232 InvalidOrder = 68,
233 MissingRequestField = 69,
234 Identifier = 70,
235 DropFunction = 71,
236 IteratorType = 72,
237 ReplicaMax = 73,
238 InvalidXlog = 74,
239 InvalidXlogName = 75,
240 InvalidXlogOrder = 76,
241 NoConnection = 77,
242 Timeout = 78,
243 ActiveTransaction = 79,
244 CursorNoTransaction = 80,
245 CrossEngineTransaction = 81,
246 NoSuchRole = 82,
247 RoleExists = 83,
248 CreateRole = 84,
249 IndexExists = 85,
250 SessionClosed = 86,
251 RoleLoop = 87,
252 Grant = 88,
253 PrivGranted = 89,
254 RoleGranted = 90,
255 PrivNotGranted = 91,
256 RoleNotGranted = 92,
257 MissingSnapshot = 93,
258 CantUpdatePrimaryKey = 94,
259 UpdateIntegerOverflow = 95,
260 GuestUserPassword = 96,
261 TransactionConflict = 97,
262 UnsupportedPriv = 98,
263 LoadFunction = 99,
264 FunctionLanguage = 100,
265 RtreeRect = 101,
266 ProcC = 102,
267 UnknownRtreeIndexDistanceType = 103,
268 Protocol = 104,
269 UpsertUniqueSecondaryKey = 105,
270 WrongIndexRecord = 106,
271 WrongIndexParts = 107,
272 WrongIndexOptions = 108,
273 WrongSchemaVersion = 109,
274 MemtxMaxTupleSize = 110,
275 WrongSpaceOptions = 111,
276 UnsupportedIndexFeature = 112,
277 ViewIsRo = 113,
278 NoTransaction = 114,
279 System = 115,
280 Loading = 116,
281 ConnectionToSelf = 117,
282 KeyPartIsTooLong = 118,
283 Compression = 119,
284 CheckpointInProgress = 120,
285 SubStmtMax = 121,
286 CommitInSubStmt = 122,
287 RollbackInSubStmt = 123,
288 Decompression = 124,
289 InvalidXlogType = 125,
290 AlreadyRunning = 126,
291 IndexFieldCountLimit = 127,
292 LocalInstanceIDIsReadOnly = 128,
293 BackupInProgress = 129,
294 ReadViewAborted = 130,
295 InvalidIndexFile = 131,
296 InvalidRunFile = 132,
297 InvalidVylogFile = 133,
298 CheckpointRollback = 134,
299 VyQuotaTimeout = 135,
300 PartialKey = 136,
301 TruncateSystemSpace = 137,
302 LoadModule = 138,
303 VinylMaxTupleSize = 139,
304 WrongDdVersion = 140,
305 WrongSpaceFormat = 141,
306 CreateSequence = 142,
307 AlterSequence = 143,
308 DropSequence = 144,
309 NoSuchSequence = 145,
310 SequenceExists = 146,
311 SequenceOverflow = 147,
312 NoSuchIndexName = 148,
313 SpaceFieldIsDuplicate = 149,
314 CantCreateCollation = 150,
315 WrongCollationOptions = 151,
316 NullablePrimary = 152,
317 NoSuchFieldName = 153,
318 TransactionYield = 154,
319 NoSuchGroup = 155,
320 SqlBindValue = 156,
321 SqlBindType = 157,
322 SqlBindParameterMax = 158,
323 SqlExecute = 159,
324 Unused = 160,
325 SqlBindNotFound = 161,
326 ActionMismatch = 162,
327 ViewMissingSql = 163,
328 ForeignKeyConstraint = 164,
329 NoSuchModule = 165,
330 NoSuchCollation = 166,
331 CreateFkConstraint = 167,
332 DropFkConstraint = 168,
333 NoSuchConstraint = 169,
334 ConstraintExists = 170,
335 SqlTypeMismatch = 171,
336 RowidOverflow = 172,
337 DropCollation = 173,
338 IllegalCollationMix = 174,
339 SqlNoSuchPragma = 175,
340 SqlCantResolveField = 176,
341 IndexExistsInSpace = 177,
342 InconsistentTypes = 178,
343 SqlSyntax = 179,
344 SqlStackOverflow = 180,
345 SqlSelectWildcard = 181,
346 SqlStatementEmpty = 182,
347 SqlKeywordIsReserved = 183,
348 SqlUnrecognizedSyntax = 184,
349 SqlUnknownToken = 185,
350 SqlParserGeneric = 186,
351 SqlAnalyzeArgument = 187,
352 SqlColumnCountMax = 188,
353 HexLiteralMax = 189,
354 IntLiteralMax = 190,
355 SqlParserLimit = 191,
356 IndexDefUnsupported = 192,
357 CkDefUnsupported = 193,
358 MultikeyIndexMismatch = 194,
359 CreateCkConstraint = 195,
360 CkConstraintFailed = 196,
361 SqlColumnCount = 197,
362 FuncIndexFunc = 198,
363 FuncIndexFormat = 199,
364 FuncIndexParts = 200,
365 BootstrapReadonly = 201,
366}
367
368pub fn clear_error() {
370 unsafe { ffi::box_error_clear() }
371}
372
373pub fn set_error(file: &str, line: u32, code: &TarantoolErrorCode, msg: &str) -> c_int {
375 unsafe {
376 ffi::box_error_set(
377 CString::new(file).unwrap().as_ptr(),
378 line,
379 code.to_u32().unwrap(),
380 CString::new(msg).unwrap().as_ptr(),
381 )
382 }
383}
384
385mod ffi {
386 use std::os::raw::{c_char, c_int, c_uint};
387
388 #[repr(C)]
389 pub struct BoxError {
390 _unused: [u8; 0],
391 }
392
393 extern "C" {
394 pub fn box_error_code(error: *const BoxError) -> u32;
395 pub fn box_error_message(error: *const BoxError) -> *const c_char;
396 pub fn box_error_last() -> *mut BoxError;
397 pub fn box_error_type(error: *const BoxError) -> *const c_char;
398 pub fn box_error_clear();
399 pub fn box_error_set(
400 file: *const c_char,
401 line: c_uint,
402 code: u32,
403 format: *const c_char,
404 ...
405 ) -> c_int;
406 }
407}