pub struct Environment { /* private fields */ }
Expand description

An Environment is a global context, in which to access data.

Associated with an Environment is any information that is global in nature, such as:

  • The Environment’s state
  • The current environment-level diagnostics
  • The handles of connections currently allocated on the environment
  • The current stetting of each environment attribute

Implementations§

Enable or disable (default) connection pooling for ODBC connections. Call this function before creating the ODBC environment for which you want to enable connection pooling.

See: https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/driver-manager-connection-pooling

Safety

An ODBC driver must be fully thread-safe, and connections must not have thread affinity to support connection pooling. This means the driver is able to handle a call on any thread at any time and is able to connect on one thread, to use the connection on another thread, and to disconnect on a third thread.

Examples found in repository?
src/environment.rs (line 97)
94
95
96
97
98
99
100
101
102
103
104
    pub unsafe fn set_connection_pooling(
        scheme: odbc_sys::AttrConnectionPooling,
    ) -> Result<(), Error> {
        match handles::Environment::set_connection_pooling(scheme) {
            SqlResult::Error { .. } => Err(Error::FailedSettingConnectionPooling),
            SqlResult::Success(()) | SqlResult::SuccessWithInfo(()) => Ok(()),
            other => {
                panic!("Unexpected return value `{:?}`.", other)
            }
        }
    }
Examples found in repository?
src/environment.rs (line 122)
120
121
122
123
124
    pub fn set_connection_pooling_matching(&mut self, matching: AttrCpMatch) -> Result<(), Error> {
        self.environment
            .set_connection_pooling_matching(matching)
            .into_result(&self.environment)
    }

An allocated ODBC Environment handle

Examples found in repository?
src/environment.rs (line 139)
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
    pub fn new() -> Result<Self, Error> {
        let result = handles::Environment::new();

        let environment = match result {
            SqlResult::Success(env) => env,
            SqlResult::SuccessWithInfo(env) => {
                log_diagnostics(&env);
                env
            }
            SqlResult::Error { .. } => return Err(Error::FailedAllocatingEnvironment),
            other => panic!("Unexpected return value '{:?}'", other),
        };

        debug!("ODBC Environment created.");

        let result = environment
            .declare_version(ODBC_API_VERSION)
            .into_result(&environment);

        // Translate invalid attribute into a more meaningful error, provided the additional
        // context that we know we tried to set version number.
        result.provide_context_for_diagnostic(|record, function| match record.state {
            // INVALID_STATE_TRANSACTION has been seen with some really old version of unixODBC on
            // a CentOS used to build manylinux wheels, with the preinstalled ODBC version.
            // INVALID_ATTRIBUTE_VALUE is the correct status code to emit for a driver manager if it
            // does not know the version and has been seen with an unknown version of unixODBC on an
            // Oracle Linux.
            State::INVALID_STATE_TRANSACTION | State::INVALID_ATTRIBUTE_VALUE => {
                Error::UnsupportedOdbcApiVersion(record)
            }
            _ => Error::Diagnostics { record, function },
        })?;

        Ok(Self {
            environment,
            internal_state: Mutex::new(()),
        })
    }

Declares which Version of the ODBC API we want to use. This is the first thing that should be done with any ODBC environment.

Examples found in repository?
src/environment.rs (line 154)
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
    pub fn new() -> Result<Self, Error> {
        let result = handles::Environment::new();

        let environment = match result {
            SqlResult::Success(env) => env,
            SqlResult::SuccessWithInfo(env) => {
                log_diagnostics(&env);
                env
            }
            SqlResult::Error { .. } => return Err(Error::FailedAllocatingEnvironment),
            other => panic!("Unexpected return value '{:?}'", other),
        };

        debug!("ODBC Environment created.");

        let result = environment
            .declare_version(ODBC_API_VERSION)
            .into_result(&environment);

        // Translate invalid attribute into a more meaningful error, provided the additional
        // context that we know we tried to set version number.
        result.provide_context_for_diagnostic(|record, function| match record.state {
            // INVALID_STATE_TRANSACTION has been seen with some really old version of unixODBC on
            // a CentOS used to build manylinux wheels, with the preinstalled ODBC version.
            // INVALID_ATTRIBUTE_VALUE is the correct status code to emit for a driver manager if it
            // does not know the version and has been seen with an unknown version of unixODBC on an
            // Oracle Linux.
            State::INVALID_STATE_TRANSACTION | State::INVALID_ATTRIBUTE_VALUE => {
                Error::UnsupportedOdbcApiVersion(record)
            }
            _ => Error::Diagnostics { record, function },
        })?;

        Ok(Self {
            environment,
            internal_state: Mutex::new(()),
        })
    }

