Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add type safety for environment attribute values #26

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 141 additions & 17 deletions src/attributes.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
use crate::SQLPOINTER;
use crate::SQLUINTEGER;
use crate::SQL_INFO;
use std::convert::TryFrom;

pub use EnvironmentAttribute::*;
pub use SQL_ATTR_CONNECTION_POOLING::*;
pub use SQL_ATTR_CP_MATCH::*;
pub use SQL_ATTR_ODBC_VERSION::*;

/// Environment attribute value
#[repr(transparent)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct EnvAttributeValue(SQLPOINTER);
impl EnvAttributeValue {
// Not required to be public
#[allow(non_snake_case)]
fn into_SQLUINTEGER(self) -> SQLUINTEGER {
self.0 as SQLUINTEGER
}
fn into_i32(self) -> i32 {
self.0 as i32
}
}

/// Governs behaviour of EnvironmentAttribute
#[repr(i32)]
#[allow(non_camel_case_types)]
Expand All @@ -25,7 +43,6 @@ pub enum EnvironmentAttribute {
///
/// Possible values for `SQL_ATTR_ODBC_VERSION` attribute set with `SQLSetEnvAttr` to
/// declare ODBC version
#[repr(i32)]
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum SQL_ATTR_ODBC_VERSION {
Expand All @@ -37,17 +54,38 @@ pub enum SQL_ATTR_ODBC_VERSION {
#[cfg(feature = "odbc_version_4")]
SQL_OV_ODBC4 = 400,
}
impl SQL_ATTR_ODBC_VERSION {
#[inline]
// Not required to be public
fn into_i32(self) -> i32 {
self as i32
}
}
impl From<SQL_ATTR_ODBC_VERSION> for EnvAttributeValue {
fn from(source: SQL_ATTR_ODBC_VERSION) -> Self {
Self(source.into_i32() as SQLPOINTER)
}
}
impl TryFrom<EnvAttributeValue> for SQL_ATTR_ODBC_VERSION {
type Error = EnvAttributeValue;

impl From<SQL_ATTR_ODBC_VERSION> for SQLPOINTER {
fn from(source: SQL_ATTR_ODBC_VERSION) -> SQLPOINTER {
source as i32 as SQLPOINTER
fn try_from(source: EnvAttributeValue) -> Result<Self, Self::Error> {
match source {
x if x.into_i32() == SQL_OV_ODBC3.into_i32() => Ok(SQL_OV_ODBC3),
#[cfg(feature = "odbc_version_3_80")]
x if x.into_i32() == SQL_OV_ODBC3_80.into_i32() => Ok(SQL_OV_ODBC3_80),
#[cfg(feature = "odbc_version_4")]
x if x.into_i32() == SQL_OV_ODBC4.into_i32() => Ok(SQL_OV_ODBC4),

unknown => Err(unknown),
}
}
}

/// Connection pool configuration
///
/// Possible values for `SQL_ATTR_CONNECTION_POOLING` attribute set with `SQLSetEnvAttr` to define
/// which pooling scheme will be used
#[repr(u32)]
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum SQL_ATTR_CONNECTION_POOLING {
Expand All @@ -56,45 +94,131 @@ pub enum SQL_ATTR_CONNECTION_POOLING {
SQL_CP_ONE_PER_HENV = 2,
SQL_CP_DRIVER_AWARE = 3,
}

impl SQL_ATTR_CONNECTION_POOLING {
// Not required to be public
#[inline]
#[allow(non_snake_case)]
fn into_SQLUINTEGER(self) -> SQLUINTEGER {
self as SQLUINTEGER
}
}
/// Connection pool default configuration
pub const SQL_CP_DEFAULT: SQL_ATTR_CONNECTION_POOLING = SQL_ATTR_CONNECTION_POOLING::SQL_CP_OFF;

pub use SQL_CP_OFF as SQL_CP_DEFAULT;
impl Default for SQL_ATTR_CONNECTION_POOLING {
fn default() -> Self {
SQL_CP_DEFAULT
}
}
impl From<SQL_ATTR_CONNECTION_POOLING> for EnvAttributeValue {
fn from(source: SQL_ATTR_CONNECTION_POOLING) -> Self {
Self(source.into_SQLUINTEGER() as SQLPOINTER)
}
}
impl TryFrom<EnvAttributeValue> for SQL_ATTR_CONNECTION_POOLING {
type Error = EnvAttributeValue;

impl From<SQL_ATTR_CONNECTION_POOLING> for SQLPOINTER {
fn from(source: SQL_ATTR_CONNECTION_POOLING) -> SQLPOINTER {
source as u32 as SQLPOINTER
fn try_from(source: EnvAttributeValue) -> Result<Self, Self::Error> {
match source {
x if x.into_SQLUINTEGER() == SQL_CP_OFF.into_SQLUINTEGER() => Ok(SQL_CP_OFF),
x if x.into_SQLUINTEGER() == SQL_CP_ONE_PER_DRIVER.into_SQLUINTEGER() => {
Ok(SQL_CP_ONE_PER_DRIVER)
}
x if x.into_SQLUINTEGER() == SQL_CP_ONE_PER_HENV.into_SQLUINTEGER() => {
Ok(SQL_CP_ONE_PER_HENV)
}
x if x.into_SQLUINTEGER() == SQL_CP_DRIVER_AWARE.into_SQLUINTEGER() => {
Ok(SQL_CP_DRIVER_AWARE)
}

unknown => Err(unknown),
}
}
}

/// Matching of pooled connections
///
/// Possible values for `SQL_ATTR_CP_MATCH` attribute set with `SQLSetEnvAttr` to define
/// which connection attributes must match for a connection returned from the pool
#[repr(u32)]
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum SQL_ATTR_CP_MATCH {
SQL_CP_STRICT_MATCH = 0,
SQL_CP_RELAXED_MATCH = 1,
}
impl SQL_ATTR_CP_MATCH {
// Not required to be public
#[inline]
#[allow(non_snake_case)]
fn into_SQLUINTEGER(self) -> SQLUINTEGER {
self as SQLUINTEGER
}
}

/// Default matching for connections returned from the pool
pub const SQL_CP_MATCH_DEFAULT: SQL_ATTR_CP_MATCH = SQL_ATTR_CP_MATCH::SQL_CP_STRICT_MATCH;

pub use SQL_CP_STRICT_MATCH as SQL_CP_MATCH_DEFAULT;
impl Default for SQL_ATTR_CP_MATCH {
fn default() -> Self {
SQL_CP_MATCH_DEFAULT
}
}
impl From<SQL_ATTR_CP_MATCH> for EnvAttributeValue {
fn from(source: SQL_ATTR_CP_MATCH) -> Self {
Self(source.into_SQLUINTEGER() as SQLPOINTER)
}
}
impl TryFrom<EnvAttributeValue> for SQL_ATTR_CP_MATCH {
type Error = EnvAttributeValue;

fn try_from(source: EnvAttributeValue) -> Result<Self, Self::Error> {
match source {
x if x.into_SQLUINTEGER() == SQL_CP_STRICT_MATCH.into_SQLUINTEGER() => {
Ok(SQL_CP_STRICT_MATCH)
}
x if x.into_SQLUINTEGER() == SQL_CP_RELAXED_MATCH.into_SQLUINTEGER() => {
Ok(SQL_CP_RELAXED_MATCH)
}

unknown => Err(unknown),
}
}
}

/// Determines how the driver returns string data.
///
/// If `SQL_TRUE`, the driver returns string data null-terminated. If `SQL_FALSE`, the driver does
/// not return string data null-terminated.
#[allow(non_camel_case_types)]
pub type SQL_ATTR_OUTPUT_NTS = SQL_INFO;
impl SQL_ATTR_OUTPUT_NTS {
// Not required to be public
#[inline]
fn into_i32(self) -> i32 {
self as i32
}
}
impl Default for SQL_ATTR_OUTPUT_NTS {
fn default() -> Self {
SQL_ATTR_OUTPUT_NTS::SQL_FALSE
}
}
impl From<SQL_ATTR_OUTPUT_NTS> for EnvAttributeValue {
fn from(source: SQL_ATTR_OUTPUT_NTS) -> Self {
Self(source.into_i32() as SQLPOINTER)
}
}
impl TryFrom<EnvAttributeValue> for SQL_ATTR_OUTPUT_NTS {
type Error = EnvAttributeValue;

fn try_from(source: EnvAttributeValue) -> Result<Self, Self::Error> {
match source {
x if x.into_i32() == SQL_ATTR_OUTPUT_NTS::SQL_FALSE.into_i32() => {
Ok(SQL_ATTR_OUTPUT_NTS::SQL_FALSE)
}
x if x.into_i32() == SQL_ATTR_OUTPUT_NTS::SQL_TRUE.into_i32() => {
Ok(SQL_ATTR_OUTPUT_NTS::SQL_TRUE)
}

impl From<SQL_ATTR_CP_MATCH> for SQLPOINTER {
fn from(source: SQL_ATTR_CP_MATCH) -> SQLPOINTER {
source as u32 as SQLPOINTER
unknown => Err(unknown),
}
}
}
16 changes: 14 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,18 @@ pub const SQL_NULL_DATA: SQLLEN = -1;
pub const SQL_NO_TOTAL: SQLLEN = -4;
pub const SQL_SS_LENGTH_UNLIMITED: SQLULEN = 0;

/// Used to provide info about enabled/supported features, attributes, etc.
///
/// This enum doesn't include #[repr(x)] because it is used as a different type in different
/// functions. If using as raw values users should cast variants of this enum into required types.
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum SQL_INFO {
SQL_FALSE = 0,
SQL_TRUE = 1,
}
pub use SQL_INFO::*;

/// SQL Free Statement options
#[repr(u16)]
#[allow(non_camel_case_types)]
Expand Down Expand Up @@ -492,7 +504,7 @@ extern "system" {
pub fn SQLGetEnvAttr(
environment_handle: SQLHENV,
attribute: EnvironmentAttribute,
value_ptr: SQLPOINTER,
value_ptr: EnvAttributeValue,
buffer_length: SQLINTEGER,
string_length: *mut SQLINTEGER,
) -> SQLRETURN;
Expand All @@ -504,7 +516,7 @@ extern "system" {
pub fn SQLSetEnvAttr(
environment_handle: SQLHENV,
attribute: EnvironmentAttribute,
value: SQLPOINTER,
value: EnvAttributeValue,
string_length: SQLINTEGER,
) -> SQLRETURN;

Expand Down