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}