Allocate a new connection handle. The Connection must not outlive the Environment.

Examples found in repository?
src/environment.rs (line 618)
614
615
616
617
618
619
620
    fn allocate_connection(&self) -> Result<handles::Connection, Error> {
        // Hold lock diagnostics errors are consumed in this thread.
        let _lock = self.internal_state.lock().unwrap();
        self.environment
            .allocate_connection()
            .into_result(&self.environment)
    }

Provides access to the raw ODBC environment handle.

List drivers descriptions and driver attribute keywords. Returns NoData to indicate the end of the list.

Safety

Callers need to make sure only one thread is iterating over driver information at a time. Method changes environment state. This method would be safe to call via an exclusive &mut reference, yet that would restrict usecases. E.g. requesting information would only be possible before connections borrow a reference.

Parameters
  • direction: Determines whether the Driver Manager fetches the next driver in the list (FetchOrientation::Next) or whether the search starts from the beginning of the list (FetchOrientation::First).
  • buffer_description: In case true is returned this buffer is filled with the description of the driver.
  • buffer_attributes: In case true is returned this buffer is filled with a list of key value attributes. E.g.: "key1=value1\0key2=value2\0\0".

Use Environment::drivers_buffer_len to determine buffer lengths.

See SQLDrivers

Examples found in repository?
src/environment.rs (lines 478-482)
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
    pub fn drivers(&self) -> Result<Vec<DriverInfo>, Error> {
        let mut driver_info = Vec::new();

        // Since we have exclusive ownership of the environment handle and we take the lock, we can
        // guarantee that this method is currently the only one changing the state of the internal
        // iterators of the environment.
        let _lock = self.internal_state.lock().unwrap();
        unsafe {
            // Find required buffer size to avoid truncation.
            let (mut desc_len, mut attr_len) = if let Some(res) = self
                .environment
                // Start with first so we are independent of state
                .drivers_buffer_len(FetchOrientation::First)
                .into_result_option(&self.environment)?
            {
                res
            } else {
                // No drivers present
                return Ok(Vec::new());
            };

            // If there are, let's loop over the remaining drivers
            while let Some((candidate_desc_len, candidate_attr_len)) = self
                .environment
                .drivers_buffer_len(FetchOrientation::Next)
                .into_result_option(&self.environment)?
            {
                desc_len = max(candidate_desc_len, desc_len);
                attr_len = max(candidate_attr_len, attr_len);
            }

            // Allocate +1 character extra for terminating zero
            let mut desc_buf = SzBuffer::with_capacity(desc_len as usize);
            let mut attr_buf = SzBuffer::with_capacity(attr_len as usize);

            while self
                .environment
                .drivers_buffer_fill(
                    FetchOrientation::Next,
                    desc_buf.mut_buf(),
                    attr_buf.mut_buf(),
                )
                .into_result_bool(&self.environment)?
            {
                let description = desc_buf.to_utf8();
                let attributes = attr_buf.to_utf8();

                let attributes = attributes_iter(&attributes).collect();

                driver_info.push(DriverInfo {
                    description,
                    attributes,
                });
            }
        }

        Ok(driver_info)
    }

Use together with Environment::drivers_buffer_fill to list drivers descriptions and driver attribute keywords.

Safety

Callers need to make sure only one thread is iterating over driver information at a time. Method changes environment state. This method would be safe to call via an exclusive &mut reference, yet that would restrict usecases. E.g. requesting information would only be possible before connections borrow a reference.

Parameters
Return

(driver description length, attribute length). Length is in characters minus terminating terminating zero.

See SQLDrivers

