sql server的sql查询包的数据格式

原创
2016/08/22 17:16
阅读数 165

sql server前后端通信的数据包的格式,可以大致分为:公共头部+个性化包头部+数据。其中公共头部是包的最开始的8byte的内容,每个包都有这8byte的内容,含义相同。再紧接着是各种类型的数据包的头部,这个就需要根据各种包的不同,这部分的内容的含义也不同。最后是数据,有些包可能没有数据。

1. 公共头部

  公共头部是包最前面的8个字节,这8个字节的含义为:

第一个字节:包类型,根据msdn的介绍,目前有11种包的类型再使用。本文需要介绍的sql batch包的类型为0x01.

第二字节:包的状态,根据msdn的介绍,包的状态有5中取值(0x00, 0x01, 0x02, 0x08, 0x10)。其中0x00表示普通包,0x01表示当前包是最后一个包。

第三,四个字节:包的长度。包的长度是经过2个byte来描述的,并且采用大端序的方式。后面可以了解到sql server中包中的数据即包括小端序的数据又包括大端序的数据。此处是大端序的数据。包的长度包括头部的8字节长度。

第五,六字节:包的spid。根据msdn的解释,这个字段是保存的是服务器的进程ID的编号。

第七字节:包的序号。包的序号取值在1-256,通过这个序号可以把打包拆分为小包进行发送到服务端或者服务端发送到客户端。

第八字节:站位字节(pad)。目前没有使用,通常设置为0x00。这个字段应该被接收者忽略掉。

2. sqlbatch包的头部

  在发送sqlbatch包的时候,除了公共的头部外,还要sqlbatch包的头部信息。sqlbatch包的头部包括:

所有头部的总长度,后面依次是每个头部的长度,类型,数据。下面是是msdn官网的一个例子的一部分情况:

 <All_HEADERS>
         <TotalLength>
           <DWORD>16 00 00 00 </DWORD>
         </TotalLength>
         <Header>
           <HeaderLength>
             <DWORD>12 00 00 00 </DWORD>
           </HeaderLength>
           <HeaderType>
             <USHORT>02 00 </USHORT>
           </HeaderType>
           <HeaderData>
             <MARS>
               <TransactionDescriptor>
                 <ULONGLONG>00 00 00 00 00 00 00 01 </ULONGLONG>
               </TransactionDescriptor>
               <OutstandingRequestCount>
                 <DWORD>00 00 00 00 </DWORD>
               </OutstandingRequestCount>
             </MARS>
           </HeaderData>
         </Header>
       </All_HEADERS>

所有头部长度站位4byte。其中头部长度占4byte,类型占2byte。其中所有头部的长度包括自身长度+所有头部的长度。从上面的例子中也可以注意到包的长度,包类型都是小端序的。

3. 包数据

包数据的长度=公共头部中的长度-sqlbatch包的头部长度-8个字节的公共长度。得到包数据的长度后,就可以读取到sql text的数据。但是读取到的数据是unicode的,需要进行转换后才能得到我们需要的sql语句。下面是从Unicode进行转换的代码:

int Tool::unicode2string(const char* unicodeStr, const int len, std::string& desStr) {
	if (len%2 != 0) {
		return -1;
	}
	desStr.reserve(len/2+1);

	int i = 0;
	for (i = 0; i < len; i = i + 2) {
		desStr.insert(i/2, 1, (char)((unicodeStr[i] & 0xff) | (unicodeStr[i+1] & 0xff) << 8));
	}
	desStr.insert(len/2, 1, (char)'\0');
	return 0;
}

则通过上面的了解后,需要提取sql batch包中的sql语句还是比较简单的。基本过程如下所示:

1. 解析公共头部,得到整个包的长度

2. 解析得到sqlbatch的头部长度

3. 计算得到sql语句的开始位置以及长度

4. 读取到Unicode类型的sql语句,再调用unicode2string来进行转换。

更多信息,请期待oneproxy-for-sqlserver.

 

 

 

 

展开阅读全文
打赏
0
1 收藏
分享
加载中
更多评论
打赏
0 评论
1 收藏
0
分享
返回顶部
顶部