oracle_nosql_rust_sdk/error.rs
1//
2// Copyright (c) 2024, 2025 Oracle and/or its affiliates. All rights reserved.
3//
4// Licensed under the Universal Permissive License v 1.0 as shown at
5// https://oss.oracle.com/licenses/upl/
6//
7use num_enum::TryFromPrimitive;
8
9include!(concat!(env!("OUT_DIR"), "/ua.rs"));
10
11pub(crate) fn sdk_version() -> &'static str {
12 SDK_VERSION
13}
14
15pub(crate) fn user_agent() -> &'static str {
16 USER_AGENT
17}
18
19/// Enumeration of all possible errors returned by this library.
20#[derive(Debug, Clone)]
21pub struct NoSQLError {
22 pub code: NoSQLErrorCode,
23 pub message: String,
24}
25
26impl std::error::Error for NoSQLError {
27 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
28 None
29 }
30}
31
32impl std::fmt::Display for NoSQLError {
33 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
34 return write!(f, "code={:?} message=\"{}\"", self.code, self.message);
35 }
36}
37
38impl NoSQLError {
39 pub fn new(code: NoSQLErrorCode, msg: &str) -> NoSQLError {
40 NoSQLError {
41 code,
42 message: msg.to_string(),
43 }
44 }
45
46 pub fn from_int(icode: i32, msg: &str) -> NoSQLError {
47 if let Ok(code) = NoSQLErrorCode::try_from(icode) {
48 return NoSQLError {
49 code: code,
50 message: msg.to_string(),
51 };
52 }
53 NoSQLError {
54 code: NoSQLErrorCode::UnknownError,
55 message: format!("Invalid integer error code {}", icode),
56 }
57 }
58}
59
60//pub(crate) fn ia(msg: String) -> NoSQLError {
61//NoSQLError {
62//code: NoSQLErrorCode::IllegalArgument,
63//message: msg,
64//}
65//}
66//pub(crate) fn ias(msg: &str) -> NoSQLError {
67//NoSQLError {
68//code: NoSQLErrorCode::IllegalArgument,
69//message: msg.to_string(),
70//}
71//}
72
73macro_rules! ia_error {
74 ($($t:tt)*) => {{
75 let m = format!($($t)*);
76 NoSQLError {
77 code: crate::error::NoSQLErrorCode::IllegalArgument,
78 message: format!("{} ({})", m, crate::error::sdk_version()),
79 }
80 }};
81}
82
83pub(crate) use ia_error;
84
85macro_rules! ia_err {
86 ($($t:tt)*) => {{
87 let m = format!($($t)*);
88 Err(NoSQLError {
89 code: crate::error::NoSQLErrorCode::IllegalArgument,
90 message: format!("{} ({})", m, crate::error::sdk_version()),
91 })
92 }};
93}
94
95pub(crate) use ia_err;
96
97impl From<reqwest::Error> for NoSQLError {
98 fn from(e: reqwest::Error) -> Self {
99 let mut code = NoSQLErrorCode::ServerError;
100 if e.is_timeout() {
101 code = NoSQLErrorCode::RequestTimeout;
102 }
103 // TODO: others?
104 NoSQLError {
105 code: code,
106 message: format!(
107 "reqwest error: {} ({})",
108 e.to_string(),
109 crate::error::sdk_version()
110 ),
111 }
112 }
113}
114
115impl From<reqwest::header::InvalidHeaderValue> for NoSQLError {
116 fn from(e: reqwest::header::InvalidHeaderValue) -> Self {
117 ia_error!("invalid header value: {}", e.to_string())
118 }
119}
120
121impl From<url::ParseError> for NoSQLError {
122 fn from(e: url::ParseError) -> Self {
123 ia_error!("error parsing url: {}", e.to_string())
124 }
125}
126
127impl From<chrono::ParseError> for NoSQLError {
128 fn from(e: chrono::ParseError) -> Self {
129 ia_error!("invalid datetime value: {}", e.to_string())
130 }
131}
132
133// TODO: remove this and write From(s) for all other errors
134impl From<Box<dyn std::error::Error>> for NoSQLError {
135 fn from(e: Box<dyn std::error::Error>) -> Self {
136 ia_error!("{}", e.to_string())
137 }
138}
139
140// NoSQLErrorCode represents the error code.
141// Error codes are divided into categories as follows:
142//
143// 1. Error codes for user-generated errors, range from 1 to 50(exclusive).
144// These include illegal arguments, exceeding size limits for some objects,
145// resource not found, etc.
146//
147// 2. Error codes for user throttling, range from 50 to 100(exclusive).
148//
149// 3. Error codes for server issues, range from 100 to 150(exclusive).
150//
151// 3.1 Retryable server issues, range from 100 to 125(exclusive), that represent
152// internal problems, presumably temporary, and need to be sent back to the
153// application for retry.
154//
155// 3.2 Other server issues, begin from 125.
156// These include server illegal state, unknown server error, etc.
157// They might be retryable, or not.
158//
159#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive)]
160#[repr(i32)]
161pub enum NoSQLErrorCode {
162 /// NoError represents there is no error.
163 NoError = 0,
164
165 /// UnknownOperation error represents the operation attempted is unknown.
166 UnknownOperation = 1,
167
168 /// TableNotFound error represents the operation attempted to access a table
169 /// that does not exist or is not in a visible state.
170 TableNotFound = 2,
171
172 /// IndexNotFound error represents the operation attempted to access an index
173 /// that does not exist or is not in a visible state.
174 IndexNotFound = 3,
175
176 /// IllegalArgument error represents the application provided an illegal
177 /// argument for the operation.
178 IllegalArgument = 4,
179
180 /// RowSizeLimitExceeded error represents an attempt has been made to create
181 /// a row with a size that exceeds the system defined limit.
182 ///
183 /// This is used for cloud service only.
184 RowSizeLimitExceeded = 5,
185
186 /// KeySizeLimitExceeded error represents an attempt has been made to create
187 /// a row with a primary key or index key size that exceeds the system defined limit.
188 ///
189 /// This is used for cloud service only.
190 KeySizeLimitExceeded = 6,
191
192 /// BatchOpNumberLimitExceeded error represents that the number of operations
193 /// included in Client.WriteMultiple operation exceeds the system defined limit.
194 ///
195 /// This is used for cloud service only.
196 BatchOpNumberLimitExceeded = 7,
197
198 /// RequestSizeLimitExceeded error represents that the size of a request
199 /// exceeds the system defined limit.
200 ///
201 /// This is used for cloud service only.
202 RequestSizeLimitExceeded = 8,
203
204 /// TableExists error represents the operation attempted to create a table
205 /// but the named table already exists.
206 TableExists = 9,
207
208 /// IndexExists error represents the operation attempted to create an index
209 /// for a table but the named index already exists.
210 IndexExists = 10,
211
212 /// InvalidAuthorization error represents the client provides an invalid
213 /// authorization string in the request header.
214 InvalidAuthorization = 11,
215
216 /// InsufficientPermission error represents an application does not have
217 /// sufficient permission to perform a request.
218 InsufficientPermission = 12,
219
220 /// ResourceExists error represents the operation attempted to create a
221 /// resource but it already exists.
222 ResourceExists = 13,
223
224 /// ResourceNotFound error represents the operation attempted to access a
225 /// resource that does not exist or is not in a visible state.
226 ResourceNotFound = 14,
227
228 /// TableLimitExceeded error represents an attempt has been made to create a
229 /// number of tables that exceeds the system defined limit.
230 ///
231 /// This is used for cloud service only.
232 TableLimitExceeded = 15,
233
234 /// IndexLimitExceeded error represents an attempt has been made to create
235 /// more indexes on a table than the system defined limit.
236 ///
237 /// This is used for cloud service only.
238 IndexLimitExceeded = 16,
239
240 /// BadProtocolMessage error represents there is an error in the protocol
241 /// used by client and server to exchange informations.
242 /// This error is not visible to applications. It is wrapped as an IllegalArgument
243 /// error and returned to applications.
244 BadProtocolMessage = 17,
245
246 /// EvolutionLimitExceeded error represents an attempt has been made to evolve
247 /// the schema of a table more times than allowed by the system defined limit.
248 ///
249 /// This is used for cloud service only.
250 EvolutionLimitExceeded = 18,
251
252 /// TableDeploymentLimitExceeded error represents an attempt has been made to
253 /// create or modify a table using limits that exceed the maximum allowed for
254 /// a single table.
255 ///
256 /// This is system-defined limit, used for cloud service only.
257 TableDeploymentLimitExceeded = 19,
258
259 /// TenantDeploymentLimitExceeded error represents an attempt has been made to
260 /// create or modify a table using limits that cause the tenant's aggregate
261 /// resources to exceed the maximum allowed for a tenant.
262 ///
263 /// This is system-defined limit, used for cloud service only.
264 TenantDeploymentLimitExceeded = 20,
265
266 /// OperationNotSupported error represents the operation attempted is not supported.
267 /// This may be related to on-premise vs cloud service configurations.
268 OperationNotSupported = 21,
269
270 /// EtagMismatch is used only by the cloud REST service.
271 EtagMismatch = 22,
272
273 /// CannotCancelWorkRequest is used only by the cloud REST service.
274 CannotCancelWorkRequest = 23,
275
276 /// UnsupportedProtocol error indicates the server does not support the
277 /// given driver protocol version. The driver should decrement its internal
278 /// protocol version (and accompanying logic) and try again.
279 UnsupportedProtocol = 24,
280
281 /// ReadLimitExceeded error represents that the provisioned read throughput
282 /// has been exceeded.
283 ///
284 /// Operations resulting in this error can be retried but it is recommended
285 /// that callers use a delay before retrying in order to minimize the chance
286 /// that a retry will also be throttled. Applications should attempt to avoid
287 /// throttling errors by rate limiting themselves to the degree possible.
288 ///
289 /// Retries and behavior related to throttling can be managed by configuring
290 /// the DefaultRetryHandler for client or by providing a custom implementation
291 /// of the RetryHandler interface for client.
292 ///
293 /// This is used for cloud service only.
294 ReadLimitExceeded = 50,
295
296 /// WriteLimitExceeded error represents that the provisioned write throughput
297 /// has been exceeded.
298 ///
299 /// Operations resulting in this error can be retried but it is recommended
300 /// that callers use a delay before retrying in order to minimize the chance
301 /// that a retry will also be throttled. Applications should attempt to avoid
302 /// throttling errors by rate limiting themselves to the degree possible.
303 ///
304 /// Retries and behavior related to throttling can be managed by configuring
305 /// the DefaultRetryHandler for client or by providing a custom implementation
306 /// of the RetryHandler interface for client.
307 ///
308 /// This is used for cloud service only.
309 WriteLimitExceeded = 51,
310
311 /// SizeLimitExceeded error represents a table size limit has been exceeded
312 /// by writing more data than the table can support.
313 /// This error is not retryable because the conditions that lead to it being
314 /// retuned, while potentially transient, typically require user intervention.
315 SizeLimitExceeded = 52,
316
317 /// OperationLimitExceeded error represents the operation attempted has exceeded
318 /// the allowed limits for non-data operations defined by the system.
319 ///
320 /// This error is returned when a non-data operation is throttled.
321 /// This can happen if an application attempts too many control operations
322 /// such as table creation, deletion, or similar methods. Such operations
323 /// do not use throughput or capacity provisioned for a given table but they
324 /// consume system resources and their use is limited.
325 ///
326 /// Operations resulting in this error can be retried but it is recommended
327 /// that callers use a relatively large delay before retrying in order to
328 /// minimize the chance that a retry will also be throttled.
329 ///
330 /// This is used for cloud service only.
331 OperationLimitExceeded = 53,
332
333 /// RequestTimeout error represents the request cannot be processed or does
334 /// not complete when the specified timeout duration elapses.
335 ///
336 /// If a retry handler is configured for the client it is possible that the
337 /// request has been retried a number of times before the timeout occurs.
338 RequestTimeout = 100,
339
340 /// ServerError represents there is an internal system problem.
341 /// Most system problems are temporary.
342 /// The operation that leads to this error may need to retry.
343 ServerError = 101,
344
345 /// ServiceUnavailable error represents the requested service is currently unavailable.
346 /// This is usually a temporary error.
347 /// The operation that leads to this error may need to retry.
348 ServiceUnavailable = 102,
349
350 /// TableBusy error represents the table is in use or busy.
351 /// This error may be returned when a table operation fails.
352 /// Note that only one modification operation at a time is allowed on a table.
353 TableBusy = 103,
354
355 /// SecurityInfoUnavailable error represents the security information is not
356 /// ready in the system.
357 /// This error will occur as the system acquires security information and
358 /// must be retried in order for authorization to work properly.
359 ///
360 /// This is used for cloud service only.
361 SecurityInfoUnavailable = 104,
362
363 /// RetryAuthentication error represents the authentication failed and may need to retry.
364 /// This may be returned by kvstore.AccessTokenProvider in the following cases:
365 ///
366 /// 1. Authentication information was not provided in the request header.
367 /// 2. The user session has expired. By default kvstore.AccessTokenProvider
368 /// will automatically retry authentication with user credentials provided.
369 ///
370 RetryAuthentication = 105,
371
372 /// UnknownError represents an unknown error has occurred on the server.
373 UnknownError = 125,
374
375 /// IllegalState error represents an illegal state.
376 IllegalState = 126,
377
378 /// InternalRetry is used internally for retry logic.
379 InternalRetry = 1001,
380}