Examples found in repository?
src/environment.rs (line 453)
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
    pub fn drivers(&self) -> Result<Vec<DriverInfo>, Error> {
        let mut driver_info = Vec::new();

        // Since we have exclusive ownership of the environment handle and we take the lock, we can
        // guarantee that this method is currently the only one changing the state of the internal
        // iterators of the environment.
        let _lock = self.internal_state.lock().unwrap();
        unsafe {
            // Find required buffer size to avoid truncation.
            let (mut desc_len, mut attr_len) = if let Some(res) = self
                .environment
                // Start with first so we are independent of state
                .drivers_buffer_len(FetchOrientation::First)
                .into_result_option(&self.environment)?
            {
                res
            } else {
                // No drivers present
                return Ok(Vec::new());
            };

            // If there are, let's loop over the remaining drivers
            while let Some((candidate_desc_len, candidate_attr_len)) = self
                .environment
                .drivers_buffer_len(FetchOrientation::Next)
                .into_result_option(&self.environment)?
            {
                desc_len = max(candidate_desc_len, desc_len);
                attr_len = max(candidate_attr_len, attr_len);
            }

            // Allocate +1 character extra for terminating zero
            let mut desc_buf = SzBuffer::with_capacity(desc_len as usize);
            let mut attr_buf = SzBuffer::with_capacity(attr_len as usize);

            while self
                .environment
                .drivers_buffer_fill(
                    FetchOrientation::Next,
                    desc_buf.mut_buf(),
                    attr_buf.mut_buf(),
                )
                .into_result_bool(&self.environment)?
            {
                let description = desc_buf.to_utf8();
                let attributes = attr_buf.to_utf8();

                let attributes = attributes_iter(&attributes).collect();

                driver_info.push(DriverInfo {
                    description,
                    attributes,
                });
            }
        }

        Ok(driver_info)
    }

    /// User and system data sources
    ///
    /// # Example
    ///
    /// ```no_run
    /// use odbc_api::Environment;
    ///
    /// let env = Environment::new()?;
    /// for data_source in env.data_sources()? {
    ///     println!("{:#?}", data_source);
    /// }
    ///
    /// # Ok::<_, odbc_api::Error>(())
    /// ```
    pub fn data_sources(&self) -> Result<Vec<DataSourceInfo>, Error> {
        self.data_sources_impl(FetchOrientation::First)
    }

    /// Only system data sources
    ///
    /// # Example
    ///
    /// ```no_run
    /// use odbc_api::Environment;
    ///
    /// let env = Environment::new ()?;
    /// for data_source in env.system_data_sources()? {
    ///     println!("{:#?}", data_source);
    /// }
    ///
    /// # Ok::<_, odbc_api::Error>(())
    /// ```
    pub fn system_data_sources(&self) -> Result<Vec<DataSourceInfo>, Error> {
        self.data_sources_impl(FetchOrientation::FirstSystem)
    }

    /// Only user data sources
    ///
    /// # Example
    ///
    /// ```no_run
    /// use odbc_api::Environment;
    ///
    /// let mut env = unsafe { Environment::new () }?;
    /// for data_source in env.user_data_sources()? {
    ///     println!("{:#?}", data_source);
    /// }
    ///
    /// # Ok::<_, odbc_api::Error>(())
    /// ```
    pub fn user_data_sources(&self) -> Result<Vec<DataSourceInfo>, Error> {
        self.data_sources_impl(FetchOrientation::FirstUser)
    }

    fn data_sources_impl(&self, direction: FetchOrientation) -> Result<Vec<DataSourceInfo>, Error> {
        let mut data_source_info = Vec::new();

        // Since we have exclusive ownership of the environment handle and we take the lock, we can
        // guarantee that this method is currently the only one changing the state of the internal
        // iterators of the environment.
        let _lock = self.internal_state.lock().unwrap();
        unsafe {
            // Find required buffer size to avoid truncation.
            let (mut server_name_len, mut driver_len) = if let Some(res) = self
                .environment
                .data_source_buffer_len(direction)
                .into_result_option(&self.environment)?
            {
                res
            } else {
                // No drivers present
                return Ok(Vec::new());
            };

            // If there are let's loop over the rest
            while let Some((candidate_name_len, candidate_decs_len)) = self
                .environment
                .drivers_buffer_len(FetchOrientation::Next)
                .into_result_option(&self.environment)?
            {
                server_name_len = max(candidate_name_len, server_name_len);
                driver_len = max(candidate_decs_len, driver_len);
            }

            let mut server_name_buf = SzBuffer::with_capacity(server_name_len as usize);
            let mut driver_buf = SzBuffer::with_capacity(driver_len as usize);

            let mut not_empty = self
                .environment
                .data_source_buffer_fill(direction, server_name_buf.mut_buf(), driver_buf.mut_buf())
                .into_result_bool(&self.environment)?;

            while not_empty {
                let server_name = server_name_buf.to_utf8();
                let driver = driver_buf.to_utf8();

                data_source_info.push(DataSourceInfo {
                    server_name,
                    driver,
                });
                not_empty = self
                    .environment
                    .data_source_buffer_fill(
                        FetchOrientation::Next,
                        server_name_buf.mut_buf(),
                        driver_buf.mut_buf(),
                    )
                    .into_result_bool(&self.environment)?;
            }
        }

        Ok(data_source_info)
    }

Use together with Environment::data_source_buffer_fill to list drivers descriptions and driver attribute keywords.

Safety

Callers need to make sure only one thread is iterating over data source information at a time. Method changes environment state. This method would be safe to call via an exclusive &mut reference, yet that would restrict usecases. E.g. requesting information would only be possible before connections borrow a reference.

Parameters
Return

