SQL 命令典型执行过程(以Select为例)
Client |
|
|
|
Server |
1 |
------- |
Data Piggyback(11) Cursor Close All(69) 注意此处也有可能是 116b,035e,0303 |
-----> |
具体语句 |
2 |
<----- |
Data DescribeInfo(10) 17 |
------- |
返回列 |
3 |
------- |
Data UOCIFun(03) FetchARow(05) |
-----> |
获取其他值 |
4 |
<----- |
Data RowTransferHeader(06) 01 |
------- |
返回值 |
11g,12c有三种sql命令执行的模式:
- 第一种是前序一个piggyback(1169)包,然后紧接execute buddle command(035e)
- 第二种是前序一个session switch piggy back(116b)包,然后紧接execute buddle command(035e)
- 第三种是直接发送execute buddle command(035e),前者可以看做只是在后者前面加了一个头
参考网上其他文章Oracle 9.2还有可能使用0303来发命令,而对其的返回(上述流程中2处)可能使用data 1019的包
使用0x1169执行SQL命令的情况
包格式
|
32bit |
64bit |
|
序列号 |
1 |
1 |
|
Piggyback cusor close all (1169) command |
9 or 13 |
16 or 20 |
|
Buddle execute (035e)command |
变长 |
变长 |
|
参考网上一些文章,Oracle9,10 Piggy Command长度为12
1169 command
这个部分是变长的,下面是几种变化,都以feMagic(定义参见本系列第二篇 《Oracle TNS 314 协议分析---基础包结构》)数组开头,有的长16个字节,有的20个字节
语句 |
Plsql |
Sqlplus |
Navicat |
Select |
fe ff ff ff ff ff ff ff 01 00 00 00 04 00 00 00 |
fe ff ff ff ff ff ff ff 01 00 00 00 00 00 00 00 05 00 00 00 当没有输入;05会变03 |
fe ff ff ff ff ff ff ff 01 00 00 00 05 00 00 00 |
Update |
fe ff ff ff ff ff ff ff 01 00 00 00 02 00 00 00 |
fe ff ff ff ff ff ff ff 01 00 00 00 00 00 00 00 06 00 00 00 |
|
Delete |
fe ff ff ff ff ff ff ff 01 00 00 00 02 00 00 00 |
fe ff ff ff ff ff ff ff 01 00 00 00 00 00 00 00 03 00 00 00 |
|
Insert |
|
fe ff ff ff ff ff ff ff 01 00 00 00 00 00 00 00 05 00 00 00 有时是0b 有时是09 |
|
CreateTable |
|
fe ff ff ff ff ff ff ff 01 00 00 00 00 00 00 00 07 00 00 00 |
|
使用0x116b执行SQL命令的情况
包格式
|
32bit |
64bit |
|
序列号 |
1 |
1 |
|
Piggy command |
12 |
12 |
|
Buddle execute command 035e |
变长 |
变长 |
|
Oracle9 10 Piggy Command长度也为12
Buddle execute Command 035e
|
32bit |
64bit |
ThinClient |
|
序列号 |
1 |
1 |
1 |
|
命令相关 |
8 |
8 |
5 |
|
feMagic |
1 |
8 |
1 |
|
语句长度相关字段 |
2 |
2 |
1 |
|
未知 | 2 | 2 | 1 | |
固定字节 |
54 |
152 |
41 |
所有命令都相同 |
SQL命令 |
变长 |
变长 |
变长 |
|
尾部字节 |
52 |
52 |
17 |
01开头 |
根据其他文章来看Oracle9、10(TNS312,313)下这个包有一定区别(主要是从序列号到SQL的字节数分别为80,92,而11,12为172)下面是根据其他文章分析的包结构
序列号 |
1 |
|
固定长度头部 |
80 or 92 |
|
SQL命令 |
变长 |
SQL查询语句 |
尾部字节 |
48 |
|
ThinClient发出的包与此相差较大,将另文描述
命令相关
各个平台各种语句调用如下
语句 |
PlSQL |
SQLplus |
Navicat |
Thin Client |
Select |
61 80 00 00 00 00 00 00 |
61 80 00 00 00 00 00 00 |
61 81 00 00 00 00 00 00 |
02 80 21 00 01 |
Update |
21 80 00 00 00 00 00 00 |
21 80 00 00 00 00 00 00 |
21 81 00 00 00 00 00 00 |
|
Delete |
21 80 00 00 00 00 00 00 |
21 80 00 00 00 00 00 00 |
21 81 00 00 00 00 00 00 |
|
Insert |
21 80 00 00 00 00 00 00 |
21 80 00 00 00 00 00 00 |
21 81 00 00 00 00 00 00 |
|
CreateTable |
21 80 00 00 00 00 00 00 |
21 80 00 00 00 00 00 00 |
21 81 00 00 00 00 00 00 |
|
AlterTable |
21 80 00 00 00 00 00 00 |
21 80 00 00 00 00 00 00 |
21 81 00 00 00 00 00 00 |
红色部分见过这些取值
61 80 plsql select
61 81 navicat select
01 80 02 plsql select another
29 04 04 plsql declare function
29 05 04 navicat declare function
21 80 plsql 除select 外
21 81 navicat 除select 外
21 01 04 navicat call function
而在ThinClient中,返现Endian会发生变化,且前序一个长度字节的情况,且此字段长度也不相同
于是21 80会变成 02 80 21
语句长度字段
此字节与sql长度有关,OCI Client 下为sql长度字段大小*3,如果sql较长,则会产生进位,注意进位后是little endian的形式,02 01 表示102,ThinClient下直接就是语句长度,ThinClient下语句前不会再附加长度,此处是获取长度的最佳地点。
39 00 00 00 表示 0x39
21 01 00 00 表示 0x121
在命令超长的情况下,这个长度字段非常有用,因为一个command会在多个TNSData包中出现,必须用这个长度字段和TNS Command Header的长度字段,才能正确组合超长命令。
上图中可以看出,一个超长命令可能跨越多个TNS包,如果一个TNS包中的Command长度不足,说明还没有收取完毕,需要继续从buffer中读取数据,直到命令长度满足要求。另外处理程序如果工作在应用层,那么处理程序从buffer中取出的数据可能横跨多个TNS包,由于每个TNS包都有自己的头部,就会在解析的命令中引入这些额外的头部。为了跳过这些头部,必须利用第一个TNS 的package Length作为指针,逐个找到每个头部,从而处理这些额外的10字节头。
固定字节
64bit OCI Client(SQLPLUS,PLSQL,Navicat)
后续19*8=152个固定字节,使用navicat和plsql无论什么命令都相同:
0000 fe ff ff ff ff ff ff ff 0d 00 00 00 fe ff ff ff ........ ........
0010 ff ff ff ff fe ff ff ff ff ff ff ff 00 00 00 00 ........ ........
0020 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
0030 00 00 00 00 00 00 00 00 00 00 00 00 fe ff ff ff ........ ........
0040 ff ff ff ff 00 00 00 00 00 00 00 00 fe ff ff ff ........ ........
0050 ff ff ff ff fe ff ff ff ff ff ff ff fe ff ff ff ........ ........
0060 ff ff ff ff 00 00 00 00 00 00 00 00 fe ff ff ff ........ ........
0070 ff ff ff ff fe ff ff ff ff ff ff ff 00 00 00 00 ........ ........
0080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
0090 00 00 00 00 00 00 00 00 ........
32bit OCI Client(SQLPLUS,PLSQL,Navicat)
后续54个固定字节
0000 01 0d 00 00 00 01 01 00 00 00 00 01 00 00 00 00 ........ ........
0010 00 00 00 00 00 00 00 00 00 01 00 01 01 01 00 00 ........ ........
0020 00 00 00 00 00 00 01 01 00 00 00 00 00 00 00 00 ........ ........
0030 00 00 00 00 00 00
Thin Client(JAVA)
后续41个固定字节
0000 01 0d 00 00 04 ff ff ff ff 01 0a 04 7f ff ff ff ........ ........
0010 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ........ ........
0020 00 00 00 00 00 00 00 00 00
Sql命令
后续立刻接sql,sql遵循变长字符串或数组形式,即len+值定义,第一个字节为长度,或fe表示数组,数组中元素也是变长字符串,当为数组时数组由00结尾,所有sql都后续01。如果输入时忘记输入;语句后会多个0a,所以结尾看起来是0a01或0a0001(变长)。
定长命令
00A0 13 53 45 ........ ......SE
00B0 4c 45 43 54 20 2a 20 46 52 4f 4d 20 44 45 50 54 LECT * F ROM DEPT
00C0 0a 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
00D0 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 ........ ........
00E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
00F0 00 00 00 00 00
变长命令
ThinClient 无长度前序命令
ThinClient下发现此包无前序长度,长度由前面长度相关字段确定
包示例(Navicat 15 premium 64bit to Oracle 12)
0303 QUERY包
根据其他文章在Oracle9.2下有可能使用这种包发送命令(本文11,12 64bit下未测得),其格式如下
Request id |
1 |
|
Magic |
12 |
|
Data Format |
可变 |
查询语句 |
通过Transfer header 获取返回值
包示例