oracle_rs/
capabilities.rs1use crate::constants::{
7 accept_flags, ccap_index, ccap_value, charset, rcap_index, rcap_value, service_options,
8 version,
9};
10
11pub const DRIVER_NAME: &str = "oracle-rs : 0.1.0";
13
14#[derive(Debug, Clone)]
16pub struct Capabilities {
17 pub protocol_version: u16,
19 pub protocol_options: u16,
21 pub charset_id: u16,
23 pub ncharset_id: u16,
25 pub compile_caps: Vec<u8>,
27 pub runtime_caps: Vec<u8>,
29 pub ttc_field_version: u8,
31 pub sdu: u32,
33 pub max_string_size: u32,
35 pub supports_fast_auth: bool,
37 pub supports_oob: bool,
39 pub supports_end_of_response: bool,
41 pub supports_pipelining: bool,
43 pub supports_request_boundaries: bool,
45 pub combo_key: Option<Vec<u8>>,
47}
48
49impl Default for Capabilities {
50 fn default() -> Self {
51 Self::new()
52 }
53}
54
55impl Capabilities {
56 pub fn new() -> Self {
58 let mut caps = Self {
59 protocol_version: 0,
60 protocol_options: 0,
61 charset_id: charset::UTF8,
62 ncharset_id: charset::UTF16,
63 compile_caps: vec![0; ccap_index::MAX],
64 runtime_caps: vec![0; rcap_index::MAX],
65 ttc_field_version: ccap_value::FIELD_VERSION_MAX,
66 sdu: 8192,
67 max_string_size: 4000,
68 supports_fast_auth: false,
69 supports_oob: false,
70 supports_end_of_response: false,
71 supports_pipelining: false,
72 supports_request_boundaries: false,
73 combo_key: None,
74 };
75
76 caps.init_compile_caps();
77 caps.init_runtime_caps();
78 caps
79 }
80
81 fn init_compile_caps(&mut self) {
83 use ccap_index::*;
84 use ccap_value::*;
85
86 self.compile_caps[SQL_VERSION] = SQL_VERSION_MAX;
87
88 self.compile_caps[LOGON_TYPES] =
89 O5LOGON | O5LOGON_NP | O7LOGON | O8LOGON_LONG_IDENTIFIER | O9LOGON_LONG_PASSWORD;
90
91 self.compile_caps[FEATURE_BACKPORT] = CTB_IMPLICIT_POOL | CTB_OAUTH_MSG_ON_ERR;
92
93 self.compile_caps[FIELD_VERSION] = self.ttc_field_version;
94
95 self.compile_caps[SERVER_DEFINE_CONV] = 1;
96 self.compile_caps[DEQUEUE_WITH_SELECTOR] = 1;
97
98 self.compile_caps[TTC1] = FAST_BVEC | END_OF_CALL_STATUS | IND_RCD;
99
100 self.compile_caps[OCI1] = FAST_SESSION_PROPAGATE | APP_CTX_PIGGYBACK;
101
102 self.compile_caps[TDS_VERSION] = TDS_VERSION_MAX;
103 self.compile_caps[RPC_VERSION] = RPC_VERSION_MAX;
104 self.compile_caps[RPC_SIG] = RPC_SIG_VALUE;
105 self.compile_caps[DBF_VERSION] = DBF_VERSION_MAX;
106
107 self.compile_caps[LOB] = LOB_UB8_SIZE
108 | LOB_ENCS
109 | LOB_PREFETCH_LENGTH
110 | LOB_TEMP_SIZE
111 | LOB_12C
112 | LOB_PREFETCH_DATA;
113
114 self.compile_caps[UB2_DTY] = 1;
115
116 self.compile_caps[LOB2] = LOB2_QUASI | LOB2_2GB_PREFETCH;
117
118 self.compile_caps[TTC3] = IMPLICIT_RESULTS | BIG_CHUNK_CLR | KEEP_OUT_ORDER | LTXID;
119
120 self.compile_caps[TTC2] = ZLNP;
121
122 self.compile_caps[OCI2] = DRCP;
123
124 self.compile_caps[OCI3] = OCI3_OCSSYNC;
125
126 self.compile_caps[CLIENT_FN] = CLIENT_FN_MAX;
127
128 self.compile_caps[SESS_SIGNATURE_VERSION] = FIELD_VERSION_12_2;
129
130 self.compile_caps[TTC4] = INBAND_NOTIFICATION | EXPLICIT_BOUNDARY;
131
132 self.compile_caps[TTC5] = VECTOR_SUPPORT
133 | TOKEN_SUPPORTED
134 | PIPELINING_SUPPORT
135 | PIPELINING_BREAK
136 | SESSIONLESS_TXNS;
137
138 self.compile_caps[VECTOR_FEATURES] = VECTOR_FEATURE_BINARY | VECTOR_FEATURE_SPARSE;
139 }
140
141 fn init_runtime_caps(&mut self) {
143 use rcap_index::*;
144 use rcap_value::*;
145
146 self.runtime_caps[COMPAT] = COMPAT_81;
147 self.runtime_caps[TTC] = TTC_ZERO_COPY | TTC_32K;
148 }
149
150 pub fn adjust_for_protocol(
152 &mut self,
153 protocol_version: u16,
154 protocol_options: u16,
155 flags2: u32,
156 ) {
157 self.protocol_version = protocol_version;
158 self.protocol_options = protocol_options;
159
160 self.supports_oob = (protocol_options & service_options::CAN_RECV_ATTENTION) != 0;
162
163 if (flags2 & accept_flags::FAST_AUTH) != 0 {
165 self.supports_fast_auth = true;
166 }
167
168 if protocol_version >= version::MIN_END_OF_RESPONSE
170 && (flags2 & accept_flags::HAS_END_OF_RESPONSE) != 0
171 {
172 self.compile_caps[ccap_index::TTC4] |= ccap_value::END_OF_REQUEST;
173 self.supports_end_of_response = true;
174 self.supports_pipelining = true;
175 }
176 }
177
178 pub fn adjust_for_server_compile_caps(&mut self, server_caps: &[u8]) {
180 if server_caps.len() > ccap_index::FIELD_VERSION {
182 let server_version = server_caps[ccap_index::FIELD_VERSION];
183 if server_version < self.ttc_field_version {
184 self.ttc_field_version = server_version;
185 self.compile_caps[ccap_index::FIELD_VERSION] = server_version;
186 }
187 }
188
189 if server_caps.len() > ccap_index::TTC4 {
191 if (server_caps[ccap_index::TTC4] & ccap_value::EXPLICIT_BOUNDARY) != 0 {
192 self.supports_request_boundaries = true;
193 }
194 }
195
196 if self.ttc_field_version < ccap_value::FIELD_VERSION_23_4 && self.supports_end_of_response
198 {
199 self.compile_caps[ccap_index::TTC4] &= !ccap_value::END_OF_REQUEST;
200 self.supports_end_of_response = false;
201 }
202 }
203
204 pub fn adjust_for_server_runtime_caps(&mut self, server_caps: &[u8]) {
206 if server_caps.len() > rcap_index::TTC {
208 if (server_caps[rcap_index::TTC] & rcap_value::TTC_32K) != 0 {
209 self.max_string_size = 32767;
210 } else {
211 self.max_string_size = 4000;
212 }
213
214 if (server_caps[rcap_index::TTC] & rcap_value::TTC_SESSION_STATE_OPS) == 0 {
216 self.supports_request_boundaries = false;
217 }
218 }
219 }
220
221 pub fn check_ncharset_id(&self) -> crate::error::Result<()> {
223 if self.ncharset_id != charset::UTF16 && self.ncharset_id != charset::AL16UTF8 {
224 return Err(crate::error::Error::FeatureNotSupported(format!(
225 "national character set {} is not supported (only UTF16 and AL16UTF8)",
226 self.ncharset_id
227 )));
228 }
229 Ok(())
230 }
231
232 pub fn supports_bool(&self) -> bool {
234 self.ttc_field_version >= ccap_value::FIELD_VERSION_23_1
235 }
236
237 pub fn supports_large_oson_fname(&self) -> bool {
239 self.ttc_field_version >= ccap_value::FIELD_VERSION_23_1
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246
247 #[test]
248 fn test_capabilities_default() {
249 let caps = Capabilities::new();
250
251 assert_eq!(caps.charset_id, charset::UTF8);
252 assert_eq!(caps.ncharset_id, charset::UTF16);
253 assert_eq!(caps.compile_caps.len(), ccap_index::MAX);
254 assert_eq!(caps.runtime_caps.len(), rcap_index::MAX);
255 assert_eq!(caps.ttc_field_version, ccap_value::FIELD_VERSION_MAX);
256 assert!(!caps.supports_fast_auth);
257 assert!(!caps.supports_oob);
258 }
259
260 #[test]
261 fn test_compile_caps_initialization() {
262 let caps = Capabilities::new();
263
264 assert_eq!(
265 caps.compile_caps[ccap_index::SQL_VERSION],
266 ccap_value::SQL_VERSION_MAX
267 );
268 assert_eq!(
269 caps.compile_caps[ccap_index::FIELD_VERSION],
270 ccap_value::FIELD_VERSION_MAX
271 );
272 assert_ne!(caps.compile_caps[ccap_index::LOGON_TYPES], 0);
273 assert_ne!(caps.compile_caps[ccap_index::TTC1], 0);
274 }
275
276 #[test]
277 fn test_runtime_caps_initialization() {
278 let caps = Capabilities::new();
279
280 assert_eq!(caps.runtime_caps[rcap_index::COMPAT], rcap_value::COMPAT_81);
281 assert_ne!(caps.runtime_caps[rcap_index::TTC], 0);
282 }
283
284 #[test]
285 fn test_adjust_for_protocol() {
286 let mut caps = Capabilities::new();
287
288 caps.adjust_for_protocol(
290 319,
291 service_options::CAN_RECV_ATTENTION,
292 accept_flags::FAST_AUTH | accept_flags::HAS_END_OF_RESPONSE,
293 );
294
295 assert_eq!(caps.protocol_version, 319);
296 assert!(caps.supports_fast_auth);
297 assert!(caps.supports_oob);
298 assert!(caps.supports_end_of_response);
299 assert!(caps.supports_pipelining);
300 }
301
302 #[test]
303 fn test_adjust_for_protocol_no_features() {
304 let mut caps = Capabilities::new();
305
306 caps.adjust_for_protocol(315, 0, 0);
307
308 assert_eq!(caps.protocol_version, 315);
309 assert!(!caps.supports_fast_auth);
310 assert!(!caps.supports_oob);
311 assert!(!caps.supports_end_of_response);
312 }
313
314 #[test]
315 fn test_adjust_for_server_compile_caps() {
316 let mut caps = Capabilities::new();
317
318 let mut server_caps = vec![0; ccap_index::MAX];
320 server_caps[ccap_index::FIELD_VERSION] = ccap_value::FIELD_VERSION_12_2;
321
322 caps.adjust_for_server_compile_caps(&server_caps);
323
324 assert_eq!(caps.ttc_field_version, ccap_value::FIELD_VERSION_12_2);
325 assert_eq!(
326 caps.compile_caps[ccap_index::FIELD_VERSION],
327 ccap_value::FIELD_VERSION_12_2
328 );
329 }
330
331 #[test]
332 fn test_adjust_for_server_runtime_caps() {
333 let mut caps = Capabilities::new();
334
335 let mut server_caps = vec![0; rcap_index::MAX];
337 server_caps[rcap_index::TTC] = rcap_value::TTC_32K;
338
339 caps.adjust_for_server_runtime_caps(&server_caps);
340
341 assert_eq!(caps.max_string_size, 32767);
342 }
343
344 #[test]
345 fn test_adjust_for_server_runtime_caps_no_32k() {
346 let mut caps = Capabilities::new();
347
348 let server_caps = vec![0; rcap_index::MAX];
350
351 caps.adjust_for_server_runtime_caps(&server_caps);
352
353 assert_eq!(caps.max_string_size, 4000);
354 }
355
356 #[test]
357 fn test_check_ncharset_id_valid() {
358 let mut caps = Capabilities::new();
359
360 caps.ncharset_id = charset::UTF16;
361 assert!(caps.check_ncharset_id().is_ok());
362
363 caps.ncharset_id = charset::AL16UTF8;
364 assert!(caps.check_ncharset_id().is_ok());
365 }
366
367 #[test]
368 fn test_check_ncharset_id_invalid() {
369 let mut caps = Capabilities::new();
370
371 caps.ncharset_id = 999;
372 assert!(caps.check_ncharset_id().is_err());
373 }
374
375 #[test]
376 fn test_supports_bool() {
377 let mut caps = Capabilities::new();
378
379 caps.ttc_field_version = ccap_value::FIELD_VERSION_23_1;
380 assert!(caps.supports_bool());
381
382 caps.ttc_field_version = ccap_value::FIELD_VERSION_12_2;
383 assert!(!caps.supports_bool());
384 }
385}