Skip to content

Commit

Permalink
wipwip
Browse files Browse the repository at this point in the history
  • Loading branch information
Julius de Bruijn committed Aug 19, 2021
1 parent 345d47c commit e8f03bc
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 104 deletions.
4 changes: 2 additions & 2 deletions examples/bulk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ async fn main() -> anyhow::Result<()> {

client
.execute(
"CREATE TABLE ##bulk_test1 (id INT IDENTITY PRIMARY KEY, content INT)",
"CREATE TABLE ##bulk_test1 (id INT IDENTITY PRIMARY KEY, content VARCHAR(255))",
&[],
)
.await?;
Expand All @@ -37,7 +37,7 @@ async fn main() -> anyhow::Result<()> {

let pb = ProgressBar::new(count as u64);

for i in 0..count {
for i in vec!["aaaaaaaaaaaaaaaaaaaa"; 1000].into_iter() {
let mut row = TokenRow::new();
row.push(i.into_sql());
req.send(row).await?;
Expand Down
28 changes: 3 additions & 25 deletions examples/tokio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,42 +10,20 @@ static CONN_STR: Lazy<String> = Lazy::new(|| {
})
});

#[cfg(not(all(windows, feature = "sql-browser-tokio")))]
#[tokio::main]
async fn main() -> anyhow::Result<()> {
env_logger::init();
let config = Config::from_ado_string(&CONN_STR)?;

let tcp = TcpStream::connect(config.get_addr()).await?;
tcp.set_nodelay(true)?;

let mut client = Client::connect(config, tcp.compat_write()).await?;

let stream = client.query("SELECT @P1", &[&1i32]).await?;
let row = stream.into_row().await?.unwrap();
let stream = client.query("SELECT * from test", &[]).await?;
let row = stream.into_row().await?;

println!("{:?}", row);
assert_eq!(Some(1), row.get(0));

Ok(())
}

#[cfg(all(windows, feature = "sql-browser-tokio"))]
#[tokio::main]
async fn main() -> anyhow::Result<()> {
use tiberius::SqlBrowser;

let config = Config::from_ado_string(&CONN_STR)?;

let tcp = TcpStream::connect_named(&config).await?;
tcp.set_nodelay(true)?;

let mut client = Client::connect(config, tcp.compat_write()).await?;

let stream = client.query("SELECT @P1", &[&1i32]).await?;
let row = stream.into_row().await?.unwrap();

println!("{:?}", row);
assert_eq!(Some(1), row.get(0));

Ok(())
}
1 change: 1 addition & 0 deletions src/tds/codec/bulk_load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ where
meta: BulkLoadMetadata<'a>,
) -> crate::Result<Self> {
let packet_id = connection.context_mut().next_packet_id();
let collation = connection.context().collation();
let mut buf = BytesMut::new();

meta.encode(&mut buf)?;
Expand Down
2 changes: 1 addition & 1 deletion src/tds/codec/column_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ impl<'a> ColumnData<'a> {
where
R: SqlReadBytes + Unpin,
{
let res = match &ctx.inner {
let res = match dbg!(&ctx.inner) {
TypeInfoInner::FixedLen(fixed_ty) => fixed_len::decode(src, fixed_ty).await?,
TypeInfoInner::VarLenSized(cx) => var_len::decode(src, cx).await?,
TypeInfoInner::VarLenSizedPrecision { ty, scale, .. } => match ty {
Expand Down
98 changes: 42 additions & 56 deletions src/tds/codec/token/token_env_change.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
use crate::{
tds::{lcid_to_encoding, sortid_to_encoding},
Error, SqlReadBytes,
};
use crate::{tds::Collation, Error, SqlReadBytes};
use byteorder::{LittleEndian, ReadBytesExt};
use encoding::Encoding;
use fmt::Debug;
use futures::io::AsyncReadExt;
use std::io::Cursor;
use std::io::Read;
use std::{convert::TryFrom, fmt};
use std::{
convert::TryFrom,
fmt,
io::{Cursor, Read},
};

uint_enum! {
#[repr(u8)]
Expand Down Expand Up @@ -63,52 +61,13 @@ impl fmt::Display for EnvChangeTy {
}
}

pub struct CollationInfo {
lcid_encoding: Option<&'static (dyn Encoding + Send + Sync)>,
sortid_encoding: Option<&'static (dyn Encoding + Send + Sync)>,
}

impl CollationInfo {
pub fn new(bytes: &[u8]) -> Self {
let lcid_encoding = match (bytes.get(0), bytes.get(1)) {
(Some(fst), Some(snd)) => lcid_to_encoding(u16::from_le_bytes([*fst, *snd])),
_ => None,
};

let sortid_encoding = match bytes.get(4) {
Some(byte) => sortid_to_encoding(*byte),
_ => None,
};

Self {
lcid_encoding,
sortid_encoding,
}
}
}

impl Debug for CollationInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}

impl fmt::Display for CollationInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match (self.lcid_encoding, self.sortid_encoding) {
(Some(lcid), Some(sortid)) => write!(f, "{}/{}", lcid.name(), sortid.name()),
_ => write!(f, "None"),
}
}
}

#[derive(Debug)]
pub enum TokenEnvChange {
Database(String, String),
PacketSize(u32, u32),
SqlCollation {
old: CollationInfo,
new: CollationInfo,
old: Option<Collation>,
new: Option<Collation>,
},
BeginTransaction([u8; 8]),
CommitTransaction,
Expand All @@ -131,9 +90,11 @@ impl fmt::Display for TokenEnvChange {
Self::PacketSize(old, new) => {
write!(f, "Packet size change from '{}' to '{}'", old, new)
}
Self::SqlCollation { old, new } => {
write!(f, "SQL collation change from {} to {}", old, new)
}
Self::SqlCollation { old, new } => match (old, new) {
(Some(old), Some(new)) => write!(f, "SQL collation change from {} to {}", old, new),
(_, Some(new)) => write!(f, "SQL collation changed to {}", new),
(_, _) => write!(f, "SQL collation change"),
},
Self::BeginTransaction(_) => write!(f, "Begin transaction"),
Self::CommitTransaction => write!(f, "Commit transaction"),
Self::RollbackTransaction => write!(f, "Rollback transaction"),
Expand Down Expand Up @@ -216,14 +177,39 @@ impl TokenEnvChange {
let mut new_value = vec![0; len];
buf.read_exact(&mut new_value[0..len])?;

let new = if len == 5 {
let new_sortid = new_value[4];
let new_info = u32::from_le_bytes([
new_value[0],
new_value[1],
new_value[2],
new_value[3],
]);

Some(Collation::new(new_info, new_sortid))
} else {
None
};

let len = buf.read_u8()? as usize;
let mut old_value = vec![0; len];
buf.read_exact(&mut old_value[0..len])?;

TokenEnvChange::SqlCollation {
new: CollationInfo::new(new_value.as_slice()),
old: CollationInfo::new(old_value.as_slice()),
}
let old = if len == 5 {
let old_sortid = old_value[4];
let old_info = u32::from_le_bytes([
old_value[0],
old_value[1],
old_value[2],
old_value[3],
]);

Some(Collation::new(old_info, old_sortid))
} else {
None
};

TokenEnvChange::SqlCollation { new, old }
}
EnvChangeTy::BeginTransaction | EnvChangeTy::EnlistDTCTransaction => {
let len = buf.read_u8()?;
Expand Down
34 changes: 17 additions & 17 deletions src/tds/codec/type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ uint_enum! {

impl Encode<BytesMut> for TypeInfo {
fn encode(self, dst: &mut BytesMut) -> crate::Result<()> {
match dbg!(self.inner) {
match self.inner {
TypeInfoInner::FixedLen(ty) => {
dst.put_u8(ty as u8);
}
Expand Down Expand Up @@ -296,30 +296,30 @@ impl TypeInfo {
/// A datetime2 value.
#[cfg(feature = "tds73")]
pub fn datetime2() -> Self {
Self::varlen(VarLenType::Datetime2, 8, None)
Self::varlen(VarLenType::Datetime2, 8)
}

/// A uniqueidentifier value.
pub fn guid() -> Self {
Self::varlen(VarLenType::Guid, 16, None)
Self::varlen(VarLenType::Guid, 16)
}

/// A date value.
#[cfg(feature = "tds73")]
pub fn date() -> Self {
Self::varlen(VarLenType::Daten, 3, None)
Self::varlen(VarLenType::Daten, 3)
}

/// A time value.
#[cfg(feature = "tds73")]
pub fn time() -> Self {
Self::varlen(VarLenType::Timen, 5, None)
Self::varlen(VarLenType::Timen, 5)
}

/// A time value.
#[cfg(feature = "tds73")]
pub fn datetimeoffset() -> Self {
Self::varlen(VarLenType::DatetimeOffsetn, 10, None)
Self::varlen(VarLenType::DatetimeOffsetn, 10)
}

/// A variable binary value. If length is limited and larger than 8000
Expand All @@ -330,7 +330,7 @@ impl TypeInfo {
_ => u16::MAX,
};

Self::varlen(VarLenType::BigVarBin, length as usize, None)
Self::varlen(VarLenType::BigVarBin, length as usize)
}

/// A binary value.
Expand All @@ -340,7 +340,7 @@ impl TypeInfo {
/// - If length is more than 8000 bytes.
pub fn binary(length: u16) -> Self {
assert!(length <= 8000);
Self::varlen(VarLenType::BigBinary, length as usize, None)
Self::varlen(VarLenType::BigBinary, length as usize)
}

/// A variable string value. If length is limited and larger than 8000
Expand All @@ -351,7 +351,7 @@ impl TypeInfo {
_ => u16::MAX,
};

Self::varlen(VarLenType::BigVarChar, length as usize, None)
Self::varlen(VarLenType::BigVarChar, length as usize)
}

/// A variable UTF-16 string value. If length is limited and larger than
Expand All @@ -362,7 +362,7 @@ impl TypeInfo {
_ => u16::MAX,
};

Self::varlen(VarLenType::BigVarChar, length as usize, None)
Self::varlen(VarLenType::BigVarChar, length as usize)
}

/// A constant-size string value.
Expand All @@ -372,7 +372,7 @@ impl TypeInfo {
/// - If length is more than 8000 characters.
pub fn char(length: u16) -> Self {
assert!(length <= 8000);
Self::varlen(VarLenType::BigChar, length as usize, None)
Self::varlen(VarLenType::BigChar, length as usize)
}

/// A constant-size UTF-16 string value.
Expand All @@ -382,22 +382,22 @@ impl TypeInfo {
/// - If length is more than 4000 characters.
pub fn nchar(length: u16) -> Self {
assert!(length <= 4000);
Self::varlen(VarLenType::NChar, length as usize, None)
Self::varlen(VarLenType::NChar, length as usize)
}

/// A (deprecated) heap-allocated text storage.
pub fn text() -> Self {
Self::varlen(VarLenType::Text, u32::MAX as usize, None)
Self::varlen(VarLenType::Text, u32::MAX as usize)
}

/// A (deprecated) heap-allocated UTF-16 text storage.
pub fn ntext() -> Self {
Self::varlen(VarLenType::NText, u32::MAX as usize, None)
Self::varlen(VarLenType::NText, u32::MAX as usize)
}

/// A (deprecated) heap-allocated binary storage.
pub fn image() -> Self {
Self::varlen(VarLenType::Image, u32::MAX as usize, None)
Self::varlen(VarLenType::Image, u32::MAX as usize)
}

/// Numeric data types that have fixed precision and scale. Decimal and
Expand Down Expand Up @@ -433,8 +433,8 @@ impl TypeInfo {
Self { inner }
}

fn varlen(ty: VarLenType, len: usize, collation: Option<Collation>) -> Self {
let cx = VarLenContext::new(ty, len, collation);
fn varlen(ty: VarLenType, len: usize) -> Self {
let cx = VarLenContext::new(ty, len, None);
let inner = TypeInfoInner::VarLenSized(cx);

Self { inner }
Expand Down
11 changes: 11 additions & 0 deletions src/tds/collation.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::fmt;

///! legacy implementation of collations (or codepages rather) for dealing with varchar's with legacy databases
///! references [1] which has some mappings from the katmai (SQL Server 2008) source code and is a TDS driver
///! directly from microsoft
Expand Down Expand Up @@ -52,6 +54,15 @@ impl Collation {
}
}

impl fmt::Display for Collation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.encoding() {
Ok(encoding) => write!(f, "{}", encoding.name()),
_ => write!(f, "None"),
}
}
}

/// https://github.com/Microsoft/mssql-jdbc/blob/eb14f63077c47ef1fc1c690deb8cfab602baeb85/src/main/java/com/microsoft/sqlserver/jdbc/SQLCollation.java#L102-L310
/// maps an LCID (it's locale part which is only 2 bytes) to a codepage
///
Expand Down
Loading

0 comments on commit e8f03bc

Please sign in to comment.