(server name length, description length). Length is in characters minus terminating zero.

Examples found in repository?
src/environment.rs (line 565)
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
    fn data_sources_impl(&self, direction: FetchOrientation) -> Result<Vec<DataSourceInfo>, Error> {
        let mut data_source_info = Vec::new();

        // Since we have exclusive ownership of the environment handle and we take the lock, we can
        // guarantee that this method is currently the only one changing the state of the internal
        // iterators of the environment.
        let _lock = self.internal_state.lock().unwrap();
        unsafe {
            // Find required buffer size to avoid truncation.
            let (mut server_name_len, mut driver_len) = if let Some(res) = self
                .environment
                .data_source_buffer_len(direction)
                .into_result_option(&self.environment)?
            {
                res
            } else {
                // No drivers present
                return Ok(Vec::new());
            };

            // If there are let's loop over the rest
            while let Some((candidate_name_len, candidate_decs_len)) = self
                .environment
                .drivers_buffer_len(FetchOrientation::Next)
                .into_result_option(&self.environment)?
            {
                server_name_len = max(candidate_name_len, server_name_len);
                driver_len = max(candidate_decs_len, driver_len);
            }

            let mut server_name_buf = SzBuffer::with_capacity(server_name_len as usize);
            let mut driver_buf = SzBuffer::with_capacity(driver_len as usize);

            let mut not_empty = self
                .environment
                .data_source_buffer_fill(direction, server_name_buf.mut_buf(), driver_buf.mut_buf())
                .into_result_bool(&self.environment)?;

            while not_empty {
                let server_name = server_name_buf.to_utf8();
                let driver = driver_buf.to_utf8();

                data_source_info.push(DataSourceInfo {
                    server_name,
                    driver,
                });
                not_empty = self
                    .environment
                    .data_source_buffer_fill(
                        FetchOrientation::Next,
                        server_name_buf.mut_buf(),
                        driver_buf.mut_buf(),
                    )
                    .into_result_bool(&self.environment)?;
            }
        }

        Ok(data_source_info)
    }

List drivers descriptions and driver attribute keywords.

Safety

Callers need to make sure only one thread is iterating over data source information at a time. Method changes environment state. This method would be safe to call via an exclusive &mut reference, yet that would restrict usecases. E.g. requesting information would only be possible before connections borrow a reference. SqlResult::NoData

Parameters

Use Environment::data_source_buffer_len to determine buffer lengths.

Examples found in repository?
src/environment.rs (line 589)
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
    fn data_sources_impl(&self, direction: FetchOrientation) -> Result<Vec<DataSourceInfo>, Error> {
        let mut data_source_info = Vec::new();

        // Since we have exclusive ownership of the environment handle and we take the lock, we can
        // guarantee that this method is currently the only one changing the state of the internal
        // iterators of the environment.
        let _lock = self.internal_state.lock().unwrap();
        unsafe {
            // Find required buffer size to avoid truncation.
            let (mut server_name_len, mut driver_len) = if let Some(res) = self
                .environment
                .data_source_buffer_len(direction)
                .into_result_option(&self.environment)?
            {
                res
            } else {
                // No drivers present
                return Ok(Vec::new());
            };

            // If there are let's loop over the rest
            while let Some((candidate_name_len, candidate_decs_len)) = self
                .environment
                .drivers_buffer_len(FetchOrientation::Next)
                .into_result_option(&self.environment)?
            {
                server_name_len = max(candidate_name_len, server_name_len);
                driver_len = max(candidate_decs_len, driver_len);
            }

            let mut server_name_buf = SzBuffer::with_capacity(server_name_len as usize);
            let mut driver_buf = SzBuffer::with_capacity(driver_len as usize);

            let mut not_empty = self
                .environment
                .data_source_buffer_fill(direction, server_name_buf.mut_buf(), driver_buf.mut_buf())
                .into_result_bool(&self.environment)?;

            while not_empty {
                let server_name = server_name_buf.to_utf8();
                let driver = driver_buf.to_utf8();

                data_source_info.push(DataSourceInfo {
                    server_name,
                    driver,
                });
                not_empty = self
                    .environment
                    .data_source_buffer_fill(
                        FetchOrientation::Next,
                        server_name_buf.mut_buf(),
                        driver_buf.mut_buf(),
                    )
                    .into_result_bool(&self.environment)?;
            }
        }

        Ok(data_source_info)
    }

Trait Implementations§

The raw underlying ODBC handle used to talk to the ODBC C API. The handle must be valid.
The type of the ODBC handle returned by as_handle. This is a method rather than a constant in order to make the type object safe.
Formats the value using the given formatter. Read more
Executes the destructor for this type. Read more

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.