1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
use bitflags::bitflags;
use bytes::{Buf, Bytes};
use crate::error::Error;
use crate::ext::ustr::UStr;
use crate::mssql::io::MssqlBufExt;
use crate::mssql::protocol::type_info::TypeInfo;
use crate::mssql::MssqlColumn;
use crate::HashMap;
#[derive(Debug)]
pub(crate) struct ColMetaData;
#[derive(Debug)]
pub(crate) struct ColumnData {
// The user type ID of the data type of the column. Depending on the TDS version that is used,
// valid values are 0x0000 or 0x00000000, with the exceptions of data type
// TIMESTAMP (0x0050 or 0x00000050) and alias types (greater than 0x00FF or 0x000000FF).
pub(crate) user_type: u32,
pub(crate) flags: Flags,
pub(crate) type_info: TypeInfo,
// TODO: pub(crate) table_name: Option<Vec<String>>,
// TODO: crypto_meta_data: Option<CryptoMetaData>,
// The column name. It contains the column name length and column name.
pub(crate) col_name: String,
}
bitflags! {
#[cfg_attr(feature = "offline", derive(serde::Serialize, serde::Deserialize))]
pub struct Flags: u16 {
// Its value is 1 if the column is nullable.
const NULLABLE = 0x0001;
// Set to 1 for string columns with binary collation and always for the XML data type.
// Set to 0 otherwise.
const CASE_SEN = 0x0002;
// usUpdateable is a 2-bit field. Its value is 0 if column is read-only, 1 if column is
// read/write and2 if updateable is unknown.
const UPDATEABLE1 = 0x0004;
const UPDATEABLE2 = 0x0008;
// Its value is 1 if the column is an identity column.
const IDENITTY = 0x0010;
// Its value is 1 if the column is a COMPUTED column.
const COMPUTED = 0x0020;
// Its value is 1 if the column is a fixed-length common language runtime
// user-defined type (CLR UDT).
const FIXED_LEN_CLR_TYPE = 0x0100;
// fSparseColumnSet, introduced in TDSversion 7.3.B, is a bit flag. Its value is 1 if the
// column is the special XML column for the sparse column set. For information about using
// column sets, see [MSDN-ColSets]
const SPARSE_COLUMN_SET = 0x0200;
// Its value is 1 if the column is encrypted transparently and
// has to be decrypted to view the plaintext value. This flag is valid when the column
// encryption feature is negotiated between client and server and is turned on.
const ENCRYPTED = 0x0400;
// Its value is 1 if the column is part of a hidden primary key created to support a
// T-SQL SELECT statement containing FOR BROWSE.
const HIDDEN = 0x0800;
// Its value is 1 if the column is part of a primary key for the row
// and the T-SQL SELECT statement contains FOR BROWSE.
const KEY = 0x1000;
// Its value is 1 if it is unknown whether the column might be nullable.
const NULLABLE_UNKNOWN = 0x2000;
}
}
impl ColMetaData {
pub(crate) fn get(
buf: &mut Bytes,
columns: &mut Vec<MssqlColumn>,
column_names: &mut HashMap<UStr, usize>,
) -> Result<(), Error> {
columns.clear();
column_names.clear();
let mut count = buf.get_u16_le();
let mut ordinal = 0;
if count == 0xffff {
// In the event that the client requested no metadata to be returned, the value of
// Count will be 0xFFFF. This has the same effect on Count as a
// zero value (for example, no ColumnData is sent).
count = 0;
} else {
columns.reserve(count as usize);
}
while count > 0 {
let col = MssqlColumn::new(ColumnData::get(buf)?, ordinal);
column_names.insert(col.name.clone(), ordinal);
columns.push(col);
count -= 1;
ordinal += 1;
}
Ok(())
}
}
impl ColumnData {
fn get(buf: &mut Bytes) -> Result<Self, Error> {
let user_type = buf.get_u32_le();
let flags = Flags::from_bits_truncate(buf.get_u16_le());
let type_info = TypeInfo::get(buf)?;
// TODO: table_name
// TODO: crypto_meta_data
let name = buf.get_b_varchar()?;
Ok(Self {
user_type,
flags,
type_info,
col_name: name,
})
}
}