Merge lp:~jan-kneschke/mysql-proxy/prep-stmt-codecs into lp:mysql-proxy/0.8
- prep-stmt-codecs
- Merge into 0.8
Status: | Merged |
---|---|
Merged at revision: | 1132 |
Proposed branch: | lp:~jan-kneschke/mysql-proxy/prep-stmt-codecs |
Merge into: | lp:mysql-proxy/0.8 |
Diff against target: |
5689 lines (+5074/-275) 26 files modified
Makefile.am (+1/-1) configure.in (+9/-1) doc/Makefile.am (+18/-0) doc/book.txt (+17/-0) doc/chapter/Makefile.am (+4/-0) doc/chapter/protocol.txt (+1581/-122) doc/chapter/scripting.txt (+326/-96) doc/protocol.txt (+8/-0) doc/scripting.txt (+8/-0) examples/Makefile.am (+1/-0) examples/tutorial-prep-stmts.lua (+74/-0) lib/mysql-proto.c (+270/-0) src/CMakeLists.txt (+4/-0) src/Makefile.am (+4/-0) src/network-mysqld-packet.c (+506/-50) src/network-mysqld-packet.h (+54/-0) src/network-mysqld-proto.h (+7/-4) src/network_mysqld_proto_binary.c (+436/-0) src/network_mysqld_proto_binary.h (+12/-0) src/network_mysqld_type.c (+656/-0) src/network_mysqld_type.h (+147/-0) tests/unit/CMakeLists.txt (+2/-0) tests/unit/Makefile.am (+18/-0) tests/unit/lua/mysql-proto.lua (+70/-1) tests/unit/t_network_mysqld_packet.c (+636/-0) tests/unit/t_network_mysqld_type.c (+205/-0) |
To merge this branch: | bzr merge lp:~jan-kneschke/mysql-proxy/prep-stmt-codecs |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Registry Administrators | Pending | ||
Review via email: mp+36325@code.launchpad.net |
This proposal supersedes a proposal from 2010-09-22.
Commit message
Description of the change
* added a network_
* added encoders and decoders for the binary row format (network_
* added encoders and decoders for COM_STMT_PREPARE, COM_STMT_EXECUTE, COM_STMT_CLOSE and its special response packets
* added a example on how to use them examples/
- 1167. By <email address hidden>
-
restructed the file into a valid reST file and added infos about MYSQL_TYPE_* and COM_*
- 1168. By <email address hidden>
-
streamlined the payload description
* described the possible types of the payload
* adjusted the payload descriptions of the packets to follow it strictly - 1169. By <email address hidden>
-
allow COM_STMT_PREPAREs to fail and linked its OK packet
- 1170. By <email address hidden>
-
document COM_SLEEP, COM_INIT_DB, _CREATE_DB and _DROP_DB
- 1171. By <email address hidden>
-
moved OK and ERR into the Generic Packets section and EOF into the text resultset
- 1172. By <email address hidden>
-
added 'COM_STMT_EXECUTE Response' and added a few more 'response:' fields to the packet definitions
- 1173. By <email address hidden>
-
added LOCAL INFILE handling
- 1174. By <email address hidden>
-
added links to the external documents describing the protocol
- 1175. By <email address hidden>
-
documented the packets of the auth phase
- 1176. By <email address hidden>
-
added COM_STMT_RESET and _STMT_SEND_
LONG_DATA - 1177. By <email address hidden>
-
added the pre-4.1 column definition
- 1178. By <email address hidden>
-
COM_STMT_RESET has a response: OK or ERR
- 1179. By <email address hidden>
-
_SEND_LONG_DATA is 18
- 1180. By <email address hidden>
-
added COM_FIELD_LIST
- 1181. By <email address hidden>
-
added COM_PROCESS_INFO, _PROCESS_KILL and _PING
- 1182. By <email address hidden>
-
documented the commands that are not handled by the server
- 1183. By <email address hidden>
-
added COM_SET_OPTION
- 1184. By <email address hidden>
-
added COM_DEBUG, _STATISTICS and _SHUTDOWN
- 1185. By <email address hidden>
-
TABLE_DUMP and CONNECT_OUT are undefined in 5.x
- 1186. By <email address hidden>
-
added COM_CHANGE_USER
- 1187. By <email address hidden>
-
documented multi-resultsets and all the server-status flags
- 1188. By <email address hidden>
-
moved the status flags to the OK packet
- 1189. By <email address hidden>
-
added the capability flags
- 1190. By <email address hidden>
-
added some more cross-references
- 1191. By <email address hidden>
-
fixed section indention to put the COM_* responses as sub-section of the command
- 1192. By <email address hidden>
-
added the COM_STMT_EXECUTE flags and did some cosmetic changes and typo fixes
- 1193. By <email address hidden>
-
replaced doxygen version of scripting.txt by a reST version
* added the basic structure
* documented the mysql.proto module - 1194. By <email address hidden>
-
removed the document headings
- 1195. By <email address hidden>
-
moved the protocol.txt and scripting.txt into the chapter/ dir
* allow to include them into standalone documents and into the
full book - 1196. By <email address hidden>
-
added rules to generate a full book and standalone pieces of protocol and scripting
- 1197. By <email address hidden>
-
removed the use of the gnu-make extension
- 1198. By <email address hidden>
-
use AC_MISSING() to let "make html" fail nicely if rst2html.py isn't installed
Preview Diff
1 | === modified file 'Makefile.am' |
2 | --- Makefile.am 2010-04-06 14:46:45 +0000 |
3 | +++ Makefile.am 2010-09-27 14:20:48 +0000 |
4 | @@ -1,4 +1,4 @@ |
5 | -SUBDIRS = cmake src lib plugins examples scripts tests m4 |
6 | +SUBDIRS = cmake src lib plugins examples scripts tests m4 doc |
7 | |
8 | EXTRA_DIST = \ |
9 | config.h.cmake \ |
10 | |
11 | === modified file 'configure.in' |
12 | --- configure.in 2010-05-25 13:44:43 +0000 |
13 | +++ configure.in 2010-09-27 14:20:48 +0000 |
14 | @@ -43,6 +43,13 @@ |
15 | AC_PROG_MAKE_SET |
16 | AM_PROG_CC_C_O |
17 | |
18 | +if test x$RST2HTML = x; then |
19 | + AM_MISSING_PROG(RST2HTMLMISSING, rst2html.py) |
20 | + RST2HTML=$RST2HTMLMISSING |
21 | +fi |
22 | +AC_SUBST(RST2HTML) |
23 | + |
24 | + |
25 | dnl more automake stuff |
26 | AM_C_PROTOTYPES |
27 | |
28 | @@ -432,7 +439,8 @@ |
29 | AC_CONFIG_FILES([scripts/mysql-proxy:scripts/mysql-proxy-binwrapper.in], [chmod +x scripts/mysql-proxy]) |
30 | AC_CONFIG_FILES([mysql-proxy.pc]) |
31 | AC_CONFIG_FILES([mysql-chassis.pc]) |
32 | - |
33 | +AC_CONFIG_FILES([doc/Makefile]) |
34 | +AC_CONFIG_FILES([doc/chapter/Makefile]) |
35 | AC_OUTPUT |
36 | |
37 | |
38 | |
39 | === modified file 'doc/Makefile.am' |
40 | --- doc/Makefile.am 2009-06-29 15:34:01 +0000 |
41 | +++ doc/Makefile.am 2010-09-27 14:20:48 +0000 |
42 | @@ -1,3 +1,5 @@ |
43 | +SUBDIRS=chapter |
44 | + |
45 | EXTRA_DIST = \ |
46 | lua-classes.dot \ |
47 | architecture.dot \ |
48 | @@ -10,3 +12,19 @@ |
49 | tests.txt \ |
50 | scripting.txt \ |
51 | lifecycle.msc |
52 | + |
53 | +clean-local: |
54 | + rm -f *.html |
55 | + |
56 | +html-local: book.html protocol.html scripting.html |
57 | + |
58 | +## we use http://docutils.sourceforge.net/rst.html to generate the docs |
59 | +book.html: book.txt chapter/scripting.txt chapter/protocol.txt |
60 | + ${RST2HTML} $< $@ |
61 | + |
62 | +protocol.html: protocol.txt chapter/protocol.txt |
63 | + ${RST2HTML} $< $@ |
64 | + |
65 | +scripting.html: scripting.txt chapter/scripting.txt |
66 | + ${RST2HTML} $< $@ |
67 | + |
68 | |
69 | === added file 'doc/book.txt' |
70 | --- doc/book.txt 1970-01-01 00:00:00 +0000 |
71 | +++ doc/book.txt 2010-09-27 14:20:48 +0000 |
72 | @@ -0,0 +1,17 @@ |
73 | +*********** |
74 | +MySQL Proxy |
75 | +*********** |
76 | + |
77 | +.. contents:: |
78 | + |
79 | +============== |
80 | +MySQL Protocol |
81 | +============== |
82 | + |
83 | +.. include:: chapter/protocol.txt |
84 | + |
85 | +========================== |
86 | +Scripting the proxy plugin |
87 | +========================== |
88 | + |
89 | +.. include:: chapter/scripting.txt |
90 | |
91 | === added directory 'doc/chapter' |
92 | === added file 'doc/chapter/Makefile.am' |
93 | --- doc/chapter/Makefile.am 1970-01-01 00:00:00 +0000 |
94 | +++ doc/chapter/Makefile.am 2010-09-27 14:20:48 +0000 |
95 | @@ -0,0 +1,4 @@ |
96 | +EXTRA_DIST=\ |
97 | + protocol.txt \ |
98 | + scripting.txt |
99 | + |
100 | |
101 | === renamed file 'doc/protocol.txt' => 'doc/chapter/protocol.txt' |
102 | --- doc/protocol.txt 2009-06-29 16:39:46 +0000 |
103 | +++ doc/chapter/protocol.txt 2010-09-27 14:20:48 +0000 |
104 | @@ -1,123 +1,1582 @@ |
105 | -/** |
106 | -@page protocol MySQL Protocol |
107 | - |
108 | -The MySQL Protocol is spilt into the four phases: |
109 | - |
110 | -@dot |
111 | -digraph { |
112 | -connect -> auth; |
113 | -auth -> command; |
114 | -command -> disconnect; |
115 | -command -> command; |
116 | -connect -> disconnect; |
117 | -auth -> disconnect; |
118 | -} |
119 | -@enddot |
120 | - |
121 | -The client and the server send and receive packets as documented in http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol |
122 | - |
123 | -@dot |
124 | -digraph states { |
125 | - graph [rankdir=LR]; |
126 | - node [fontname=Helvetica, fontsize=10]; |
127 | - |
128 | - connect [ shape=record ]; |
129 | - disconnect [ shape=record ]; |
130 | - |
131 | - subgraph cluster_client { |
132 | - label = "client"; |
133 | - style = filled; |
134 | - node [ style=filled, fillcolor=lightblue ]; |
135 | - connect; |
136 | - auth_response; |
137 | - auth_old; |
138 | - command; |
139 | - command_local; |
140 | - } |
141 | - |
142 | - subgraph cluster_server { |
143 | - label = "server"; |
144 | - style = filled; |
145 | - node [ style=filled, fillcolor=orange ]; |
146 | - auth_challenge; |
147 | - auth_result; |
148 | - command_result; |
149 | - command_infile; |
150 | - } |
151 | - |
152 | - subgraph { |
153 | - edge [ fontcolor=blue, color=blue, fontsize=10, fontname=Helvetica ]; |
154 | - |
155 | - connect->auth_challenge [ label = "connecting server" ]; |
156 | - auth_response->auth_result [ label = "capabilities, password, default-db", URL="http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Client_Authentication_Packet" ]; |
157 | - auth_old->auth_result [ label = "scrambled password" ] ; |
158 | - command->command_result [ label = "command (COM_*)", URL="http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Command_Packet" ] ; |
159 | - command->command_infile [ label = "LOAD DATA INFILE LOCAL" ]; |
160 | - command_local->command_result [ label = "file content"]; |
161 | - } |
162 | - |
163 | - subgraph { |
164 | - edge [ fontcolor=red, color=red, fontsize=10, fontname=Helvetica ]; |
165 | - auth_challenge->disconnect [ label = "ERR: host denied", URL="http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Error_Packet" ]; |
166 | - auth_challenge->auth_response [ label = "0x10: auth_challenge", URL="http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Handshake_Initialization_Packet" ]; |
167 | - auth_result->auth_old [ label = "EOF: old password reauth" ]; |
168 | - auth_result->command [ label = "OK: auth done", URL="http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#OK_Packet" ]; |
169 | - auth_result->disconnect [ label = "ERR: auth failed", URL="http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Error_Packet" ]; |
170 | - command_result->command [ label = "OK|ERR|Resultset", URL="http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Result_Set_Header_Packet" ] ; |
171 | - command_result->disconnect [ label = "command = COM_QUIT" ]; |
172 | - command_result->command_result [ label = "command = COM_BINLOG_DUMP" ]; |
173 | - command_infile->command_local [ label = "EOF: filename" ]; |
174 | - } |
175 | -} |
176 | -@enddot |
177 | - |
178 | -The @ref page-core exposes all the states to the @ref page-plugins. |
179 | - |
180 | -@section section-protocol-use-cases Use Cases |
181 | - |
182 | --# the client connects to the server and waits for data to return @msc |
183 | - client, backend; |
184 | - --- [ label = "connect to backend" ]; |
185 | - client->backend [ label = "INIT" ]; |
186 | -@endmsc |
187 | --# the auth-phase handles the new SHA1-style passwords and the old scramble() passwords |
188 | - -# 4.1+ passwords @msc |
189 | - client, backend; |
190 | - --- [ label = "authenticate" ]; |
191 | - backend->client [ label = "HANDSHAKE" ]; |
192 | - client->backend [ label = "AUTH" ]; |
193 | - backend->client [ label = "AUTH_RESULT" ]; |
194 | -@endmsc |
195 | - -# pre-4.1 passwords @msc |
196 | - client, backend; |
197 | - --- [ label = "authenticate" ]; |
198 | - backend->client [ label = "HANDSHAKE" ]; |
199 | - client->backend [ label = "AUTH" ]; |
200 | - backend->client [ label = "OLD_PASSWORD_SCRAMBLE" ]; |
201 | - client->backend [ label = "OLD_PASSWORD_AUTH" ]; |
202 | - backend->client [ label = "AUTH_RESULT" ]; |
203 | -@endmsc |
204 | --# the query-phase repeats |
205 | - -# COM_QUERY and friends @msc |
206 | - client, backend; |
207 | - --- [ label = "query result phase" ]; |
208 | - client->backend [ label = "QUERY" ]; |
209 | - backend->client [ label = "QUERY_RESULT" ]; |
210 | -@endmsc |
211 | - -# COM_QUIT @msc |
212 | - client, backend; |
213 | - --- [ label = "query result phase" ]; |
214 | - client->backend [ label = "QUERY" ]; |
215 | - backend->client [ label = "connection close" ]; |
216 | -@endmsc |
217 | - -# COM_BINLOG_DUMP @msc |
218 | - client, backend; |
219 | - --- [ label = "query result phase" ]; |
220 | - client->backend [ label = "QUERY" ]; |
221 | - backend->client [ label = "QUERY_RESULT" ]; |
222 | - ... [ label = "more binlog entries" ]; |
223 | - backend->client [ label = "QUERY_RESULT"]; |
224 | -@endmsc |
225 | - */ |
226 | - |
227 | +The MySQL protocol is used between the MySQL Clients and the MySQL Server. It is implemented by |
228 | + |
229 | +* the Connectors (Connector/C, ...) |
230 | +* MySQL Proxy |
231 | +* the MySQL Server itself for the slaves |
232 | + |
233 | +The documentation is sparse and is split between: |
234 | + |
235 | + http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol |
236 | + |
237 | +and the source files of the MySQL Server: |
238 | + |
239 | +* sql/sql_parse.cc for the protocol basics |
240 | + |
241 | + * dispatch_command() |
242 | + |
243 | +* sql/sql_prepare.cc for the prepared statement protocol |
244 | + |
245 | + * mysqld_stmt_prepare() |
246 | + * mysqld_stmt_execute() |
247 | + * mysqld_stmt_close() |
248 | + * mysqld_stmt_reset() |
249 | + * mysqld_stmt_fetch() |
250 | + * mysql_stmt_get_longdata() |
251 | + |
252 | +* sql/sql_repl.cc for the binlog protocol |
253 | + |
254 | + * mysql_binlog_send() |
255 | + |
256 | +* sql/protocol.cc for the value and type encoding |
257 | + |
258 | +Tracking the MySQL Protocol |
259 | +=========================== |
260 | + |
261 | +All the examples here are captured with:: |
262 | + |
263 | + $ ngrep -x -q -d lo0 '' 'port 3306' |
264 | + |
265 | +A mysql client logs in |
266 | +---------------------- |
267 | + |
268 | +Taking a look at the packet dump when a mysql-client logs in:: |
269 | + |
270 | + client -> server |
271 | + <connect> |
272 | + |
273 | +The client initiates the communication by connecting to the server.:: |
274 | + |
275 | + server -> client |
276 | + 36 00 00 00 0a 35 2e 35 2e 32 2d 6d 32 00 03 00 6....5.5.2-m2... |
277 | + 00 00 27 75 3e 6f 38 66 79 4e 00 ff f7 08 02 00 ..'u>o8fyN...... |
278 | + 00 00 00 00 00 00 00 00 00 00 00 00 00 57 4d 5d .............WM] |
279 | + 6a 7c 53 68 32 5c 59 2e 73 00 j|Sh2\Y.s. |
280 | + |
281 | +which responds with a handshake packet which contains the version, some flags and a password challenge.:: |
282 | + |
283 | + client -> server |
284 | + 3a 00 00 01 05 a6 03 00 00 00 00 01 08 00 00 00 :............... |
285 | + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ |
286 | + 00 00 00 00 72 6f 6f 74 00 14 cb b5 ea 68 eb 6b ....root.....h.k |
287 | + 3b 03 cb ae fb 9b df 5a cb 0f 6d b5 de fd ;......Z..m... |
288 | + |
289 | +The client answers with username, some flags and the response to the challenge.:: |
290 | + |
291 | + server -> client |
292 | + 07 00 00 02 00 00 00 02 00 00 00 ........... |
293 | + |
294 | +As the client provided the right password and the flags are fine, the server responds with a `OK packet`_. That closes auth-phase |
295 | +and switches to the command-phase.:: |
296 | + |
297 | + client -> server |
298 | + 21 00 00 00 03 73 65 6c 65 63 74 20 40 40 76 65 !....select @@ve |
299 | + 72 73 69 6f 6e 5f 63 6f 6d 6d 65 6e 74 20 6c 69 rsion_comment li |
300 | + 6d 69 74 20 31 mit 1 |
301 | + |
302 | +The mysql client first checks the version string of the server and sends a `COM_QUERY`_ packet.:: |
303 | + |
304 | + server -> client |
305 | + 01 00 00 01 01 27 00 00 02 03 64 65 66 00 00 00 .....'....def... |
306 | + 11 40 40 76 65 72 73 69 6f 6e 5f 63 6f 6d 6d 65 .@@version_comme |
307 | + 6e 74 00 0c 08 00 1c 00 00 00 fd 00 00 1f 00 00 nt.............. |
308 | + 05 00 00 03 fe 00 00 02 00 1d 00 00 04 1c 4d 79 ..............My |
309 | + 53 51 4c 20 43 6f 6d 6d 75 6e 69 74 79 20 53 65 SQL Community Se |
310 | + 72 76 65 72 20 28 47 50 4c 29 05 00 00 05 fe 00 rver (GPL)...... |
311 | + 00 02 00 ... |
312 | + |
313 | +The server responds with a resultset containing the version-string.:: |
314 | + |
315 | + client -> server |
316 | + 0e 00 00 00 03 73 65 6c 65 63 74 20 55 53 45 52 .....select USER |
317 | + 28 29 () |
318 | + |
319 | +For the prompt (\u ...) the mysql client also asks for the current username.:: |
320 | + |
321 | + server -> client |
322 | + 01 00 00 01 01 1c 00 00 02 03 64 65 66 00 00 00 ..........def... |
323 | + 06 55 53 45 52 28 29 00 0c 08 00 4d 00 00 00 fd .USER()....M.... |
324 | + 01 00 1f 00 00 05 00 00 03 fe 00 00 02 00 0f 00 ................ |
325 | + 00 04 0e 72 6f 6f 74 40 6c 6f 63 61 6c 68 6f 73 ...root@localhos |
326 | + 74 05 00 00 05 fe 00 00 02 00 t......... |
327 | + |
328 | +which is 'root@localhost' in this example. |
329 | + |
330 | +MySQL Packet header |
331 | +------------------- |
332 | + |
333 | +The packets that are exchanged between client and server look like:: |
334 | + |
335 | + ... |
336 | + T 127.0.0.1:51656 -> 127.0.0.1:3306 [AP] |
337 | + 01 00 00 00 01 |
338 | + |
339 | +The example shows a COM_QUIT packet. It starts (like all packets) with a 4 byte packet header: |
340 | + |
341 | +* 3 byte length |
342 | +* 1 byte sequence-id |
343 | + |
344 | +The length is the length of the payload of the packet. If the payload is larger than 2^24-2 bytes the length is set to 2^24-1 |
345 | +and a additional packets are sent with the rest of the payload until the payload of a packet is less than 2^24-2 bytes. |
346 | + |
347 | +The sequence-id is incremented with each packet for a sequence of packets. It is reset, when a new command begins. |
348 | + |
349 | +Basic Types |
350 | +=========== |
351 | + |
352 | +Integer |
353 | +------- |
354 | + |
355 | +The MySQL Protocol has a set of possible encodings for integers: |
356 | + |
357 | +* fixed length intergers |
358 | +* length encoded integers |
359 | + |
360 | +fixed length integer |
361 | +.................... |
362 | + |
363 | +The fixed length integers can be of a byte-length 1, 2, 3, 4 or 8 and send their first byte first. The packet length |
364 | +for example is:: |
365 | + |
366 | + 01 00 00 |
367 | + |
368 | +is a 3-byte fixed length integer with the value `1`. |
369 | + |
370 | +length encoded integer |
371 | +...................... |
372 | + |
373 | +In other places integers have a variable size of 1, 3, 4 or 9 bytes depending on their value: |
374 | + |
375 | +========================== ====== |
376 | +value bytes |
377 | +========================== ====== |
378 | +``< 251`` 1 |
379 | +``>= 251 < (2^16 - 1)`` 3 |
380 | +``>= (2^16) < (2^24 - 1)`` 4 |
381 | +``>= (2^24)`` 9 |
382 | +========================== ====== |
383 | + |
384 | +The 1-byte values from 251 to 255 have a special meaning and aren't used for integers. Instead they |
385 | +signal special packets or the 3 other variable length integer types: |
386 | + |
387 | +======== === =========== |
388 | +hex dec description |
389 | +======== === =========== |
390 | +``0xfb`` 251 NULL in the `Text Resultset Row`_ |
391 | +``0xfc`` 252 indicator for a 2-byte integer |
392 | +``0xfd`` 253 indicator for a 3-byte integer |
393 | +``0xfe`` 254 indicator for a 8-byte integer or first byte of a `EOF packet`_ |
394 | +``0xff`` 255 first byte of a `ERR packet`_ |
395 | +======== === =========== |
396 | + |
397 | +They also send least significant byte first. |
398 | + |
399 | +String |
400 | +------ |
401 | + |
402 | +Strings appear in a few forms in the protocol: |
403 | + |
404 | +_`Fixed Length String` |
405 | + Fixed length strings have a known, hardcoded length. An example is the `sql-state` of the `ERR packet`_ which is always 5 byte long. |
406 | + |
407 | +_`NUL-terminated String` |
408 | + Strings that are terminated by a [00] byte. |
409 | + |
410 | +_`Length Encoded String` |
411 | + A length encoded string is a string that is prefixed with `length encoded integer`_ describing the length of the string. |
412 | + |
413 | +_`End-of-packet String` |
414 | + If a string is the last component of a packet, its length can be calculated from the overall-packet length minus the current position. |
415 | + |
416 | +Describing packets |
417 | +------------------ |
418 | + |
419 | +In this document we describe the packets by first defining their payload and provide examples with packet header and payload as |
420 | +you would see it on the wire.:: |
421 | + |
422 | + <packetname> |
423 | + <description> |
424 | + |
425 | + direction: client -> server |
426 | + |
427 | + payload: |
428 | + <type> <description> |
429 | + |
430 | + Example: |
431 | + 01 00 00 00 01 |
432 | + |
433 | +The `<type>` describes the sequence of bytes of the packet: |
434 | + |
435 | +============== =========== |
436 | +type description |
437 | +============== =========== |
438 | +1 1 byte `fixed length integer`_ |
439 | +2 2 byte `fixed length integer`_ |
440 | +3 3 byte `fixed length integer`_ |
441 | +4 4 byte `fixed length integer`_ |
442 | +8 8 byte `fixed length integer`_ |
443 | +lenenc-int `length encoded integer`_ |
444 | +string `NUL-terminated string`_ |
445 | +string[p] `End-of-packet string`_ |
446 | +string[`<n>`] fixed length string with the length `<n>` |
447 | +lenenc-str `length encoded string`_ |
448 | +n a byte sequence of any length |
449 | +============== =========== |
450 | + |
451 | +.. attention:: |
452 | + Some packets have optional fields or a different layout depending on the `capability flags`_ that are sent as part of the |
453 | + `Auth Response Packet`_. |
454 | + |
455 | +If a field has a fixed value its description will show it as hex value in brackets like `[00]`. |
456 | + |
457 | +Generic Response Packets |
458 | +======================== |
459 | + |
460 | +For most of the commands the client sends to the server one of two packets is returned as response: |
461 | + |
462 | +* `OK packet`_ |
463 | +* `ERR packet`_ |
464 | + |
465 | +OK packet |
466 | +--------- |
467 | + |
468 | +:: |
469 | + |
470 | + OK |
471 | + |
472 | + direction: server -> client |
473 | + |
474 | + payload: |
475 | + 1 [00] the OK header |
476 | + lenenc-int affected rows |
477 | + lenenc-int last-insert-id |
478 | + 2 status flags |
479 | + if capabilities & PROTOCOL_41: |
480 | + 2 warnings |
481 | + |
482 | + example: |
483 | + 07 00 00 02 00 00 00 02 00 00 00 ........... |
484 | + |
485 | +Status Flags |
486 | +............ |
487 | + |
488 | +The status flags are a bit-field: |
489 | + |
490 | +====== ============= |
491 | +flag constant name |
492 | +====== ============= |
493 | +0x0001 SERVER_STATUS_IN_TRANS |
494 | +0x0002 SERVER_STATUS_AUTOCOMMIT |
495 | +0x0008 _`SERVER_MORE_RESULTS_EXISTS` |
496 | +0x0010 SERVER_STATUS_NO_GOOD_INDEX_USED |
497 | +0x0020 SERVER_STATUS_NO_INDEX_USED |
498 | +0x0040 SERVER_STATUS_CURSOR_EXISTS |
499 | +0x0080 SERVER_STATUS_LAST_ROW_SENT |
500 | +0x0100 SERVER_STATUS_DB_DROPPED |
501 | +0x0200 SERVER_STATUS_NO_BACKSLASH_ESCAPES |
502 | +0x0400 SERVER_STATUS_METADATA_CHANGED |
503 | +0x0800 SERVER_QUERY_WAS_SLOW |
504 | +0x1000 SERVER_PS_OUT_PARAMS |
505 | +====== ============= |
506 | + |
507 | +ERR packet |
508 | +---------- |
509 | + |
510 | +:: |
511 | + |
512 | + ERR |
513 | + |
514 | + direction: server -> client |
515 | + |
516 | + payload: |
517 | + 1 [ff] the ERR header |
518 | + 2 error code |
519 | + if capabilities & PROTOCOL_41: |
520 | + 1 '#' the sql-state marker |
521 | + string[5] sql-state |
522 | + all protocols: |
523 | + string[p] error-message |
524 | + |
525 | + example: |
526 | + 17 00 00 01 ff 48 04 23 48 59 30 30 30 4e 6f 20 .....H.#HY000No |
527 | + 74 61 62 6c 65 73 20 75 73 65 64 tables used |
528 | + |
529 | + |
530 | +The Auth Phase |
531 | +============== |
532 | + |
533 | +A simple MySQL 4.1+ auth starts with: |
534 | + |
535 | +1. the client connecting to the server |
536 | +2. the server responds with the `Auth Challenge Packet`_ |
537 | +3. the client sends the `Auth Response Packet`_ |
538 | +4. the server responds with `OK Packet`_ |
539 | + |
540 | +If the auth fails, it sends a `ERR Packet`_ instead of a `OK Packet`_ and closes the connection: |
541 | + |
542 | +1. the client connecting to the server |
543 | +2. the server responds with the `Auth Challenge Packet`_ |
544 | +3. the client sends the `Auth Response Packet`_ |
545 | +4. the server responds with `ERR Packet`_ and closes connection |
546 | + |
547 | +or the server denies the client right away if for example its IP is deny: |
548 | + |
549 | +1. the client connecting to the server |
550 | +2. the server responds with the `ERR Packet`_ and closes connection |
551 | + |
552 | +MySQL 4.1+ server also may respond at step 4 with a `Old Password Auth Challenge Packet`_: |
553 | + |
554 | +1. the client connecting to the server |
555 | +2. the server responds with the `Auth Challenge Packet`_ |
556 | +3. the client sends the `Auth Response Packet`_ |
557 | +4. the server responds with the `Old Password Auth Challenge Packet`_ |
558 | +5. the client sends the `Old Password Auth Response Packet`_ |
559 | +6. the server responds with `OK Packet`_ or `ERR Packet`_ and closes the connection |
560 | + |
561 | +Auth Challenge Packet |
562 | +--------------------- |
563 | + |
564 | +As first packet the server sends a Auth Challenge to the client. It contains several other fields: |
565 | + |
566 | +* the protocol version |
567 | +* the mysql-server version string |
568 | +* the server capabilities |
569 | +* the auth challenge |
570 | + |
571 | +The client answers with a `Auth Response Packet`_. |
572 | + |
573 | +:: |
574 | + |
575 | + Auth Challenge Packet |
576 | + response: Auth Response Packet |
577 | + |
578 | + payload: |
579 | + 1 [0a] protocol version |
580 | + string server version |
581 | + 4 connection id |
582 | + string[8] challenge-part-1 |
583 | + 1 [00] filler |
584 | + 2 capability flags |
585 | + 1 character set |
586 | + 2 status flags |
587 | + string[13] reserved |
588 | + if capabilities & SECURE_CONNECTION: |
589 | + string[12] challenge-part-2 |
590 | + 1 [00] filler |
591 | + |
592 | + example: |
593 | + 36 00 00 00 0a 35 2e 35 2e 32 2d 6d 32 00 0b 00 6....5.5.2-m2... |
594 | + 00 00 64 76 48 40 49 2d 43 4a 00 ff f7 08 02 00 ..dvH@I-CJ...... |
595 | + 00 00 00 00 00 00 00 00 00 00 00 00 00 2a 34 64 .............*4d |
596 | + 7c 63 5a 77 6b 34 5e 5d 3a 00 |cZwk4^]:. |
597 | + |
598 | +`status flags` is defined as the `Status Flags`_ of the `OK packet`_. |
599 | + |
600 | +Capability flags |
601 | +................ |
602 | + |
603 | +The capability flags are used by the client and server to indicate which features |
604 | +they support and want to use. |
605 | + |
606 | +====== ============================== ================================== |
607 | +flags constant name description |
608 | +====== ============================== ================================== |
609 | +0x0001 CLIENT_LONG_PASSWORD new more secure passwords |
610 | +0x0002 CLIENT_FOUND_ROWS Found instead of affected rows |
611 | +0x0004 CLIENT_LONG_FLAG Get all column flags |
612 | +0x0008 CLIENT_CONNECT_WITH_DB One can specify db on connect |
613 | +0x0010 CLIENT_NO_SCHEMA Don't allow database.table.column |
614 | +0x0020 CLIENT_COMPRESS Can use compression protocol |
615 | +0x0040 CLIENT_ODBC Odbc client |
616 | +0x0080 _`CLIENT_LOCAL_FILES` Can use LOAD DATA LOCAL |
617 | +0x0100 CLIENT_IGNORE_SPACE Ignore spaces before '(' |
618 | +0x0200 _`CLIENT_PROTOCOL_41` New 4.1 protocol |
619 | +0x0400 CLIENT_INTERACTIVE This is an interactive client |
620 | +0x0800 CLIENT_SSL Switch to SSL after handshake |
621 | +0x1000 CLIENT_IGNORE_SIGPIPE IGNORE sigpipes |
622 | +0x2000 CLIENT_TRANSACTIONS Client knows about transactions |
623 | +0x4000 CLIENT_RESERVED Old flag for 4.1 protocol |
624 | +0x8000 CLIENT_SECURE_CONNECTION New 4.1 authentication |
625 | +====== ============================== ================================== |
626 | + |
627 | + |
628 | + |
629 | +Auth Response Packet |
630 | +-------------------- |
631 | + |
632 | +The client answers the `Auth Challenge Packet`_ with: |
633 | + |
634 | +* its capability flags |
635 | +* its password hashed with challenge |
636 | + |
637 | +If the capabilities have a `CLIENT_PROTOCOL_41`_ flag set the response packet is:: |
638 | + |
639 | + Auth Response Packet 4.1+ |
640 | + payload: |
641 | + 4 capability flags |
642 | + 4 max-packet size |
643 | + 1 character set |
644 | + string[23] reserved |
645 | + string username |
646 | + if capabilities & SECURE_CONNECTION: |
647 | + lenenc-str auth-response |
648 | + else: |
649 | + string auth-response |
650 | + all: |
651 | + string[p] database |
652 | + |
653 | +If not, it is:: |
654 | + |
655 | + Auth Response Packet pre-4.1 |
656 | + payload: |
657 | + 2 capability flags |
658 | + 3 max-packet size |
659 | + string username |
660 | + string auth-response |
661 | + |
662 | +`capability flags` are the same as defined in the `Capability flags`_ of the `Auth Challenge Packet`_ plus: |
663 | + |
664 | +========== ============================== ================================== |
665 | +flags constant name description |
666 | +========== ============================== ================================== |
667 | +0x00010000 _`CLIENT_MULTI_STATEMENTS` Enable/disable multi-stmt support |
668 | +0x00020000 _`CLIENT_MULTI_RESULTS` Enable/disable multi-results |
669 | +0x00040000 _`CLIENT_PS_MULTI_RESULTS` Multi-results in PS-protocol |
670 | +0x40000000 CLIENT_SSL_VERIFY_SERVER_CERT |
671 | +0x80000000 CLIENT_REMEMBER_OPTIONS |
672 | +========== ============================== ================================== |
673 | + |
674 | + |
675 | + |
676 | +Old Password Auth Challenge Packet |
677 | +---------------------------------- |
678 | + |
679 | +In case the server stored a password in the OLD_PASSWORD() fashion for this |
680 | +user the client has to use another hash for the password. |
681 | + |
682 | +:: |
683 | + |
684 | + Old Password Auth Challenge Packet |
685 | + ask the client to send the password hashed with insecure hash-function |
686 | + |
687 | + payload: |
688 | + 1 [fe] |
689 | + |
690 | + example: |
691 | + 01 00 00 02 fe |
692 | + |
693 | +Old Password Auth Response Packet |
694 | +--------------------------------- |
695 | + |
696 | +:: |
697 | + |
698 | + Old Password Auth Response Packet |
699 | + the password hashed with old, insecure hash-function |
700 | + |
701 | + payload: |
702 | + string auth-response |
703 | + |
704 | + example: |
705 | + 09 00 00 03 5c 49 4d 5e 4e 58 4f 47 00 ....\IM^NXOG. |
706 | + |
707 | + |
708 | + |
709 | +The Command Phase |
710 | +================= |
711 | + |
712 | +In the command phase the client sends a command packet with the sequence-id [00]:: |
713 | + |
714 | + 13 00 00 00 03 53 ... |
715 | + 01 00 00 00 01 |
716 | + ^^- command-byte |
717 | + ^^---- sequence-id == 0 |
718 | + |
719 | +The first byte of the payload describes the command-type like: |
720 | + |
721 | +=== ====================== |
722 | +hex constant name |
723 | +=== ====================== |
724 | +00 `COM_SLEEP`_ |
725 | +01 `COM_QUIT`_ |
726 | +02 `COM_INIT_DB`_ |
727 | +03 `COM_QUERY`_ |
728 | +04 `COM_FIELD_LIST`_ |
729 | +05 `COM_CREATE_DB`_ |
730 | +06 `COM_DROP_DB`_ |
731 | +07 `COM_REFRESH`_ |
732 | +08 `COM_SHUTDOWN`_ |
733 | +09 `COM_STATISTICS`_ |
734 | +0a `COM_PROCESS_INFO`_ |
735 | +0b `COM_CONNECT`_ |
736 | +0c `COM_PROCESS_KILL`_ |
737 | +0d `COM_DEBUG`_ |
738 | +0e `COM_PING`_ |
739 | +0f `COM_TIME`_ |
740 | +10 `COM_DELAYED_INSERT`_ |
741 | +11 `COM_CHANGE_USER`_ |
742 | +12 COM_BINLOG_DUMP |
743 | +13 `COM_TABLE_DUMP`_ |
744 | +14 `COM_CONNECT_OUT`_ |
745 | +15 COM_REGISTER_SLAVE |
746 | +16 `COM_STMT_PREPARE`_ |
747 | +17 `COM_STMT_EXECUTE`_ |
748 | +18 `COM_STMT_SEND_LONG_DATA`_ |
749 | +19 `COM_STMT_CLOSE`_ |
750 | +1a `COM_STMT_RESET`_ |
751 | +1b `COM_SET_OPTION`_ |
752 | +1c `COM_STMT_FETCH`_ |
753 | +1d `COM_DAEMON`_ |
754 | +=== ====================== |
755 | + |
756 | +.. _COM_SLEEP: `unhandled commands`_ |
757 | +.. _COM_CONNECT: `unhandled commands`_ |
758 | +.. _COM_TIME: `unhandled commands`_ |
759 | +.. _COM_DELAYED_INSERT: `unhandled commands`_ |
760 | +.. _COM_CONNECT_OUT: `unhandled commands`_ |
761 | +.. _COM_TABLE_DUMP: `unhandled commands`_ |
762 | +.. _COM_DAEMON: `unhandled commands`_ |
763 | + |
764 | +The commands belong to |
765 | + |
766 | +* the `Old Commands`_ |
767 | +* the `Prepared Statements`_ Commands |
768 | +* the `Stored Procedures`_ Commands |
769 | +* or the Replication Commands |
770 | + |
771 | +Old Commands |
772 | +============ |
773 | + |
774 | +The old commands are supported for all MySQL Server versions from 3.23 upwards (and perhaps older). |
775 | + |
776 | +unhandled commands |
777 | +------------------ |
778 | + |
779 | +* COM_SLEEP |
780 | +* COM_CONNECT |
781 | +* COM_TIME |
782 | +* COM_DELAYED_INSERT |
783 | +* COM_DAEMON |
784 | + |
785 | +These commands are only used internally by the server or are deprecated. Sending the to the server always results in a |
786 | +`ERR packet`_. |
787 | + |
788 | +COM_QUIT |
789 | +-------- |
790 | + |
791 | +:: |
792 | + |
793 | + COM_QUIT |
794 | + tells the server that the client wants to close the connection |
795 | + |
796 | + direction: client -> server |
797 | + response: either a connection close or a OK packet |
798 | + |
799 | + payload: |
800 | + 1 [01] COM_QUIT |
801 | + |
802 | + Example: |
803 | + 01 00 00 00 01 |
804 | + |
805 | +COM_INIT_DB |
806 | +----------- |
807 | + |
808 | +:: |
809 | + |
810 | + COM_INIT_DB |
811 | + change the default schema of the connection |
812 | + |
813 | + direction: client -> server |
814 | + response: OK or ERR |
815 | + |
816 | + payload: |
817 | + 1 [02] COM_INIT_DB |
818 | + string[p] schema name |
819 | + |
820 | + example: |
821 | + 05 00 00 00 02 74 65 73 74 .....test |
822 | + |
823 | +COM_QUERY |
824 | +--------- |
825 | + |
826 | +A COM_QUERY is used to send the server a text-based query that is executed immediately. |
827 | + |
828 | +The server replies to a COM_QUERY packet with a `COM_QUERY Response`_. |
829 | + |
830 | +:: |
831 | + |
832 | + COM_QUERY |
833 | + tells the server to execute a text-based query |
834 | + |
835 | + direction: client -> server |
836 | + |
837 | + payload: |
838 | + 1 [03] COM_QUERY |
839 | + string[p] the query the server shall execute |
840 | + |
841 | + Example: |
842 | + 21 00 00 00 03 73 65 6c 65 63 74 20 40 40 76 65 !....select @@ve |
843 | + 72 73 69 6f 6e 5f 63 6f 6d 6d 65 6e 74 20 6c 69 rsion_comment li |
844 | + 6d 69 74 20 31 mit 1 |
845 | + |
846 | +The length of the query-string is a taken from the packet length - 1. |
847 | + |
848 | +API call: `mysql_query() <http://dev.mysql.com/doc/refman/5.1/en/mysql-query.html>`_ |
849 | + |
850 | + |
851 | +COM_QUERY Response |
852 | +.................. |
853 | + |
854 | +The query-response packet is a meta packet which can be one of |
855 | + |
856 | +* a `ERR packet`_ |
857 | +* a `OK packet`_ |
858 | +* a `LOCAL INFILE request`_ |
859 | +* a `Text Resultset`_ |
860 | + |
861 | +The type of the packet is defined by the type-identifier:: |
862 | + |
863 | + COM_QUERY response |
864 | + response to a COM_QUERY packet |
865 | + |
866 | + payload |
867 | + lenenc-int number of columns in the resultset |
868 | + |
869 | +If the number of columns in the resultset is 0, this is a `OK packet`_. |
870 | + |
871 | +If it is not a valid `length encoded integer`_ it is a either a `ERR packet`_ or a `LOCAL INFILE request`_. |
872 | + |
873 | +Text Resultset |
874 | +************** |
875 | + |
876 | +A Text Resultset is a possible `COM_QUERY Response`_. |
877 | + |
878 | +It is made up of a two parts: |
879 | + |
880 | +* the column definition |
881 | +* the rows |
882 | + |
883 | +which consists of a sequence of packets. |
884 | + |
885 | +The column defintion is starts with a packet containing the column-count and is |
886 | +followed by as many `Column Definition`_ packets as we have columns and is terminated |
887 | +by a `EOF packet`. |
888 | + |
889 | +Each row is a packet too. The rows are terminated by another `EOF packet`_. In case |
890 | +the query could generate the column-definition, but generating the rows afterwards |
891 | +failed a `ERR packet`_ may be sent instead of the last `EOF packet`_. |
892 | + |
893 | +* a packet containing a `length encoded integer`_ column-count |
894 | +* column-count * `Column Definition`_ packets |
895 | +* `EOF packet`_ |
896 | +* row-count * packets as in `Text Resultset Row`_ format |
897 | +* `EOF packet`_ |
898 | + |
899 | +In the example we use `|` to show the packet borders:: |
900 | + |
901 | + 01 00 00 01 01|27 00 00 02 03 64 65 66 00 00 00 .....'....def... |
902 | + 11 40 40 76 65 72 73 69 6f 6e 5f 63 6f 6d 6d 65 .@@version_comme |
903 | + 6e 74 00 0c 08 00 1c 00 00 00 fd 00 00 1f 00 00| nt.............. |
904 | + 05 00 00 03 fe 00 00 02 00|1d 00 00 04 1c 4d 79 ..............My |
905 | + 53 51 4c 20 43 6f 6d 6d 75 6e 69 74 79 20 53 65 SQL Community Se |
906 | + 72 76 65 72 20 28 47 50 4c 29|05 00 00 05 fe 00 rver (GPL)...... |
907 | + 00 02 00 ... |
908 | + |
909 | +It has one column (`01 00 00 01 01`) and a field named `@@version_comment` whichs is a `MYSQL_TYPE_VAR_STRING`_ [fd]. |
910 | +It has one row and its one value is `MySQL Community Server (GPL)`. |
911 | + |
912 | +If the `SERVER_MORE_RESULTS_EXISTS`_ flag is set in the last `EOF packet`_ a `multi-resultset`_ is sent. |
913 | + |
914 | + |
915 | +It may also be resultset with an closing `ERR packet`_: |
916 | + |
917 | +* a packet containing a `length encoded integer`_ column-count |
918 | +* column-count * `Column Definition`_ packets |
919 | +* `EOF packet`_ |
920 | +* `ERR packet`_ |
921 | + |
922 | +which is generated for queries like `EXPLAIN SELECT * FROM dual`. |
923 | + |
924 | +Column Types |
925 | +,,,,,,,,,,,, |
926 | + |
927 | +=== ====================== |
928 | +hex constant name |
929 | +=== ====================== |
930 | +00 _`MYSQL_TYPE_DECIMAL` |
931 | +01 _`MYSQL_TYPE_TINY` |
932 | +02 _`MYSQL_TYPE_SHORT` |
933 | +03 _`MYSQL_TYPE_LONG` |
934 | +04 _`MYSQL_TYPE_FLOAT` |
935 | +05 _`MYSQL_TYPE_DOUBLE` |
936 | +06 _`MYSQL_TYPE_NULL` |
937 | +07 _`MYSQL_TYPE_TIMESTAMP` |
938 | +08 _`MYSQL_TYPE_LONGLONG` |
939 | +09 _`MYSQL_TYPE_INT24` |
940 | +0a _`MYSQL_TYPE_DATE` |
941 | +0b _`MYSQL_TYPE_TIME` |
942 | +0c _`MYSQL_TYPE_DATETIME` |
943 | +0d _`MYSQL_TYPE_YEAR` |
944 | +0e _`MYSQL_TYPE_NEWDATE` |
945 | +0f _`MYSQL_TYPE_VARCHAR` |
946 | +10 _`MYSQL_TYPE_BIT` |
947 | +f6 _`MYSQL_TYPE_NEWDECIMAL` |
948 | +f7 _`MYSQL_TYPE_ENUM` |
949 | +f8 _`MYSQL_TYPE_SET` |
950 | +f9 _`MYSQL_TYPE_TINY_BLOB` |
951 | +fa _`MYSQL_TYPE_MEDIUM_BLOB` |
952 | +fb _`MYSQL_TYPE_LONG_BLOB` |
953 | +fc _`MYSQL_TYPE_BLOB` |
954 | +fd _`MYSQL_TYPE_VAR_STRING` |
955 | +fe _`MYSQL_TYPE_STRING` |
956 | +ff _`MYSQL_TYPE_GEOMETRY` |
957 | +=== ====================== |
958 | + |
959 | +Column Definition |
960 | +,,,,,,,,,,,,,,,,, |
961 | + |
962 | +If the PROTOCOL_41 capability is set:: |
963 | + |
964 | + Column Definition - 4.1+ |
965 | + |
966 | + payload: |
967 | + lenenc-str catalog |
968 | + lenenc-str schema |
969 | + lenenc-str table |
970 | + lenenc-str org_table |
971 | + lenenc-str name |
972 | + lenenc-str org_name |
973 | + 1 filler [00] |
974 | + 2 character set |
975 | + 4 column length |
976 | + 1 type |
977 | + 2 flags |
978 | + 1 decimals |
979 | + 2 filler [00] [00] |
980 | + |
981 | +If not :: |
982 | + |
983 | + Column Definition - pre-4.1 |
984 | + |
985 | + payload: |
986 | + lenenc-str table |
987 | + lenenc-str name |
988 | + 1 [03] |
989 | + 3 column length |
990 | + 1 [01] |
991 | + 1 type |
992 | + 1 [02] or [03] |
993 | + if above field == 02: |
994 | + 1 flags |
995 | + if ... == 03: |
996 | + 2 flags |
997 | + all: |
998 | + 1 decimals |
999 | + |
1000 | +Text Resultset Row |
1001 | +,,,,,,,,,,,,,,,,,, |
1002 | + |
1003 | +A row with the data for each column. |
1004 | + |
1005 | +* Integers are sent as `length encoded integer`_. |
1006 | +* everything else sent as `length encoded string`_. |
1007 | + |
1008 | +If a field is NULL `0xfb` is sent as described in `length encoded integer`_. |
1009 | + |
1010 | +EOF packet |
1011 | +,,,,,,,,,, |
1012 | + |
1013 | +:: |
1014 | + |
1015 | + EOF |
1016 | + |
1017 | + direction: server -> client |
1018 | + |
1019 | + payload: |
1020 | + 1 [fe] the EOF header |
1021 | + if capabilities & PROTOCOL_41: |
1022 | + 2 warning count |
1023 | + 2 status flags |
1024 | + |
1025 | + example: |
1026 | + 05 00 00 05 fe 00 00 02 00 |
1027 | + |
1028 | +The status flags are a bit-field as defined in the `Status Flags`_ of the `OK packet`_. |
1029 | + |
1030 | +LOCAL INFILE request |
1031 | +******************** |
1032 | + |
1033 | +If the client wants to LOAD DATA from a LOCAL file into the server it sends:: |
1034 | + |
1035 | + LOAD DATA LOCAL INFILE '<filename>' INTO TABLE <table>; |
1036 | + |
1037 | +The LOCAL keyword triggers the server to send a LOAD INFILE packet asks the client |
1038 | +to send the file via a `LOCAL INFILE data`_ response. |
1039 | + |
1040 | +The client has to set the `CLIENT_LOCAL_FILES`_ capability. |
1041 | + |
1042 | +:: |
1043 | + |
1044 | + LOCAL INFILE packet |
1045 | + |
1046 | + direction: server -> client |
1047 | + response: LOCAL INFILE data |
1048 | + |
1049 | + payload: |
1050 | + 1 [fb] LOCAL INFILE |
1051 | + string[p] filename the client shall send |
1052 | + |
1053 | + example: |
1054 | + 0c 00 00 01 fb 2f 65 74 63 2f 70 61 73 73 77 64 ...../etc/passwd |
1055 | + |
1056 | +LOCAL INFILE data |
1057 | +,,,,,,,,,,,,,,,,, |
1058 | + |
1059 | +The client sends its file data AS IS to the server in response to a `LOCAL INFILE request`_. |
1060 | + |
1061 | +:: |
1062 | + |
1063 | + LOAD INFILE data |
1064 | + |
1065 | + direction: client data |
1066 | + |
1067 | + payload: |
1068 | + n the filedata |
1069 | + |
1070 | +COM_FIELD_LIST |
1071 | +-------------- |
1072 | + |
1073 | +:: |
1074 | + |
1075 | + COM_FIELD_LIST |
1076 | + get the column definition of a tables |
1077 | + |
1078 | + direction: client -> server |
1079 | + response: |
1080 | + |
1081 | + payload: |
1082 | + 1 [04] COM_FIELD_LIST |
1083 | + string table |
1084 | + string[p] field wildcard |
1085 | + |
1086 | +API call: `mysql_list_fields() <http://dev.mysql.com/doc/refman/5.1/en/mysql-list-fields.html>`_ |
1087 | + |
1088 | +COM_FIELD_LIST response |
1089 | +....................... |
1090 | + |
1091 | +The response to a `COM_FIELD_LIST`_ can either be a |
1092 | + |
1093 | +* a `ERR packet`_ or the |
1094 | +* first half of a `Text Resultset`_ |
1095 | + |
1096 | + * a packet containing a `length encoded integer`_ column-count |
1097 | + * column-count * `Column Definition`_ packets |
1098 | + * `EOF packet`_ |
1099 | + |
1100 | +COM_CREATE_DB |
1101 | +------------- |
1102 | + |
1103 | +:: |
1104 | + |
1105 | + COM_CREATE_DB |
1106 | + create a schema |
1107 | + |
1108 | + direction: client -> server |
1109 | + response: OK or ERR |
1110 | + |
1111 | + payload: |
1112 | + 1 [05] COM_CREATE_DB |
1113 | + string[p] schema name |
1114 | + |
1115 | + example: |
1116 | + 05 00 00 00 05 74 65 73 74 .....test |
1117 | + |
1118 | +COM_DROP_DB |
1119 | +----------- |
1120 | + |
1121 | +:: |
1122 | + |
1123 | + COM_DROP_DB |
1124 | + drop a schema |
1125 | + |
1126 | + direction: client -> server |
1127 | + response: OK or ERR |
1128 | + |
1129 | + payload: |
1130 | + 1 [06] COM_DROP_DB |
1131 | + string[p] schema name |
1132 | + |
1133 | + example: |
1134 | + 05 00 00 00 06 74 65 73 74 .....test |
1135 | + |
1136 | +COM_REFRESH |
1137 | +----------- |
1138 | + |
1139 | +a low-level version of several `FLUSH ...` and `RESET ...` commands. |
1140 | + |
1141 | +==== =============== =========== |
1142 | +flag constant name description |
1143 | +==== =============== =========== |
1144 | +0x01 REFRESH_GRANT Refresh grant tables `FLUSH PRIVILEGES` |
1145 | +0x02 REFRESH_LOG Start on new log file `FLUSH LOGS` |
1146 | +0x04 REFRESH_TABLES close all tables `FLUSH TABLES` |
1147 | +0x08 REFRESH_HOSTS Flush host cache `FLUSH HOSTS` |
1148 | +0x10 REFRESH_STATUS Flush status variables `FLUSH STATUS` |
1149 | +0x20 REFRESH_THREADS Flush thread cache |
1150 | +0x40 REFRESH_SLAVE Reset master info and restart slave thread `RESET SLAVE` |
1151 | +0x80 REFRESH_MASTER Remove all bin logs in the index and truncate the index `RESET MASTER` |
1152 | +==== =============== =========== |
1153 | + |
1154 | +:: |
1155 | + |
1156 | + COM_REFRESH |
1157 | + get a list of active threads |
1158 | + |
1159 | + direction: client -> server |
1160 | + response: OK or ERR |
1161 | + |
1162 | + payload: |
1163 | + 1 [07] COM_REFRESH |
1164 | + 1 flags |
1165 | + |
1166 | +COM_SHUTDOWN |
1167 | +------------ |
1168 | + |
1169 | +COM_SHUTDOWN is used to shutdown the mysql-server. |
1170 | + |
1171 | +Even if several shutdown types are define, right now only one is use: SHUTDOWN_WAIT_ALL_BUFFERS |
1172 | + |
1173 | +==== ============================== =========== |
1174 | +type constant name description |
1175 | +==== ============================== =========== |
1176 | +0x00 SHUTDOWN_DEFAULT defaults to SHUTDOWN_WAIT_ALL_BUFFERS |
1177 | +0x01 SHUTDOWN_WAIT_CONNECTIONS wait for existing connections to finish |
1178 | +0x02 SHUTDOWN_WAIT_TRANSACTIONS wait for existing trans to finish |
1179 | +0x08 SHUTDOWN_WAIT_UPDATES wait for existing updates to finish (=> no partial MyISAM update) |
1180 | +0x10 SHUTDOWN_WAIT_ALL_BUFFERS flush InnoDB buffers and other storage engines' buffers |
1181 | +0x11 SHUTDOWN_WAIT_CRITICAL_BUFFERS don't flush InnoDB buffers, flush other storage engines' buffers |
1182 | +0xfe KILL_QUERY |
1183 | +0xff KILL_CONNECTION |
1184 | +==== ============================== =========== |
1185 | + |
1186 | +`SHUTDOWN` privilege is required. |
1187 | + |
1188 | +:: |
1189 | + |
1190 | + COM_SHUTDOWN |
1191 | + get a list of active threads |
1192 | + |
1193 | + direction: client -> server |
1194 | + response: EOF or ERR |
1195 | + |
1196 | + payload: |
1197 | + 1 [08] COM_SHUTDOWN |
1198 | + if shutdown type != 0x00: |
1199 | + 1 shutdown type |
1200 | + |
1201 | +Clients before 4.1.3 don't send the `shutdown type`. `0x00` is assumed in that case. |
1202 | + |
1203 | +COM_STATISTICS |
1204 | +-------------- |
1205 | + |
1206 | +Get a human readable string of internal statistics. |
1207 | + |
1208 | +:: |
1209 | + |
1210 | + COM_STATISTICS |
1211 | + get a list of active threads |
1212 | + |
1213 | + direction: client -> server |
1214 | + response: string[p] |
1215 | + |
1216 | + payload: |
1217 | + 1 [09] COM_STATISTICS |
1218 | + |
1219 | + |
1220 | +COM_PROCESS_INFO |
1221 | +---------------- |
1222 | + |
1223 | +The COM_PROCESS_INFO command is deprecated. `SHOW PROCESSLIST` should be used instead. |
1224 | + |
1225 | +It either returns a: |
1226 | + |
1227 | +* `Text Resultset`_ or |
1228 | +* `ERR packet`_. |
1229 | + |
1230 | +:: |
1231 | + |
1232 | + COM_PROCESS_INFO |
1233 | + get a list of active threads |
1234 | + |
1235 | + direction: client -> server |
1236 | + response: resultset or ERR |
1237 | + |
1238 | + payload: |
1239 | + 1 [0a] COM_PROCCESS_INFO |
1240 | + |
1241 | +COM_PROCESS_KILL |
1242 | +---------------- |
1243 | + |
1244 | +Same as `KILL <id>`. |
1245 | + |
1246 | +:: |
1247 | + |
1248 | + COM_PROCESS_KILL |
1249 | + ask the server to terminate a connection |
1250 | + |
1251 | + direction: client -> server |
1252 | + response: OK or ERR |
1253 | + |
1254 | + payload: |
1255 | + 1 [0c] COM_PROCCESS_KILL |
1256 | + 4 connection id |
1257 | + |
1258 | + |
1259 | +COM_DEBUG |
1260 | +--------- |
1261 | + |
1262 | +COM_DEBUG triggers a dump on internal debug info to stdout of the mysql-server. |
1263 | + |
1264 | +The `SUPER` privilege is required for this operation. |
1265 | + |
1266 | +:: |
1267 | + |
1268 | + COM_DEBUG |
1269 | + dump debug info to stdout |
1270 | + |
1271 | + direction: client -> server |
1272 | + response: EOF or ERR |
1273 | + |
1274 | + payload: |
1275 | + 1 [0d] COM_DEBUG |
1276 | + |
1277 | + |
1278 | +COM_PING |
1279 | +-------- |
1280 | + |
1281 | +:: |
1282 | + |
1283 | + COM_PING |
1284 | + check if the server is alive |
1285 | + |
1286 | + direction: client -> server |
1287 | + response: OK |
1288 | + |
1289 | + payload: |
1290 | + 1 [0e] COM_PING |
1291 | + |
1292 | +COM_CHANGE_USER |
1293 | +--------------- |
1294 | + |
1295 | +COM_CHANGE_USER changes the user of the current connection and reset the connection state. |
1296 | + |
1297 | +* user variables |
1298 | +* temp tables |
1299 | +* prepared statemants |
1300 | +* ... and others |
1301 | + |
1302 | +:: |
1303 | + |
1304 | + COM_CHANGE_USER |
1305 | + change the user of the current connection |
1306 | + |
1307 | + direction: client -> server |
1308 | + response: EOF or ERR |
1309 | + |
1310 | + payload: |
1311 | + 1 [11] COM_CHANGE_USER |
1312 | + string user |
1313 | + if capabilities & SECURE_CONNECTION: |
1314 | + lenenc-str auth-response |
1315 | + else: |
1316 | + string auth-response |
1317 | + all: |
1318 | + string schema-name |
1319 | + if more bytes in packet: |
1320 | + 2 character-set |
1321 | + |
1322 | +Prepared Statements |
1323 | +=================== |
1324 | + |
1325 | +The prepared statement protocol was introduced in MySQL 4.1 and adds a few new commands: |
1326 | + |
1327 | +* `COM_STMT_PREPARE`_ |
1328 | +* `COM_STMT_EXECUTE`_ |
1329 | +* `COM_STMT_CLOSE`_ |
1330 | +* `COM_STMT_RESET`_ |
1331 | +* `COM_STMT_SEND_LONG_DATA`_ |
1332 | + |
1333 | +It also defines a more compact resultset format that is used instead of the `Text Resultset`_ to |
1334 | +return resultsets. |
1335 | + |
1336 | +Keep in mind that not all statements can be prepared: |
1337 | + |
1338 | + http://forge.mysql.com/worklog/task.php?id=2871 |
1339 | + |
1340 | +Binary Protocol Resultset |
1341 | +------------------------- |
1342 | + |
1343 | +Binary Protocol Resultset is similar the `Text Resultset`_. It just contains the rows in |
1344 | +`Binary Protocol Resultset Row`_ format. |
1345 | + |
1346 | +* lenenc column-count |
1347 | +* column-count * `Column Definition`_ |
1348 | +* `EOF packet`_ |
1349 | +* n * rows as in `Binary Protocol Resultset Row`_ |
1350 | +* `EOF packet`_ |
1351 | + |
1352 | +Example:: |
1353 | + |
1354 | + 01 00 00 01 01|1a 00 00 02 03 64 65 66 00 00 00 ..........def... |
1355 | + 04 63 6f 6c 31 00 0c 08 00 06 00 00 00 fd 00 00 .col1........... |
1356 | + 1f 00 00|05 00 00 03 fe 00 00 02 00|09 00 00 04 ................ |
1357 | + 00 00 06 66 6f 6f 62 61 72|05 00 00 05 fe 00 00 ...foobar....... |
1358 | + 02 00 .. |
1359 | + |
1360 | +Binary Protocol Resultset Row |
1361 | +----------------------------- |
1362 | + |
1363 | +A Binary Protocol Resultset Row is made up of the bit-mask containing as many bits as we have columns in the |
1364 | +resultset + 2 and the values for columns that are not NULL in the `Binary Protocol Value`_ format. |
1365 | + |
1366 | +:: |
1367 | + |
1368 | + Binary Protocol Resultset Row |
1369 | + row of a binary resultset (COM_STMT_EXECUTE) |
1370 | + |
1371 | + payload: |
1372 | + 1 packet header [00] |
1373 | + n nul-bit-mask if length (column-count + 7 + 2) / 8 |
1374 | + n values |
1375 | + |
1376 | + example: |
1377 | + 09 00 00 04 00 00 06 66 6f 6f 62 61 72 |
1378 | + |
1379 | +Binary Protocol Value |
1380 | +---------------------- |
1381 | + |
1382 | +* Strings like `MYSQL_TYPE_STRING`_ `MYSQL_TYPE_BLOB`_ and `MYSQL_TYPE_DECIMAL`_:: |
1383 | + |
1384 | + lenenc-str string |
1385 | + |
1386 | + example: |
1387 | + 03 66 6f 6f -- string = "foo" |
1388 | + |
1389 | +* `MYSQL_TYPE_LONGLONG`_:: |
1390 | + |
1391 | + 8 integer least significant byte first |
1392 | + |
1393 | + example: |
1394 | + 01 00 00 00 00 00 00 00 -- int64 = 1 |
1395 | + |
1396 | +* `MYSQL_TYPE_LONG`_ and `MYSQL_TYPE_INT24`_:: |
1397 | + |
1398 | + 4 integer least significant byte first |
1399 | + |
1400 | + example: |
1401 | + 01 00 00 00 -- int32 = 1 |
1402 | + |
1403 | +* `MYSQL_TYPE_SHORT`_:: |
1404 | + |
1405 | + 2 integer least significant byte first |
1406 | + |
1407 | + example: |
1408 | + 01 00 -- int16 = 1 |
1409 | + |
1410 | +* `MYSQL_TYPE_TINY`_:: |
1411 | + |
1412 | + 1 integer |
1413 | + |
1414 | + example: |
1415 | + 01 -- int8 = 1 |
1416 | + |
1417 | +* `MYSQL_TYPE_DOUBLE`_:: |
1418 | + |
1419 | + 8 double |
1420 | + |
1421 | + example: |
1422 | + 66 66 66 66 66 66 24 40 -- double = 10.2 |
1423 | + |
1424 | +* `MYSQL_TYPE_FLOAT`_:: |
1425 | + |
1426 | + 4 float |
1427 | + |
1428 | + example: |
1429 | + 33 33 23 41 -- float = 10.2 |
1430 | + |
1431 | +* `MYSQL_TYPE_DATE`_:: |
1432 | + |
1433 | + 1 [04] length of the encoded value |
1434 | + 2 year |
1435 | + 1 month |
1436 | + 1 day |
1437 | + |
1438 | + example: |
1439 | + 04 da 07 0a 11 -- date = 2010-10-17 |
1440 | + |
1441 | +* `MYSQL_TYPE_DATETIME`_:: |
1442 | + |
1443 | + 1 [0b] length of the encoded value |
1444 | + 2 year |
1445 | + 1 month |
1446 | + 1 day |
1447 | + 1 hour |
1448 | + 1 minutes |
1449 | + 1 seconds |
1450 | + 4 nseconds |
1451 | + |
1452 | + example: |
1453 | + 0b da 07 0a 11 13 1b 1e 01 00 00 00 -- datetime 2010-10-17 19:27:30.000 000 001 |
1454 | + |
1455 | +* `MYSQL_TYPE_TIME`_:: |
1456 | + |
1457 | + 1 [0c] length of the encoded value |
1458 | + 1 sign (1 if minus, 0 for plus) |
1459 | + 4 days |
1460 | + 1 hour |
1461 | + 1 minutes |
1462 | + 1 seconds |
1463 | + 4 nseconds |
1464 | + |
1465 | + example: |
1466 | + 0c 01 78 00 00 00 13 1b 1e 01 00 00 00 -- time -120d 19:27:30.000 000 001 |
1467 | + |
1468 | +* `MYSQL_TYPE_TIMESTAMP`_:: |
1469 | + |
1470 | + 1 [0b] length of the encoded value |
1471 | + 2 year |
1472 | + 1 month |
1473 | + 1 day |
1474 | + 1 hour |
1475 | + 1 minutes |
1476 | + 1 seconds |
1477 | + 4 nseconds |
1478 | + |
1479 | + example: |
1480 | + 0b da 07 0a 11 13 1b 1e 01 00 00 00 -- timestamp |
1481 | + |
1482 | + |
1483 | + |
1484 | +COM_STMT_PREPARE |
1485 | +---------------- |
1486 | + |
1487 | +COM_STMT_PREPARE creates a prepared statement from the passed query string. |
1488 | + |
1489 | +The server returns a `COM_STMT_PREPARE Response`_ which contains a statement-id which is |
1490 | +used to identify the prepared statement. |
1491 | + |
1492 | +:: |
1493 | + |
1494 | + COM_STMT_PREPARE |
1495 | + create a prepared statement |
1496 | + |
1497 | + direction: client -> server |
1498 | + response: COM_STMT_PREPARE response |
1499 | + |
1500 | + payload: |
1501 | + 1 [16] the COM_STMT_PREPARE command |
1502 | + string[p] the query to prepare |
1503 | + |
1504 | + example: |
1505 | + 1c 00 00 00 16 53 45 4c 45 43 54 20 43 4f 4e 43 .....SELECT CONC |
1506 | + 41 54 28 3f 2c 20 3f 29 20 41 53 20 63 6f 6c 31 AT(?, ?) AS col1 |
1507 | + |
1508 | + |
1509 | +COM_STMT_PREPARE response |
1510 | +......................... |
1511 | + |
1512 | +If the `COM_STMT_PREPARE`_ succeeded, it sends: |
1513 | + |
1514 | +* `COM_STMT_PREPARE OK packet`_ |
1515 | +* if num-params > 0 |
1516 | + |
1517 | + * num-params * `Column Definition`_ |
1518 | + * `EOF packet`_ |
1519 | + |
1520 | +* if num-columns > 0 |
1521 | + |
1522 | + * num-colums * `Column Definition`_ |
1523 | + * `EOF packet`_ |
1524 | + |
1525 | +Example:: |
1526 | + |
1527 | + 0c 00 00 01 00 01 00 00 00 01 00 02 00 00 00 00| ................ |
1528 | + 17 00 00 02 03 64 65 66 00 00 00 01 3f 00 0c 3f .....def....?..? |
1529 | + 00 00 00 00 00 fd 80 00 00 00 00|17 00 00 03 03 ................ |
1530 | + 64 65 66 00 00 00 01 3f 00 0c 3f 00 00 00 00 00 def....?..?..... |
1531 | + fd 80 00 00 00 00|05 00 00 04 fe 00 00 02 00|1a ................ |
1532 | + 00 00 05 03 64 65 66 00 00 00 04 63 6f 6c 31 00 ....def....col1. |
1533 | + 0c 3f 00 00 00 00 00 fd 80 00 1f 00 00|05 00 00 .?.............. |
1534 | + 06 fe 00 00 02 00 ...... |
1535 | + |
1536 | +for a query without parameters and resultset like "DO 1" it is:: |
1537 | + |
1538 | + 0c 00 00 01 00 01 00 00 00 00 00 00 00 00 00 00 |
1539 | + |
1540 | +If it failed, a `ERR packet`_ is sent. |
1541 | + |
1542 | +As LOAD DATA isn't supported by `COM_STMT_PREPARE`_ yet, no is `LOCAL INFILE request`_ expected here. |
1543 | +Compare this to `COM_QUERY response`_. |
1544 | + |
1545 | +COM_STMT_PREPARE OK packet |
1546 | +************************** |
1547 | + |
1548 | +The `COM_STMT_PREPARE response`_ starts a packet which contains the meta-information for the following packets:: |
1549 | + |
1550 | + COM_STMT_PREPARE OK |
1551 | + OK response to a COM_STMT_PREPARE packet |
1552 | + |
1553 | + direction: server -> client |
1554 | + |
1555 | + payload: |
1556 | + 1 [00] OK |
1557 | + 4 statement-id |
1558 | + 2 num-columns |
1559 | + 2 num-params |
1560 | + 1 [00] filler |
1561 | + 2 warning count |
1562 | + |
1563 | + |
1564 | +COM_STMT_EXECUTE |
1565 | +---------------- |
1566 | + |
1567 | +COM_STMT_EXECUTE asks the server to execute a prepared statement as identified by `stmt-id`. |
1568 | + |
1569 | +It sends the values for the placeholders of the prepared statement (if it contained any) in |
1570 | +`Binary Protocol Value`_ form. The type of each parameter is made up of two bytes: |
1571 | + |
1572 | +* the type as in `Column Types`_ |
1573 | +* a flag byte which has the highest bit set if the type is unsigned [80] |
1574 | + |
1575 | +The `num-params` used for this packet has to match the `num-params` of the `COM_STMT_PREPARE OK packet`_ |
1576 | +of the corresponding prepared statement. |
1577 | + |
1578 | +The server returns a `COM_STMT_EXECUTE Response`_. |
1579 | + |
1580 | +:: |
1581 | + |
1582 | + COM_STMT_EXECUTE |
1583 | + execute a prepared statement |
1584 | + |
1585 | + direction: client -> server |
1586 | + response: COM_STMT_EXECUTE Response |
1587 | + |
1588 | + payload: |
1589 | + 1 [17] COM_STMT_EXECUTE |
1590 | + 4 stmt-id |
1591 | + 1 flags |
1592 | + 4 iteration-count |
1593 | + if num-params > 0: |
1594 | + n nul-bit-map, length: (num-params+7)/8 |
1595 | + 1 new-params-bound-flag |
1596 | + if new-params-bound-flag == 1: |
1597 | + n type of each parameter, length: num-params * 2 |
1598 | + n value of each parameter |
1599 | + |
1600 | + example: |
1601 | + 12 00 00 00 17 01 00 00 00 00 01 00 00 00 00 01 ................ |
1602 | + 0f 00 03 66 6f 6f ...foo |
1603 | + |
1604 | +The `iteration-count` is always `1`. |
1605 | + |
1606 | +The `flags` are: |
1607 | + |
1608 | +===== ============= |
1609 | +flags constant name |
1610 | +===== ============= |
1611 | +0x00 CURSOR_TYPE_NO_CURSOR |
1612 | +0x01 CURSOR_TYPE_READ_ONLY |
1613 | +0x02 CURSOR_TYPE_FOR_UPDATE |
1614 | +0x04 CURSOR_TYPE_SCROLLABLE |
1615 | +===== ============= |
1616 | + |
1617 | + |
1618 | +COM_STMT_EXECUTE Response |
1619 | +......................... |
1620 | + |
1621 | +Similar to the `COM_QUERY Response`_ a `COM_STMT_EXECUTE`_ either returns: |
1622 | + |
1623 | +* a `OK packet`_ |
1624 | +* a `ERR packet`_ |
1625 | +* or a resultset: `Binary Protocol Resultset`_ |
1626 | + |
1627 | +COM_STMT_SEND_LONG_DATA |
1628 | +----------------------- |
1629 | + |
1630 | +COM_STMT_SEND_LONG_DATA sends the data for a column. Repeating to send it, appends the data to the parameter. |
1631 | + |
1632 | +No response is sent back to the client. |
1633 | + |
1634 | +:: |
1635 | + |
1636 | + COM_STMT_SEND_LONG_DATA |
1637 | + direction: client -> server |
1638 | + response: none |
1639 | + |
1640 | + payload: |
1641 | + 1 [18] COM_STMT_SEND_LONG_DATA |
1642 | + 4 statement-id |
1643 | + 2 param-id |
1644 | + n data |
1645 | + |
1646 | + |
1647 | +COM_STMT_CLOSE |
1648 | +-------------- |
1649 | + |
1650 | +a COM_STMT_CLOSE deallocates a prepared statement |
1651 | + |
1652 | +No response is sent back to the client. |
1653 | + |
1654 | +:: |
1655 | + |
1656 | + COM_STMT_CLOSE |
1657 | + direction: client -> server |
1658 | + response: none |
1659 | + |
1660 | + payload: |
1661 | + 1 [19] COM_STMT_CLOSE |
1662 | + 4 statement-id |
1663 | + |
1664 | + example: |
1665 | + 05 00 00 00 19 01 00 00 00 ......... |
1666 | + |
1667 | + |
1668 | +COM_STMT_RESET |
1669 | +-------------- |
1670 | + |
1671 | +a COM_STMT_RESET resets the data of a prepared statement. Useful in together with `COM_STMT_SEND_LONG_DATA`_. |
1672 | + |
1673 | +The server will send a `OK packet`_ if the statement could be reset, a `ERR packet`_ if not. |
1674 | + |
1675 | +:: |
1676 | + |
1677 | + COM_STMT_RESET |
1678 | + direction: client -> server |
1679 | + response: OK or ERR |
1680 | + |
1681 | + payload: |
1682 | + 1 [1a] COM_STMT_RESET |
1683 | + 4 statement-id |
1684 | + |
1685 | + example: |
1686 | + 05 00 00 00 1a 01 00 00 00 ......... |
1687 | + |
1688 | + |
1689 | +Stored Procedures |
1690 | +================= |
1691 | + |
1692 | +In MySQL 5.0 the protocol was extended to handle: |
1693 | + |
1694 | +* `multi-resultset`_ |
1695 | +* `multi-statement`_ |
1696 | + |
1697 | +Multi-resultset |
1698 | +--------------- |
1699 | + |
1700 | +Multi-resultsets are sent up stored procedures if more than one resultset was generated inside of it:: |
1701 | + |
1702 | + CREATE TEMPORARY TABLE ins ( id INT ); |
1703 | + DROP PROCEDURE IF EXISTS multi; |
1704 | + DELIMITER $$ |
1705 | + CREATE PROCEDURE multi() BEGIN |
1706 | + SELECT 1; |
1707 | + SELECT 1; |
1708 | + INSERT INTO ins VALUES (1); |
1709 | + INSERT INTO ins VALUES (2); |
1710 | + END$$ |
1711 | + DELIMITER ; |
1712 | + |
1713 | + CALL multi(); |
1714 | + DROP TABLE ins; |
1715 | + |
1716 | +results in: |
1717 | + |
1718 | +* a resultset:: |
1719 | + |
1720 | + 01 00 00 01 01 17 00 00 02 03 64 65 66 00 00 00 ..........def... |
1721 | + 01 31 00 0c 3f 00 01 00 00 00 08 81 00 00 00 00 .1..?........... |
1722 | + 05 00 00 03 fe 00 00 0a 00 02 00 00 04 01 31 05 ..............1. |
1723 | + 00 00 05 fe 00 00 0a 00 ........ |
1724 | + |
1725 | + * see the `EOF packet`_: `05 00 00 03 fe 00 00 0a 00` with its status-flag being `0a` |
1726 | + |
1727 | +* the 2nd resultset:: |
1728 | + |
1729 | + 01 00 00 06 01 17 00 00 07 03 64 65 66 00 00 00 ..........def... |
1730 | + 01 31 00 0c 3f 00 01 00 00 00 08 81 00 00 00 00 .1..?........... |
1731 | + 05 00 00 08 fe 00 00 0a 00 02 00 00 09 01 31 05 ..............1. |
1732 | + 00 00 0a fe 00 00 0a 00 ........ |
1733 | + |
1734 | + * see the `EOF packet`_: `05 00 00 0a fe 00 00 0a 00` with its status-flag being `0a` |
1735 | + |
1736 | +* ... and a closing empty resultset, a `OK packet`_:: |
1737 | + |
1738 | + 07 00 00 0b 00 01 00 02 00 00 00 ........... |
1739 | + |
1740 | +`SERVER_MORE_RESULTS_EXISTS`_ is set to indicate that more resultsets will follow. |
1741 | + |
1742 | +The trailing `OK packet`_ is the response to the CALL statement and contains the affected rows of |
1743 | +the last statement. In our case we INSERTed 2 rows, but only the `affected_rows` of the |
1744 | +last INSERT statement is returned as part of the `OK packet`_. If the last statement is a SELECT |
1745 | +the affected rows is 0. |
1746 | + |
1747 | +The client has to announce that it wants multi-resultsets by either setting the `CLIENT_MULTI_RESULTS`_ or |
1748 | +`CLIENT_PS_MULTI_RESULTS`_ capability. |
1749 | + |
1750 | +Multi-statement |
1751 | +--------------- |
1752 | + |
1753 | +A multi-statement is allowing COM_QUERY to send more than one query to the server, separated by a ';'. |
1754 | + |
1755 | +The client has to announce that it wants multi-statements by either setting the `CLIENT_MULTI_STATEMENTS`_ capability |
1756 | +or by using `COM_SET_OPTION`_. |
1757 | + |
1758 | +COM_SET_OPTION |
1759 | +-------------- |
1760 | + |
1761 | +Allows to enable and disable: |
1762 | + |
1763 | +* `CLIENT_MULTI_STATEMENTS`_ |
1764 | + |
1765 | +for the current connection. The option operation is one of: |
1766 | + |
1767 | +=== ============= |
1768 | +op constant name |
1769 | +=== ============= |
1770 | +0 MYSQL_OPTION_MULTI_STATEMENTS_ON |
1771 | +1 MYSQL_OPTION_MULTI_STATEMENTS_OFF |
1772 | +=== ============= |
1773 | + |
1774 | +On success it returns a `EOF packet`_ otherwise a `ERR packet`_. |
1775 | + |
1776 | +:: |
1777 | + |
1778 | + COM_SET_OPTION |
1779 | + set options for the current connection |
1780 | + |
1781 | + response: EOF or ERR |
1782 | + |
1783 | + payload: |
1784 | + 1 [1b] COM_SET_OPTION |
1785 | + 2 option operation |
1786 | + |
1787 | +COM_STMT_FETCH |
1788 | +-------------- |
1789 | + |
1790 | +:: |
1791 | + |
1792 | + COM_STMT_FETCH |
1793 | + |
1794 | + response: binary rows or ERR |
1795 | + |
1796 | + payload: |
1797 | + 1 [1c] COM_STMT_FETCH |
1798 | + 4 stmt-id |
1799 | + 4 num rows |
1800 | + |
1801 | +COM_STMT_FETCH response |
1802 | +....................... |
1803 | + |
1804 | +A fetch may result: |
1805 | + |
1806 | +* a `multi-resultset`_ |
1807 | +* a `ERR packet`_ |
1808 | |
1809 | |
1810 | === renamed file 'doc/scripting.txt' => 'doc/chapter/scripting.txt' |
1811 | --- doc/scripting.txt 2009-06-24 15:04:59 +0000 |
1812 | +++ doc/chapter/scripting.txt 2010-09-27 14:20:48 +0000 |
1813 | @@ -1,96 +1,326 @@ |
1814 | -/** |
1815 | - |
1816 | -@page page-scripting Lua Scripting |
1817 | - |
1818 | -The @ref page-plugin-proxy exposes the internals of the MySQL Protocol into a scripting layer allowing you to |
1819 | -change the behaviour of the proxy with a few lines of code without having to understand all the internals. |
1820 | - |
1821 | -@li @subpage page-examples |
1822 | -@li @subpage page-lua-classes |
1823 | - |
1824 | -@page page-lua-classes Classes |
1825 | - |
1826 | -All structures structures are exposes as tables into Lua. If you want to know the clients username in the @c read_query() function |
1827 | -you can check |
1828 | - |
1829 | -@verbatim |
1830 | - print(proxy.connection.client.username) |
1831 | -@endverbatim |
1832 | - |
1833 | -Please check the class-diagram below: |
1834 | - |
1835 | -@li @c r if it is readable |
1836 | -@li @c w if it is writable |
1837 | -@li @c x if it is a function |
1838 | - |
1839 | -@dotfile doc/lua-classes.dot |
1840 | - |
1841 | -@page page-examples Tutorial |
1842 | - |
1843 | -@li @subpage page-examples-basic |
1844 | -@li @subpage page-examples-exectime |
1845 | -@li @subpage page-examples-rewrite |
1846 | -@li @subpage page-examples-warnings |
1847 | -@li @subpage page-examples-resultset |
1848 | -@li @subpage page-examples-union |
1849 | -@li @subpage page-examples-inject |
1850 | -@li @subpage page-examples-states |
1851 | -@li @subpage page-examples-packets |
1852 | -@li @subpage page-examples-tokenize |
1853 | -@li @subpage page-examples-scramble |
1854 | - |
1855 | -@page page-examples-basic a Minimal Example |
1856 | - |
1857 | -@include examples/tutorial-basic.lua |
1858 | - |
1859 | - |
1860 | - |
1861 | -@page page-examples-exectime Execution Time |
1862 | - |
1863 | -@include examples/tutorial-query-time.lua |
1864 | - |
1865 | - |
1866 | -@page page-examples-rewrite Rewriting Queries |
1867 | - |
1868 | -@include examples/tutorial-rewrite.lua |
1869 | - |
1870 | - |
1871 | -@page page-examples-warnings Logging all warnings |
1872 | - |
1873 | -@include examples/tutorial-warnings.lua |
1874 | - |
1875 | - |
1876 | -@page page-examples-resultset Creating resultsets |
1877 | - |
1878 | -@include examples/tutorial-resultset.lua |
1879 | - |
1880 | - |
1881 | -@page page-examples-union Merging resultsets |
1882 | - |
1883 | -@include examples/tutorial-union.lua |
1884 | - |
1885 | - |
1886 | -@page page-examples-inject Query Injection |
1887 | - |
1888 | -@include examples/tutorial-inject.lua |
1889 | - |
1890 | - |
1891 | -@page page-examples-states States |
1892 | - |
1893 | -@include examples/tutorial-states.lua |
1894 | - |
1895 | - |
1896 | -@page page-examples-packets Exploring the Packets content |
1897 | - |
1898 | -@include examples/tutorial-packets.lua |
1899 | - |
1900 | - |
1901 | -@page page-examples-tokenize Tokenizing Queries |
1902 | - |
1903 | -@include examples/tutorial-tokenize.lua |
1904 | - |
1905 | - |
1906 | -@page page-examples-scramble Using the scramble functions |
1907 | - |
1908 | -@include examples/tutorial-scramble.lua |
1909 | -*/ |
1910 | +Hooks |
1911 | +===== |
1912 | + |
1913 | +connect_server |
1914 | +-------------- |
1915 | + |
1916 | +read_auth |
1917 | +--------- |
1918 | + |
1919 | +read_auth_result |
1920 | +---------------- |
1921 | + |
1922 | +read_query |
1923 | +---------- |
1924 | + |
1925 | +read_query_result |
1926 | +----------------- |
1927 | + |
1928 | +disconnect_client |
1929 | +----------------- |
1930 | + |
1931 | +Modules |
1932 | +======= |
1933 | + |
1934 | +mysql.proto |
1935 | +----------- |
1936 | + |
1937 | +The ``mysql.proto`` module provides encoders and decoders for the packets exchanged between client and server |
1938 | + |
1939 | + |
1940 | +from_err_packet |
1941 | +............... |
1942 | + |
1943 | +Decodes a ERR-packet into a table. |
1944 | + |
1945 | +Parameters: |
1946 | + |
1947 | +``packet`` |
1948 | + (string) mysql packet |
1949 | + |
1950 | + |
1951 | +On success it returns a table containing: |
1952 | + |
1953 | +``errmsg`` |
1954 | + (string) |
1955 | + |
1956 | +``sqlstate`` |
1957 | + (string) |
1958 | + |
1959 | +``errcode`` |
1960 | + (int) |
1961 | + |
1962 | +Otherwise it raises an error. |
1963 | + |
1964 | +to_err_packet |
1965 | +............. |
1966 | + |
1967 | +Encode a table containing a ERR packet into a MySQL packet. |
1968 | + |
1969 | +Parameters: |
1970 | + |
1971 | +``err`` |
1972 | + (table) |
1973 | + |
1974 | + ``errmsg`` |
1975 | + (string) |
1976 | + |
1977 | + ``sqlstate`` |
1978 | + (string) |
1979 | + |
1980 | + ``errcode`` |
1981 | + (int) |
1982 | + |
1983 | +into a MySQL packet. |
1984 | + |
1985 | +Returns a string. |
1986 | + |
1987 | +from_ok_packet |
1988 | +.............. |
1989 | + |
1990 | +Decodes a OK-packet |
1991 | + |
1992 | +``packet`` |
1993 | + (string) mysql packet |
1994 | + |
1995 | + |
1996 | +On success it returns a table containing: |
1997 | + |
1998 | +``server_status`` |
1999 | + (int) bit-mask of the connection status |
2000 | + |
2001 | +``insert_id`` |
2002 | + (int) last used insert id |
2003 | + |
2004 | +``warnings`` |
2005 | + (int) number of warnings for the last executed statement |
2006 | + |
2007 | +``affected_rows`` |
2008 | + (int) rows affected by the last statement |
2009 | + |
2010 | +Otherwise it raises an error. |
2011 | + |
2012 | + |
2013 | +to_ok_packet |
2014 | +............ |
2015 | + |
2016 | +Encode a OK packet |
2017 | + |
2018 | +from_eof_packet |
2019 | +............... |
2020 | + |
2021 | +Decodes a EOF-packet |
2022 | + |
2023 | +Parameters: |
2024 | + |
2025 | +``packet`` |
2026 | + (string) mysql packet |
2027 | + |
2028 | + |
2029 | +On success it returns a table containing: |
2030 | + |
2031 | +``server_status`` |
2032 | + (int) bit-mask of the connection status |
2033 | + |
2034 | +``warnings`` |
2035 | + (int) |
2036 | + |
2037 | +Otherwise it raises an error. |
2038 | + |
2039 | + |
2040 | +to_eof_packet |
2041 | +............. |
2042 | + |
2043 | +from_challenge_packet |
2044 | +..................... |
2045 | + |
2046 | +Decodes a auth-challenge-packet |
2047 | + |
2048 | +Parameters: |
2049 | + |
2050 | +``packet`` |
2051 | + (string) mysql packet |
2052 | + |
2053 | +On success it returns a table containing: |
2054 | + |
2055 | +``protocol_version`` |
2056 | + (int) version of the mysql protocol, usually 10 |
2057 | + |
2058 | +``server_version`` |
2059 | + (int) version of the server as integer: 50506 is MySQL 5.5.6 |
2060 | + |
2061 | +``thread_id`` |
2062 | + (int) connection id |
2063 | + |
2064 | +``capabilities`` |
2065 | + (int) bit-mask of the server capabilities |
2066 | + |
2067 | +``charset`` |
2068 | + (int) server default character-set |
2069 | + |
2070 | +``server_status`` |
2071 | + (int) bit-mask of the connection-status |
2072 | + |
2073 | +``challenge`` |
2074 | + (string) password challenge |
2075 | + |
2076 | + |
2077 | +to_challenge_packet |
2078 | +................... |
2079 | + |
2080 | +Encode a auth-response-packet |
2081 | + |
2082 | +from_response_packet |
2083 | +.................... |
2084 | + |
2085 | +Decodes a auth-response-packet |
2086 | + |
2087 | +Parameters: |
2088 | + |
2089 | +``packet`` |
2090 | + (string) mysql packet |
2091 | + |
2092 | + |
2093 | +to_response_packet |
2094 | +.................. |
2095 | + |
2096 | +from_masterinfo_string |
2097 | +...................... |
2098 | + |
2099 | +Decodes the content of the ``master.info`` file. |
2100 | + |
2101 | + |
2102 | +to_masterinfo_string |
2103 | +.................... |
2104 | + |
2105 | +from_stmt_prepare_packet |
2106 | +........................ |
2107 | + |
2108 | +Decodes a COM_STMT_PREPARE-packet |
2109 | + |
2110 | +Parameters: |
2111 | + |
2112 | +``packet`` |
2113 | + (string) mysql packet |
2114 | + |
2115 | + |
2116 | +On success it returns a table containing: |
2117 | + |
2118 | +``stmt_text`` |
2119 | + (string) |
2120 | + text of the prepared statement |
2121 | + |
2122 | +Otherwise it raises an error. |
2123 | + |
2124 | +from_stmt_prepare_ok_packet |
2125 | +........................... |
2126 | + |
2127 | +Decodes a COM_STMT_PACKET OK-packet |
2128 | + |
2129 | +Parameters: |
2130 | + |
2131 | +``packet`` |
2132 | + (string) mysql packet |
2133 | + |
2134 | + |
2135 | +On success it returns a table containing: |
2136 | + |
2137 | +``stmt_id`` |
2138 | + (int) statement-id |
2139 | + |
2140 | +``num_columns`` |
2141 | + (int) number of columns in the resultset |
2142 | + |
2143 | +``num_params`` |
2144 | + (int) number of parameters |
2145 | + |
2146 | +``warnings`` |
2147 | + (int) warnings generated by the prepare statement |
2148 | + |
2149 | +Otherwise it raises an error. |
2150 | + |
2151 | + |
2152 | +from_stmt_execute_packet |
2153 | +........................ |
2154 | + |
2155 | +Decodes a COM_STMT_EXECUTE-packet |
2156 | + |
2157 | +Parameters: |
2158 | + |
2159 | +``packet`` |
2160 | + (string) mysql packet |
2161 | + |
2162 | +``num_params`` |
2163 | + (int) number of parameters of the corresponding prepared statement |
2164 | + |
2165 | +On success it returns a table containing: |
2166 | + |
2167 | +``stmt_id`` |
2168 | + (int) statemend-id |
2169 | + |
2170 | +``flags`` |
2171 | + (int) flags describing the kind of cursor used |
2172 | + |
2173 | +``iteration_count`` |
2174 | + (int) iteration count: always 1 |
2175 | + |
2176 | +``new_params_bound`` |
2177 | + (bool) |
2178 | + |
2179 | +``params`` |
2180 | + (nil, table) |
2181 | + number-index array of parameters if ``new_params_bound`` is ``true`` |
2182 | + |
2183 | +Each param is a table of: |
2184 | + |
2185 | +``type`` |
2186 | + (int) |
2187 | + MYSQL_TYPE_INT, MYSQL_TYPE_STRING ... and so on |
2188 | + |
2189 | +``value`` |
2190 | + (nil, number, string) |
2191 | + if the value is a NULL, it ``nil`` |
2192 | + if it is a number (_INT, _DOUBLE, ...) it is a ``number`` |
2193 | + otherwise it is a ``string`` |
2194 | + |
2195 | +If decoding fails it raises an error. |
2196 | + |
2197 | +To get the ``num_params`` for this function, you have to track the track the number of parameters as returned |
2198 | +by the `from_stmt_prepare_ok_packet`_. Use `stmt_id_from_stmt_execute_packet`_ to get the ``statement-id`` from |
2199 | +the COM_STMT_EXECUTE packet and lookup your tracked information. |
2200 | + |
2201 | +stmt_id_from_stmt_execute_packet |
2202 | +................................ |
2203 | + |
2204 | +Decodes statement-id from a COM_STMT_EXECUTE-packet |
2205 | + |
2206 | +Parameters: |
2207 | + |
2208 | +``packet`` |
2209 | + (string) mysql packet |
2210 | + |
2211 | + |
2212 | +On success it returns the ``statement-id`` as ``int``. |
2213 | + |
2214 | +Otherwise it raises an error. |
2215 | + |
2216 | +from_stmt_close_packet |
2217 | +...................... |
2218 | + |
2219 | +Decodes a COM_STMT_CLOSE-packet |
2220 | + |
2221 | +Parameters: |
2222 | + |
2223 | +``packet`` |
2224 | + (string) mysql packet |
2225 | + |
2226 | + |
2227 | +On success it returns a table containing: |
2228 | + |
2229 | +``stmt_id`` |
2230 | + (int) |
2231 | + statement-id that shall be closed |
2232 | + |
2233 | +Otherwise it raises an error. |
2234 | + |
2235 | + |
2236 | |
2237 | === added file 'doc/protocol.txt' |
2238 | --- doc/protocol.txt 1970-01-01 00:00:00 +0000 |
2239 | +++ doc/protocol.txt 2010-09-27 14:20:48 +0000 |
2240 | @@ -0,0 +1,8 @@ |
2241 | +============== |
2242 | +MySQL Protocol |
2243 | +============== |
2244 | + |
2245 | +.. contents:: |
2246 | + |
2247 | +.. include:: chapter/protocol.txt |
2248 | + |
2249 | |
2250 | === added file 'doc/scripting.txt' |
2251 | --- doc/scripting.txt 1970-01-01 00:00:00 +0000 |
2252 | +++ doc/scripting.txt 2010-09-27 14:20:48 +0000 |
2253 | @@ -0,0 +1,8 @@ |
2254 | +========================== |
2255 | +Scripting the proxy plugin |
2256 | +========================== |
2257 | + |
2258 | +.. contents:: |
2259 | + |
2260 | +.. include:: chapter/scripting.txt |
2261 | + |
2262 | |
2263 | === modified file 'examples/Makefile.am' |
2264 | --- examples/Makefile.am 2009-07-03 12:28:02 +0000 |
2265 | +++ examples/Makefile.am 2010-09-27 14:20:48 +0000 |
2266 | @@ -8,6 +8,7 @@ |
2267 | tutorial-monitor.lua \ |
2268 | tutorial-packets.lua \ |
2269 | tutorial-query-time.lua \ |
2270 | + tutorial-prep-stmts.lua \ |
2271 | tutorial-resultset.lua \ |
2272 | tutorial-rewrite.lua \ |
2273 | tutorial-routing.lua \ |
2274 | |
2275 | === added file 'examples/tutorial-prep-stmts.lua' |
2276 | --- examples/tutorial-prep-stmts.lua 1970-01-01 00:00:00 +0000 |
2277 | +++ examples/tutorial-prep-stmts.lua 2010-09-27 14:20:48 +0000 |
2278 | @@ -0,0 +1,74 @@ |
2279 | +--[[ $%BEGINLICENSE%$ |
2280 | + Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. |
2281 | + |
2282 | + This program is free software; you can redistribute it and/or |
2283 | + modify it under the terms of the GNU General Public License as |
2284 | + published by the Free Software Foundation; version 2 of the |
2285 | + License. |
2286 | + |
2287 | + This program is distributed in the hope that it will be useful, |
2288 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
2289 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2290 | + GNU General Public License for more details. |
2291 | + |
2292 | + You should have received a copy of the GNU General Public License |
2293 | + along with this program; if not, write to the Free Software |
2294 | + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA |
2295 | + 02110-1301 USA |
2296 | + |
2297 | + $%ENDLICENSE%$ --]] |
2298 | + |
2299 | +local proto = require("mysql.proto") |
2300 | + |
2301 | +local prep_stmts = { } |
2302 | + |
2303 | +function read_query( packet ) |
2304 | + local cmd_type = packet:byte() |
2305 | + if cmd_type == proxy.COM_STMT_PREPARE then |
2306 | + proxy.queries:append(1, packet, { resultset_is_needed = true } ) |
2307 | + return proxy.PROXY_SEND_QUERY |
2308 | + elseif cmd_type == proxy.COM_STMT_EXECUTE then |
2309 | + proxy.queries:append(2, packet, { resultset_is_needed = true } ) |
2310 | + return proxy.PROXY_SEND_QUERY |
2311 | + elseif cmd_type == proxy.COM_STMT_CLOSE then |
2312 | + proxy.queries:append(3, packet, { resultset_is_needed = true } ) |
2313 | + return proxy.PROXY_SEND_QUERY |
2314 | + end |
2315 | +end |
2316 | + |
2317 | +function read_query_result(inj) |
2318 | + if inj.id == 1 then |
2319 | + -- print the query we sent |
2320 | + local stmt_prepare = assert(proto.from_stmt_prepare_packet(inj.query)) |
2321 | + print(("> PREPARE: %s"):format(stmt_prepare.stmt_text)) |
2322 | + |
2323 | + -- and the stmt-id we got for it |
2324 | + if inj.resultset.raw:byte() == 0 then |
2325 | + local stmt_prepare_ok = assert(proto.from_stmt_prepare_ok_packet(inj.resultset.raw)) |
2326 | + print(("< PREPARE: stmt-id = %d (resultset-cols = %d, params = %d)"):format( |
2327 | + stmt_prepare_ok.stmt_id, |
2328 | + stmt_prepare_ok.num_columns, |
2329 | + stmt_prepare_ok.num_params)) |
2330 | + |
2331 | + prep_stmts[stmt_prepare_ok.stmt_id] = { |
2332 | + num_columns = stmt_prepare_ok.num_columns, |
2333 | + num_params = stmt_prepare_ok.num_params, |
2334 | + } |
2335 | + end |
2336 | + elseif inj.id == 2 then |
2337 | + local stmt_id = assert(proto.stmt_id_from_stmt_execute_packet(inj.query)) |
2338 | + local stmt_execute = assert(proto.from_stmt_execute_packet(inj.query, prep_stmts[stmt_id].num_params)) |
2339 | + print(("> EXECUTE: stmt-id = %d"):format(stmt_execute.stmt_id)) |
2340 | + if stmt_execute.new_params_bound then |
2341 | + for ndx, v in ipairs(stmt_execute.params) do |
2342 | + print((" [%d] %s (type = %d)"):format(ndx, tostring(v.value), v.type)) |
2343 | + end |
2344 | + end |
2345 | + elseif inj.id == 3 then |
2346 | + local stmt_close = assert(proto.from_stmt_close_packet(inj.query)) |
2347 | + print(("> CLOSE: stmt-id = %d"):format(stmt_close.stmt_id)) |
2348 | + |
2349 | + prep_stmts[stmt_close.stmt_id] = nil -- cleanup |
2350 | + end |
2351 | +end |
2352 | + |
2353 | |
2354 | === modified file 'lib/mysql-proto.c' |
2355 | --- lib/mysql-proto.c 2010-04-06 14:26:51 +0000 |
2356 | +++ lib/mysql-proto.c 2010-09-27 14:20:48 +0000 |
2357 | @@ -30,6 +30,7 @@ |
2358 | |
2359 | #include "network-mysqld-proto.h" |
2360 | #include "network-mysqld-packet.h" |
2361 | +#include "network_mysqld_type.h" |
2362 | #include "network-mysqld-masterinfo.h" |
2363 | #include "glib-ext.h" |
2364 | #include "lua-env.h" |
2365 | @@ -57,6 +58,10 @@ |
2366 | lua_pushinteger(L, x->y); \ |
2367 | lua_setfield(L, -2, G_STRINGIFY(y)); |
2368 | |
2369 | +#define LUA_EXPORT_BOOL(x, y) \ |
2370 | + lua_pushboolean(L, x->y); \ |
2371 | + lua_setfield(L, -2, G_STRINGIFY(y)); |
2372 | + |
2373 | #define LUA_EXPORT_STR(x, y) \ |
2374 | if (x->y->len) { \ |
2375 | lua_pushlstring(L, S(x->y)); \ |
2376 | @@ -466,6 +471,266 @@ |
2377 | return 1; |
2378 | } |
2379 | |
2380 | +static int lua_proto_get_stmt_prepare_packet (lua_State *L) { |
2381 | + size_t packet_len; |
2382 | + const char *packet_str = luaL_checklstring(L, 1, &packet_len); |
2383 | + network_mysqld_stmt_prepare_packet_t *cmd; |
2384 | + network_packet packet; |
2385 | + GString s; |
2386 | + int err = 0; |
2387 | + |
2388 | + s.str = (char *)packet_str; |
2389 | + s.len = packet_len; |
2390 | + |
2391 | + packet.data = &s; |
2392 | + packet.offset = 0; |
2393 | + |
2394 | + cmd = network_mysqld_stmt_prepare_packet_new(); |
2395 | + |
2396 | + err = err || network_mysqld_proto_get_stmt_prepare_packet(&packet, cmd); |
2397 | + if (err) { |
2398 | + network_mysqld_stmt_prepare_packet_free(cmd); |
2399 | + |
2400 | + luaL_error(L, "%s: network_mysqld_proto_get_stmt_prepare_packet() failed", G_STRLOC); |
2401 | + return 0; |
2402 | + } |
2403 | + |
2404 | + lua_newtable(L); |
2405 | + |
2406 | + LUA_EXPORT_STR(cmd, stmt_text); |
2407 | + |
2408 | + network_mysqld_stmt_prepare_packet_free(cmd); |
2409 | + |
2410 | + return 1; |
2411 | +} |
2412 | + |
2413 | +/** |
2414 | + * transform the OK packet of a COM_STMT_PREPARE result into a table |
2415 | + */ |
2416 | +static int lua_proto_get_stmt_prepare_ok_packet (lua_State *L) { |
2417 | + size_t packet_len; |
2418 | + const char *packet_str = luaL_checklstring(L, 1, &packet_len); |
2419 | + network_mysqld_stmt_prepare_ok_packet_t *cmd; |
2420 | + network_packet packet; |
2421 | + GString s; |
2422 | + int err = 0; |
2423 | + |
2424 | + s.str = (char *)packet_str; |
2425 | + s.len = packet_len; |
2426 | + |
2427 | + packet.data = &s; |
2428 | + packet.offset = 0; |
2429 | + |
2430 | + cmd = network_mysqld_stmt_prepare_ok_packet_new(); |
2431 | + |
2432 | + err = err || network_mysqld_proto_get_stmt_prepare_ok_packet(&packet, cmd); |
2433 | + if (err) { |
2434 | + network_mysqld_stmt_prepare_ok_packet_free(cmd); |
2435 | + |
2436 | + luaL_error(L, "%s: network_mysqld_proto_get_stmt_prepare_ok_packet() failed", G_STRLOC); |
2437 | + return 0; |
2438 | + } |
2439 | + |
2440 | + lua_newtable(L); |
2441 | + |
2442 | + LUA_EXPORT_INT(cmd, stmt_id); |
2443 | + LUA_EXPORT_INT(cmd, num_columns); |
2444 | + LUA_EXPORT_INT(cmd, num_params); |
2445 | + LUA_EXPORT_INT(cmd, warnings); |
2446 | + |
2447 | + network_mysqld_stmt_prepare_ok_packet_free(cmd); |
2448 | + |
2449 | + return 1; |
2450 | +} |
2451 | + |
2452 | +/** |
2453 | + * get the stmt-id from the com-stmt-execute packet |
2454 | + */ |
2455 | +static int lua_proto_get_stmt_execute_packet (lua_State *L) { |
2456 | + size_t packet_len; |
2457 | + const char *packet_str = luaL_checklstring(L, 1, &packet_len); |
2458 | + int param_count = luaL_checkint(L, 2); |
2459 | + network_mysqld_stmt_execute_packet_t *cmd; |
2460 | + network_packet packet; |
2461 | + GString s; |
2462 | + int err = 0; |
2463 | + |
2464 | + s.str = (char *)packet_str; |
2465 | + s.len = packet_len; |
2466 | + |
2467 | + packet.data = &s; |
2468 | + packet.offset = 0; |
2469 | + |
2470 | + cmd = network_mysqld_stmt_execute_packet_new(); |
2471 | + |
2472 | + err = err || network_mysqld_proto_get_stmt_execute_packet(&packet, cmd, param_count); |
2473 | + if (err) { |
2474 | + network_mysqld_stmt_execute_packet_free(cmd); |
2475 | + |
2476 | + luaL_error(L, "%s: network_mysqld_proto_get_stmt_execute_packet() failed", G_STRLOC); |
2477 | + return 0; |
2478 | + } |
2479 | + |
2480 | + lua_newtable(L); |
2481 | + |
2482 | + LUA_EXPORT_INT(cmd, stmt_id); |
2483 | + LUA_EXPORT_INT(cmd, flags); |
2484 | + LUA_EXPORT_INT(cmd, iteration_count); |
2485 | + LUA_EXPORT_BOOL(cmd, new_params_bound); |
2486 | + |
2487 | + if (cmd->new_params_bound) { |
2488 | + guint i; |
2489 | + |
2490 | + lua_newtable(L); |
2491 | + for (i = 0; i < cmd->params->len; i++) { |
2492 | + network_mysqld_type_t *param = g_ptr_array_index(cmd->params, i); |
2493 | + |
2494 | + lua_newtable(L); |
2495 | + lua_pushnumber(L, param->type); |
2496 | + lua_setfield(L, -2, "type"); |
2497 | + |
2498 | + if (param->is_null) { |
2499 | + lua_pushnil(L); |
2500 | + } else { |
2501 | + const char *const_s; |
2502 | + char *_s; |
2503 | + gsize s_len; |
2504 | + guint64 _i; |
2505 | + gboolean is_unsigned; |
2506 | + double d; |
2507 | + |
2508 | + switch (param->type) { |
2509 | + case MYSQL_TYPE_BLOB: |
2510 | + case MYSQL_TYPE_MEDIUM_BLOB: |
2511 | + case MYSQL_TYPE_LONG_BLOB: |
2512 | + case MYSQL_TYPE_STRING: |
2513 | + case MYSQL_TYPE_VARCHAR: |
2514 | + case MYSQL_TYPE_VAR_STRING: |
2515 | + if (0 != network_mysqld_type_get_string_const(param, &const_s, &s_len)) { |
2516 | + return luaL_error(L, "%s: _get_string_const() failed for type = %d", |
2517 | + G_STRLOC, |
2518 | + param->type); |
2519 | + } |
2520 | + |
2521 | + lua_pushlstring(L, const_s, s_len); |
2522 | + break; |
2523 | + case MYSQL_TYPE_TINY: |
2524 | + case MYSQL_TYPE_SHORT: |
2525 | + case MYSQL_TYPE_LONG: |
2526 | + case MYSQL_TYPE_LONGLONG: |
2527 | + if (0 != network_mysqld_type_get_int(param, &_i, &is_unsigned)) { |
2528 | + return luaL_error(L, "%s: _get_int() failed for type = %d", |
2529 | + G_STRLOC, |
2530 | + param->type); |
2531 | + } |
2532 | + |
2533 | + lua_pushinteger(L, _i); |
2534 | + break; |
2535 | + case MYSQL_TYPE_DOUBLE: |
2536 | + case MYSQL_TYPE_FLOAT: |
2537 | + if (0 != network_mysqld_type_get_double(param, &d)) { |
2538 | + return luaL_error(L, "%s: _get_double() failed for type = %d", |
2539 | + G_STRLOC, |
2540 | + param->type); |
2541 | + } |
2542 | + |
2543 | + lua_pushnumber(L, d); |
2544 | + break; |
2545 | + case MYSQL_TYPE_DATETIME: |
2546 | + case MYSQL_TYPE_TIMESTAMP: |
2547 | + case MYSQL_TYPE_DATE: |
2548 | + case MYSQL_TYPE_TIME: |
2549 | + _s = NULL; |
2550 | + s_len = 0; |
2551 | + |
2552 | + if (0 != network_mysqld_type_get_string(param, &_s, &s_len)) { |
2553 | + return luaL_error(L, "%s: _get_string() failed for type = %d", |
2554 | + G_STRLOC, |
2555 | + param->type); |
2556 | + } |
2557 | + |
2558 | + lua_pushlstring(L, _s, s_len); |
2559 | + |
2560 | + if (NULL != _s) g_free(_s); |
2561 | + break; |
2562 | + default: |
2563 | + luaL_error(L, "%s: can't decode type %d yet", |
2564 | + G_STRLOC, |
2565 | + param->type); /* we don't have that value yet */ |
2566 | + break; |
2567 | + } |
2568 | + } |
2569 | + lua_setfield(L, -2, "value"); |
2570 | + lua_rawseti(L, -2, i + 1); |
2571 | + } |
2572 | + lua_setfield(L, -2, "params"); |
2573 | + } |
2574 | + |
2575 | + network_mysqld_stmt_execute_packet_free(cmd); |
2576 | + |
2577 | + return 1; |
2578 | +} |
2579 | + |
2580 | +static int lua_proto_get_stmt_execute_packet_stmt_id (lua_State *L) { |
2581 | + size_t packet_len; |
2582 | + const char *packet_str = luaL_checklstring(L, 1, &packet_len); |
2583 | + network_packet packet; |
2584 | + GString s; |
2585 | + int err = 0; |
2586 | + guint32 stmt_id; |
2587 | + |
2588 | + s.str = (char *)packet_str; |
2589 | + s.len = packet_len; |
2590 | + |
2591 | + packet.data = &s; |
2592 | + packet.offset = 0; |
2593 | + |
2594 | + err = err || network_mysqld_proto_get_stmt_execute_packet_stmt_id(&packet, &stmt_id); |
2595 | + if (err) { |
2596 | + luaL_error(L, "%s: network_mysqld_proto_get_stmt_execute_packet_stmt_id() failed", G_STRLOC); |
2597 | + return 0; |
2598 | + } |
2599 | + |
2600 | + lua_pushinteger(L, stmt_id); |
2601 | + |
2602 | + return 1; |
2603 | +} |
2604 | + |
2605 | + |
2606 | +static int lua_proto_get_stmt_close_packet (lua_State *L) { |
2607 | + size_t packet_len; |
2608 | + const char *packet_str = luaL_checklstring(L, 1, &packet_len); |
2609 | + network_mysqld_stmt_close_packet_t *cmd; |
2610 | + network_packet packet; |
2611 | + GString s; |
2612 | + int err = 0; |
2613 | + |
2614 | + s.str = (char *)packet_str; |
2615 | + s.len = packet_len; |
2616 | + |
2617 | + packet.data = &s; |
2618 | + packet.offset = 0; |
2619 | + |
2620 | + cmd = network_mysqld_stmt_close_packet_new(); |
2621 | + |
2622 | + err = err || network_mysqld_proto_get_stmt_close_packet(&packet, cmd); |
2623 | + if (err) { |
2624 | + network_mysqld_stmt_close_packet_free(cmd); |
2625 | + |
2626 | + luaL_error(L, "%s: network_mysqld_proto_get_stmt_close_packet() failed", G_STRLOC); |
2627 | + return 0; |
2628 | + } |
2629 | + |
2630 | + lua_newtable(L); |
2631 | + |
2632 | + LUA_EXPORT_INT(cmd, stmt_id); |
2633 | + |
2634 | + network_mysqld_stmt_close_packet_free(cmd); |
2635 | + |
2636 | + return 1; |
2637 | +} |
2638 | + |
2639 | + |
2640 | |
2641 | |
2642 | /* |
2643 | @@ -497,6 +762,11 @@ |
2644 | {"to_response_packet", lua_proto_append_response_packet}, |
2645 | {"from_masterinfo_string", lua_proto_get_masterinfo_string}, |
2646 | {"to_masterinfo_string", lua_proto_append_masterinfo_string}, |
2647 | + {"from_stmt_prepare_packet", lua_proto_get_stmt_prepare_packet}, |
2648 | + {"from_stmt_prepare_ok_packet", lua_proto_get_stmt_prepare_ok_packet}, |
2649 | + {"from_stmt_execute_packet", lua_proto_get_stmt_execute_packet}, |
2650 | + {"stmt_id_from_stmt_execute_packet", lua_proto_get_stmt_execute_packet_stmt_id}, |
2651 | + {"from_stmt_close_packet", lua_proto_get_stmt_close_packet}, |
2652 | {NULL, NULL}, |
2653 | }; |
2654 | |
2655 | |
2656 | === modified file 'src/CMakeLists.txt' |
2657 | --- src/CMakeLists.txt 2010-04-06 15:18:47 +0000 |
2658 | +++ src/CMakeLists.txt 2010-09-27 14:20:48 +0000 |
2659 | @@ -69,6 +69,8 @@ |
2660 | network-mysqld.c |
2661 | network-mysqld-lua.c |
2662 | network-mysqld-proto.c |
2663 | + network_mysqld_type.c |
2664 | + network_mysqld_proto_binary.c |
2665 | network-mysqld-binlog.c |
2666 | network-mysqld-packet.c |
2667 | network-mysqld-masterinfo.c |
2668 | @@ -206,6 +208,8 @@ |
2669 | network-mysqld.h |
2670 | network-mysqld-lua.h |
2671 | network-mysqld-proto.h |
2672 | + network_mysqld_type.h |
2673 | + network_mysqld_proto_binary.h |
2674 | network-mysqld-binlog.h |
2675 | network-mysqld-packet.h |
2676 | network-mysqld-masterinfo.h |
2677 | |
2678 | === modified file 'src/Makefile.am' |
2679 | --- src/Makefile.am 2010-05-03 14:26:32 +0000 |
2680 | +++ src/Makefile.am 2010-09-27 14:20:48 +0000 |
2681 | @@ -109,6 +109,8 @@ |
2682 | network-mysqld-proto.c \ |
2683 | network-mysqld-binlog.c \ |
2684 | network-mysqld-packet.c \ |
2685 | + network_mysqld_type.c \ |
2686 | + network_mysqld_proto_binary.c \ |
2687 | network-mysqld-masterinfo.c \ |
2688 | network-conn-pool.c \ |
2689 | network-conn-pool-lua.c \ |
2690 | @@ -137,6 +139,8 @@ |
2691 | network-mysqld-proto.h \ |
2692 | network-mysqld-binlog.h \ |
2693 | network-mysqld-packet.h \ |
2694 | + network_mysqld_type.h \ |
2695 | + network_mysqld_proto_binary.h \ |
2696 | network-mysqld-masterinfo.h \ |
2697 | network-conn-pool.h \ |
2698 | network-conn-pool-lua.h \ |
2699 | |
2700 | === modified file 'src/network-mysqld-packet.c' |
2701 | --- src/network-mysqld-packet.c 2010-05-10 10:31:45 +0000 |
2702 | +++ src/network-mysqld-packet.c 2010-09-27 14:20:48 +0000 |
2703 | @@ -23,8 +23,11 @@ |
2704 | |
2705 | #include <stdlib.h> |
2706 | #include <stdio.h> |
2707 | +#include <string.h> |
2708 | |
2709 | #include "network-mysqld-packet.h" |
2710 | +#include "network_mysqld_type.h" |
2711 | +#include "network_mysqld_proto_binary.h" |
2712 | |
2713 | #include "glib-ext.h" |
2714 | |
2715 | @@ -668,6 +671,57 @@ |
2716 | return is_finished; |
2717 | } |
2718 | |
2719 | +int network_mysqld_proto_get_fielddef(network_packet *packet, network_mysqld_proto_fielddef_t *field, guint32 capabilities) { |
2720 | + int err = 0; |
2721 | + |
2722 | + if (capabilities & CLIENT_PROTOCOL_41) { |
2723 | + err = err || network_mysqld_proto_get_lenenc_string(packet, &field->catalog, NULL); |
2724 | + err = err || network_mysqld_proto_get_lenenc_string(packet, &field->db, NULL); |
2725 | + err = err || network_mysqld_proto_get_lenenc_string(packet, &field->table, NULL); |
2726 | + err = err || network_mysqld_proto_get_lenenc_string(packet, &field->org_table, NULL); |
2727 | + err = err || network_mysqld_proto_get_lenenc_string(packet, &field->name, NULL); |
2728 | + err = err || network_mysqld_proto_get_lenenc_string(packet, &field->org_name, NULL); |
2729 | + |
2730 | + err = err || network_mysqld_proto_skip(packet, 1); /* filler */ |
2731 | + |
2732 | + err = err || network_mysqld_proto_get_int16(packet, (guint16 *)&field->charsetnr); |
2733 | + err = err || network_mysqld_proto_get_int32(packet, (guint32 *)&field->length); |
2734 | + err = err || network_mysqld_proto_get_int8(packet, (guint8 *)&field->type); |
2735 | + err = err || network_mysqld_proto_get_int16(packet, (guint16 *)&field->flags); |
2736 | + err = err || network_mysqld_proto_get_int8(packet, (guint8 *)&field->decimals); |
2737 | + |
2738 | + err = err || network_mysqld_proto_skip(packet, 2); /* filler */ |
2739 | + } else { |
2740 | + guint8 len; |
2741 | + |
2742 | + /* see protocol.cc Protocol::send_fields */ |
2743 | + |
2744 | + err = err || network_mysqld_proto_get_lenenc_string(packet, &field->table, NULL); |
2745 | + err = err || network_mysqld_proto_get_lenenc_string(packet, &field->name, NULL); |
2746 | + err = err || network_mysqld_proto_get_int8(packet, &len); |
2747 | + err = err || (len != 3); |
2748 | + err = err || network_mysqld_proto_get_int24(packet, (guint32 *)&field->length); |
2749 | + err = err || network_mysqld_proto_get_int8(packet, &len); |
2750 | + err = err || (len != 1); |
2751 | + err = err || network_mysqld_proto_get_int8(packet, (guint8 *)&field->type); |
2752 | + err = err || network_mysqld_proto_get_int8(packet, &len); |
2753 | + if (len == 3) { /* the CLIENT_LONG_FLAG is set */ |
2754 | + err = err || network_mysqld_proto_get_int16(packet, (guint16 *)&field->flags); |
2755 | + err = err || network_mysqld_proto_get_int8(packet, (guint8 *)&field->decimals); |
2756 | + } else if (len == 2) { |
2757 | + guint8 flags = 0; |
2758 | + err = err || network_mysqld_proto_get_int8(packet, &flags); |
2759 | + err = err || network_mysqld_proto_get_int8(packet, (guint8 *)&field->decimals); |
2760 | + |
2761 | + if (!err) field->flags = flags; |
2762 | + } else { |
2763 | + /* well */ |
2764 | + } |
2765 | + } |
2766 | + |
2767 | + return err ? -1 : 0; |
2768 | +} |
2769 | + |
2770 | /** |
2771 | * parse the result-set packet and extract the fields |
2772 | * |
2773 | @@ -714,7 +768,7 @@ |
2774 | |
2775 | /* the next chunk, the field-def */ |
2776 | for (i = 0; i < field_count; i++) { |
2777 | - MYSQL_FIELD *field; |
2778 | + network_mysqld_proto_fielddef_t *field; |
2779 | |
2780 | chunk = chunk->next; |
2781 | g_assert(chunk); |
2782 | @@ -722,56 +776,11 @@ |
2783 | packet.data = chunk->data; |
2784 | packet.offset = 0; |
2785 | |
2786 | + field = network_mysqld_proto_fielddef_new(); |
2787 | + |
2788 | err = err || network_mysqld_proto_skip_network_header(&packet); |
2789 | - |
2790 | - field = network_mysqld_proto_fielddef_new(); |
2791 | - |
2792 | - if (capabilities & CLIENT_PROTOCOL_41) { |
2793 | - err = err || network_mysqld_proto_get_lenenc_string(&packet, &field->catalog, NULL); |
2794 | - err = err || network_mysqld_proto_get_lenenc_string(&packet, &field->db, NULL); |
2795 | - err = err || network_mysqld_proto_get_lenenc_string(&packet, &field->table, NULL); |
2796 | - err = err || network_mysqld_proto_get_lenenc_string(&packet, &field->org_table, NULL); |
2797 | - err = err || network_mysqld_proto_get_lenenc_string(&packet, &field->name, NULL); |
2798 | - err = err || network_mysqld_proto_get_lenenc_string(&packet, &field->org_name, NULL); |
2799 | - |
2800 | - err = err || network_mysqld_proto_skip(&packet, 1); /* filler */ |
2801 | - |
2802 | - err = err || network_mysqld_proto_get_int16(&packet, (guint16 *)&field->charsetnr); |
2803 | - err = err || network_mysqld_proto_get_int32(&packet, (guint32 *)&field->length); |
2804 | - err = err || network_mysqld_proto_get_int8(&packet, (guint8 *)&field->type); |
2805 | - err = err || network_mysqld_proto_get_int16(&packet, (guint16 *)&field->flags); |
2806 | - err = err || network_mysqld_proto_get_int8(&packet, (guint8 *)&field->decimals); |
2807 | - |
2808 | - err = err || network_mysqld_proto_skip(&packet, 2); /* filler */ |
2809 | - } else { |
2810 | - guint8 len; |
2811 | - |
2812 | - /* see protocol.cc Protocol::send_fields */ |
2813 | - |
2814 | - err = err || network_mysqld_proto_get_lenenc_string(&packet, &field->table, NULL); |
2815 | - err = err || network_mysqld_proto_get_lenenc_string(&packet, &field->name, NULL); |
2816 | - err = err || network_mysqld_proto_get_int8(&packet, &len); |
2817 | - err = err || (len != 3); |
2818 | - err = err || network_mysqld_proto_get_int24(&packet, (guint32 *)&field->length); |
2819 | - err = err || network_mysqld_proto_get_int8(&packet, &len); |
2820 | - err = err || (len != 1); |
2821 | - err = err || network_mysqld_proto_get_int8(&packet, (guint8 *)&field->type); |
2822 | - err = err || network_mysqld_proto_get_int8(&packet, &len); |
2823 | - if (len == 3) { /* the CLIENT_LONG_FLAG is set */ |
2824 | - err = err || network_mysqld_proto_get_int16(&packet, (guint16 *)&field->flags); |
2825 | - err = err || network_mysqld_proto_get_int8(&packet, (guint8 *)&field->decimals); |
2826 | - } else if (len == 2) { |
2827 | - guint8 flags = 0; |
2828 | - err = err || network_mysqld_proto_get_int8(&packet, &flags); |
2829 | - err = err || network_mysqld_proto_get_int8(&packet, (guint8 *)&field->decimals); |
2830 | - |
2831 | - if (!err) field->flags = flags; |
2832 | - } else { |
2833 | - /* well */ |
2834 | - } |
2835 | - |
2836 | - } |
2837 | - |
2838 | + err = err || network_mysqld_proto_get_fielddef(&packet, field, capabilities); |
2839 | + |
2840 | g_ptr_array_add(fields, field); /* even if we had an error, append it so that we can free it later */ |
2841 | |
2842 | if (err) return NULL; |
2843 | @@ -1358,4 +1367,451 @@ |
2844 | return dst; |
2845 | } |
2846 | |
2847 | +/* |
2848 | + * prepared statements |
2849 | + */ |
2850 | + |
2851 | +/** |
2852 | + * |
2853 | + */ |
2854 | +network_mysqld_stmt_prepare_packet_t *network_mysqld_stmt_prepare_packet_new() { |
2855 | + network_mysqld_stmt_prepare_packet_t *stmt_prepare_packet; |
2856 | + |
2857 | + stmt_prepare_packet = g_slice_new0(network_mysqld_stmt_prepare_packet_t); |
2858 | + stmt_prepare_packet->stmt_text = g_string_new(NULL); |
2859 | + |
2860 | + return stmt_prepare_packet; |
2861 | +} |
2862 | + |
2863 | +/** |
2864 | + * |
2865 | + */ |
2866 | +void network_mysqld_stmt_prepare_packet_free(network_mysqld_stmt_prepare_packet_t *stmt_prepare_packet) { |
2867 | + if (NULL == stmt_prepare_packet) return; |
2868 | + |
2869 | + if (NULL != stmt_prepare_packet->stmt_text) g_string_free(stmt_prepare_packet->stmt_text, TRUE); |
2870 | + |
2871 | + g_slice_free(network_mysqld_stmt_prepare_packet_t, stmt_prepare_packet); |
2872 | +} |
2873 | + |
2874 | +/** |
2875 | + * |
2876 | + */ |
2877 | +int network_mysqld_proto_get_stmt_prepare_packet(network_packet *packet, network_mysqld_stmt_prepare_packet_t *stmt_prepare_packet) { |
2878 | + guint8 packet_type; |
2879 | + |
2880 | + int err = 0; |
2881 | + |
2882 | + err = err || network_mysqld_proto_get_int8(packet, &packet_type); |
2883 | + if (err) return -1; |
2884 | + |
2885 | + if (COM_STMT_PREPARE != packet_type) { |
2886 | + g_critical("%s: expected the first byte to be %02x, got %02x", |
2887 | + G_STRLOC, |
2888 | + COM_STMT_PREPARE, |
2889 | + packet_type); |
2890 | + return -1; |
2891 | + } |
2892 | + |
2893 | + g_string_assign_len(stmt_prepare_packet->stmt_text, packet->data->str + packet->offset, packet->data->len - packet->offset); |
2894 | + |
2895 | + return err ? -1 : 0; |
2896 | +} |
2897 | + |
2898 | +int network_mysqld_proto_append_stmt_prepare_packet(GString *packet, network_mysqld_stmt_prepare_packet_t *stmt_prepare_packet) { |
2899 | + network_mysqld_proto_append_int8(packet, COM_STMT_PREPARE); |
2900 | + g_string_append_len(packet, S(stmt_prepare_packet->stmt_text)); |
2901 | + |
2902 | + return 0; |
2903 | +} |
2904 | + |
2905 | +/** |
2906 | + * |
2907 | + */ |
2908 | +network_mysqld_stmt_prepare_ok_packet_t *network_mysqld_stmt_prepare_ok_packet_new() { |
2909 | + network_mysqld_stmt_prepare_ok_packet_t *stmt_prepare_ok_packet; |
2910 | + |
2911 | + stmt_prepare_ok_packet = g_slice_new0(network_mysqld_stmt_prepare_ok_packet_t); |
2912 | + |
2913 | + return stmt_prepare_ok_packet; |
2914 | +} |
2915 | + |
2916 | +/** |
2917 | + * |
2918 | + */ |
2919 | +void network_mysqld_stmt_prepare_ok_packet_free(network_mysqld_stmt_prepare_ok_packet_t *stmt_prepare_ok_packet) { |
2920 | + if (NULL == stmt_prepare_ok_packet) return; |
2921 | + |
2922 | + g_slice_free(network_mysqld_stmt_prepare_ok_packet_t, stmt_prepare_ok_packet); |
2923 | +} |
2924 | + |
2925 | +/** |
2926 | + * parse the first packet of the OK response for a COM_STMT_PREPARE |
2927 | + * |
2928 | + * it is followed by the field defs for the params and the columns and their EOF packets which is handled elsewhere |
2929 | + */ |
2930 | +int network_mysqld_proto_get_stmt_prepare_ok_packet(network_packet *packet, network_mysqld_stmt_prepare_ok_packet_t *stmt_prepare_ok_packet) { |
2931 | + guint8 packet_type; |
2932 | + guint16 num_columns; |
2933 | + guint16 num_params; |
2934 | + guint16 warnings; |
2935 | + guint32 stmt_id; |
2936 | + |
2937 | + int err = 0; |
2938 | + |
2939 | + err = err || network_mysqld_proto_get_int8(packet, &packet_type); |
2940 | + if (err) return -1; |
2941 | + |
2942 | + if (0x00 != packet_type) { |
2943 | + g_critical("%s: expected the first byte to be %02x, got %02x", |
2944 | + G_STRLOC, |
2945 | + 0x00, |
2946 | + packet_type); |
2947 | + return -1; |
2948 | + } |
2949 | + err = err || network_mysqld_proto_get_int32(packet, &stmt_id); |
2950 | + err = err || network_mysqld_proto_get_int16(packet, &num_columns); |
2951 | + err = err || network_mysqld_proto_get_int16(packet, &num_params); |
2952 | + err = err || network_mysqld_proto_skip(packet, 1); /* the filler */ |
2953 | + err = err || network_mysqld_proto_get_int16(packet, &warnings); |
2954 | + |
2955 | + if (!err) { |
2956 | + stmt_prepare_ok_packet->stmt_id = stmt_id; |
2957 | + stmt_prepare_ok_packet->num_columns = num_columns; |
2958 | + stmt_prepare_ok_packet->num_params = num_params; |
2959 | + stmt_prepare_ok_packet->warnings = warnings; |
2960 | + } |
2961 | + |
2962 | + return err ? -1 : 0; |
2963 | +} |
2964 | + |
2965 | +int network_mysqld_proto_append_stmt_prepare_ok_packet(GString *packet, network_mysqld_stmt_prepare_ok_packet_t *stmt_prepare_ok_packet) { |
2966 | + int err = 0; |
2967 | + |
2968 | + err = err || network_mysqld_proto_append_int8(packet, MYSQLD_PACKET_OK); |
2969 | + err = err || network_mysqld_proto_append_int32(packet, stmt_prepare_ok_packet->stmt_id); |
2970 | + err = err || network_mysqld_proto_append_int16(packet, stmt_prepare_ok_packet->num_columns); |
2971 | + err = err || network_mysqld_proto_append_int16(packet, stmt_prepare_ok_packet->num_params); |
2972 | + err = err || network_mysqld_proto_append_int8(packet, 0x00); |
2973 | + err = err || network_mysqld_proto_append_int16(packet, stmt_prepare_ok_packet->warnings); |
2974 | + |
2975 | + return err ? -1 : 0; |
2976 | +} |
2977 | + |
2978 | +/** |
2979 | + * create a struct for a COM_STMT_EXECUTE packet |
2980 | + */ |
2981 | +network_mysqld_stmt_execute_packet_t *network_mysqld_stmt_execute_packet_new() { |
2982 | + network_mysqld_stmt_execute_packet_t *stmt_execute_packet; |
2983 | + |
2984 | + stmt_execute_packet = g_slice_new0(network_mysqld_stmt_execute_packet_t); |
2985 | + stmt_execute_packet->params = g_ptr_array_new(); |
2986 | + |
2987 | + return stmt_execute_packet; |
2988 | +} |
2989 | + |
2990 | +/** |
2991 | + * free a struct for a COM_STMT_EXECUTE packet |
2992 | + */ |
2993 | +void network_mysqld_stmt_execute_packet_free(network_mysqld_stmt_execute_packet_t *stmt_execute_packet) { |
2994 | + guint i; |
2995 | + |
2996 | + if (NULL == stmt_execute_packet) return; |
2997 | + |
2998 | + for (i = 0; i < stmt_execute_packet->params->len; i++) { |
2999 | + network_mysqld_type_t *param = g_ptr_array_index(stmt_execute_packet->params, i); |
3000 | + |
3001 | + network_mysqld_type_free(param); |
3002 | + } |
3003 | + |
3004 | + g_ptr_array_free(stmt_execute_packet->params, TRUE); |
3005 | + |
3006 | + g_slice_free(network_mysqld_stmt_execute_packet_t, stmt_execute_packet); |
3007 | +} |
3008 | + |
3009 | +/** |
3010 | + * get the statement-id from the COM_STMT_EXECUTE packet |
3011 | + * |
3012 | + * as network_mysqld_proto_get_stmt_execute_packet() needs the parameter count |
3013 | + * to calculate the number of null-bits, we need a way to look it up in a |
3014 | + * external store which is very likely indexed by the stmt-id |
3015 | + * |
3016 | + * @see network_mysqld_proto_get_stmt_execute_packet() |
3017 | + */ |
3018 | +int network_mysqld_proto_get_stmt_execute_packet_stmt_id(network_packet *packet, |
3019 | + guint32 *stmt_id) { |
3020 | + guint8 packet_type; |
3021 | + int err = 0; |
3022 | + |
3023 | + err = err || network_mysqld_proto_get_int8(packet, &packet_type); |
3024 | + if (err) return -1; |
3025 | + |
3026 | + if (COM_STMT_EXECUTE != packet_type) { |
3027 | + g_critical("%s: expected the first byte to be %02x, got %02x", |
3028 | + G_STRLOC, |
3029 | + COM_STMT_EXECUTE, |
3030 | + packet_type); |
3031 | + return -1; |
3032 | + } |
3033 | + |
3034 | + err = err || network_mysqld_proto_get_int32(packet, stmt_id); |
3035 | + |
3036 | + return err ? -1 : 0; |
3037 | +} |
3038 | + |
3039 | +/** |
3040 | + * |
3041 | + * param_count has to be taken from the response of the prepare-stmt-ok packet |
3042 | + * |
3043 | + * @param param_count number of parameters that we expect to see here |
3044 | + */ |
3045 | +int network_mysqld_proto_get_stmt_execute_packet(network_packet *packet, |
3046 | + network_mysqld_stmt_execute_packet_t *stmt_execute_packet, |
3047 | + guint param_count) { |
3048 | + int err = 0; |
3049 | + GString *nul_bits; |
3050 | + gsize nul_bits_len; |
3051 | + |
3052 | + err = err || network_mysqld_proto_get_stmt_execute_packet_stmt_id(packet, &stmt_execute_packet->stmt_id); |
3053 | + err = err || network_mysqld_proto_get_int8(packet, &stmt_execute_packet->flags); |
3054 | + err = err || network_mysqld_proto_get_int32(packet, &stmt_execute_packet->iteration_count); |
3055 | + |
3056 | + if (0 == param_count) { |
3057 | + return err ? -1 : 0; |
3058 | + } |
3059 | + |
3060 | + nul_bits_len = (param_count + 7) / 8; |
3061 | + nul_bits = g_string_sized_new(nul_bits_len); |
3062 | + err = err || network_mysqld_proto_get_gstring_len(packet, nul_bits_len, nul_bits); |
3063 | + err = err || network_mysqld_proto_get_int8(packet, &stmt_execute_packet->new_params_bound); |
3064 | + |
3065 | + if (0 != err) { |
3066 | + g_string_free(nul_bits, TRUE); |
3067 | + |
3068 | + return -1; /* exit early if something failed up to now */ |
3069 | + } |
3070 | + |
3071 | + if (stmt_execute_packet->new_params_bound) { |
3072 | + guint i; |
3073 | + |
3074 | + for (i = 0; 0 == err && i < param_count; i++) { |
3075 | + guint16 param_type; |
3076 | + |
3077 | + err = err || network_mysqld_proto_get_int16(packet, ¶m_type); |
3078 | + |
3079 | + if (0 == err) { |
3080 | + network_mysqld_type_t *param; |
3081 | + |
3082 | + param = network_mysqld_type_new(param_type & 0xff); |
3083 | + if (NULL == param) { |
3084 | + g_critical("%s: couldn't create type = %d", G_STRLOC, param_type & 0xff); |
3085 | + |
3086 | + err = -1; |
3087 | + break; |
3088 | + } |
3089 | + param->is_null = (nul_bits->str[i / 8] & (1 << (i % 8))) != 0; |
3090 | + param->is_unsigned = (param_type & 0x8000) != 0; |
3091 | + |
3092 | + g_ptr_array_add(stmt_execute_packet->params, param); |
3093 | + } |
3094 | + } |
3095 | + |
3096 | + for (i = 0; 0 == err && i < param_count; i++) { |
3097 | + network_mysqld_type_t *param = g_ptr_array_index(stmt_execute_packet->params, i); |
3098 | + |
3099 | + if (!param->is_null) { |
3100 | + err = err || network_mysqld_proto_binary_get_type(packet, param); |
3101 | + } |
3102 | + } |
3103 | + } |
3104 | + |
3105 | + g_string_free(nul_bits, TRUE); |
3106 | + |
3107 | + return err ? -1 : 0; |
3108 | +} |
3109 | + |
3110 | +int network_mysqld_proto_append_stmt_execute_packet(GString *packet, |
3111 | + network_mysqld_stmt_execute_packet_t *stmt_execute_packet, |
3112 | + guint param_count) { |
3113 | + gsize nul_bits_len; |
3114 | + GString *nul_bits; |
3115 | + guint i; |
3116 | + int err = 0; |
3117 | + |
3118 | + nul_bits_len = (param_count + 7) / 8; |
3119 | + nul_bits = g_string_sized_new(nul_bits_len); |
3120 | + memset(nul_bits->str, 0, nul_bits->len); /* set it all to zero */ |
3121 | + |
3122 | + for (i = 0; i < param_count; i++) { |
3123 | + network_mysqld_type_t *param = g_ptr_array_index(stmt_execute_packet->params, i); |
3124 | + |
3125 | + if (param->is_null) { |
3126 | + nul_bits->str[i / 8] |= 1 << (i % 8); |
3127 | + } |
3128 | + } |
3129 | + |
3130 | + network_mysqld_proto_append_int8(packet, COM_STMT_EXECUTE); |
3131 | + network_mysqld_proto_append_int32(packet, stmt_execute_packet->stmt_id); |
3132 | + network_mysqld_proto_append_int8(packet, stmt_execute_packet->flags); |
3133 | + network_mysqld_proto_append_int32(packet, stmt_execute_packet->iteration_count); |
3134 | + g_string_append_len(packet, S(nul_bits)); |
3135 | + network_mysqld_proto_append_int8(packet, stmt_execute_packet->new_params_bound); |
3136 | + |
3137 | + if (stmt_execute_packet->new_params_bound) { |
3138 | + for (i = 0; i < stmt_execute_packet->params->len; i++) { |
3139 | + network_mysqld_type_t *param = g_ptr_array_index(stmt_execute_packet->params, i); |
3140 | + |
3141 | + network_mysqld_proto_append_int16(packet, (guint16)param->type); |
3142 | + } |
3143 | + for (i = 0; 0 == err && i < stmt_execute_packet->params->len; i++) { |
3144 | + network_mysqld_type_t *param = g_ptr_array_index(stmt_execute_packet->params, i); |
3145 | + |
3146 | + if (!param->is_null) { |
3147 | + err = err || network_mysqld_proto_binary_append_type(packet, param); |
3148 | + } |
3149 | + } |
3150 | + } |
3151 | + |
3152 | + return err ? -1 : 0; |
3153 | +} |
3154 | + |
3155 | +/** |
3156 | + * create a struct for a COM_STMT_EXECUTE resultset row |
3157 | + */ |
3158 | +network_mysqld_resultset_row_t *network_mysqld_resultset_row_new() { |
3159 | + return g_ptr_array_new(); |
3160 | +} |
3161 | + |
3162 | +/** |
3163 | + * free a struct for a COM_STMT_EXECUTE resultset row |
3164 | + */ |
3165 | +void network_mysqld_resultset_row_free(network_mysqld_resultset_row_t *row) { |
3166 | + guint i; |
3167 | + |
3168 | + if (NULL == row) return; |
3169 | + |
3170 | + for (i = 0; i < row->len; i++) { |
3171 | + network_mysqld_type_t *field = g_ptr_array_index(row, i); |
3172 | + |
3173 | + network_mysqld_type_free(field); |
3174 | + } |
3175 | + |
3176 | + g_ptr_array_free(row, TRUE); |
3177 | +} |
3178 | + |
3179 | +/** |
3180 | + * get the fields of a row that is in binary row format |
3181 | + */ |
3182 | +int network_mysqld_proto_get_binary_row(network_packet *packet, network_mysqld_proto_fielddefs_t *coldefs, network_mysqld_resultset_row_t *row) { |
3183 | + int err = 0; |
3184 | + guint i; |
3185 | + guint nul_bytes_len; |
3186 | + GString *nul_bytes; |
3187 | + |
3188 | + err = err || network_mysqld_proto_skip(packet, 1); /* the packet header which seems to be always 0 */ |
3189 | + |
3190 | + nul_bytes_len = (coldefs->len + 7 + 2) / 8; /* the first 2 bits are reserved */ |
3191 | + nul_bytes = g_string_sized_new(nul_bytes_len); |
3192 | + err = err || network_mysqld_proto_get_gstring_len(packet, nul_bytes_len, nul_bytes); |
3193 | + |
3194 | + for (i = 0; 0 == err && i < coldefs->len; i++) { |
3195 | + network_mysqld_type_t *param; |
3196 | + network_mysqld_proto_fielddef_t *coldef = g_ptr_array_index(coldefs, i); |
3197 | + |
3198 | + param = network_mysqld_type_new(coldef->type); |
3199 | + if (NULL == param) { |
3200 | + g_critical("%s: coulnd't create type = %d", G_STRLOC, coldef->type); |
3201 | + |
3202 | + err = -1; |
3203 | + break; |
3204 | + } |
3205 | + |
3206 | + if (nul_bytes->str[(i + 2) / 8] & (1 << ((i + 2) % 8))) { |
3207 | + param->is_null = TRUE; |
3208 | + } else { |
3209 | + err = err || network_mysqld_proto_binary_get_type(packet, param); |
3210 | + } |
3211 | + |
3212 | + g_ptr_array_add(row, param); |
3213 | + } |
3214 | + |
3215 | + g_string_free(nul_bytes, TRUE); |
3216 | + |
3217 | + return err ? -1 : 0; |
3218 | +} |
3219 | + |
3220 | +/** |
3221 | + */ |
3222 | +GList *network_mysqld_proto_get_next_binary_row(GList *chunk, network_mysqld_proto_fielddefs_t *fields, network_mysqld_resultset_row_t *row) { |
3223 | + network_packet packet; |
3224 | + int err = 0; |
3225 | + network_mysqld_lenenc_type lenenc_type; |
3226 | + |
3227 | + packet.data = chunk->data; |
3228 | + packet.offset = 0; |
3229 | + |
3230 | + err = err || network_mysqld_proto_skip_network_header(&packet); |
3231 | + |
3232 | + err = err || network_mysqld_proto_peek_lenenc_type(&packet, &lenenc_type); |
3233 | + if (0 != err) return NULL; |
3234 | + |
3235 | + if (NETWORK_MYSQLD_LENENC_TYPE_EOF == lenenc_type) { |
3236 | + /* this is a EOF packet, we are done */ |
3237 | + return NULL; |
3238 | + } |
3239 | + |
3240 | + err = err || network_mysqld_proto_get_binary_row(&packet, fields, row); |
3241 | + |
3242 | + return err ? NULL : chunk->next; |
3243 | +} |
3244 | + |
3245 | +/** |
3246 | + * create a struct for a COM_STMT_CLOSE packet |
3247 | + */ |
3248 | +network_mysqld_stmt_close_packet_t *network_mysqld_stmt_close_packet_new() { |
3249 | + network_mysqld_stmt_close_packet_t *stmt_close_packet; |
3250 | + |
3251 | + stmt_close_packet = g_slice_new0(network_mysqld_stmt_close_packet_t); |
3252 | + |
3253 | + return stmt_close_packet; |
3254 | +} |
3255 | + |
3256 | +/** |
3257 | + * free a struct for a COM_STMT_CLOSE packet |
3258 | + */ |
3259 | +void network_mysqld_stmt_close_packet_free(network_mysqld_stmt_close_packet_t *stmt_close_packet) { |
3260 | + if (NULL == stmt_close_packet) return; |
3261 | + |
3262 | + g_slice_free(network_mysqld_stmt_close_packet_t, stmt_close_packet); |
3263 | +} |
3264 | + |
3265 | +/** |
3266 | + */ |
3267 | +int network_mysqld_proto_get_stmt_close_packet(network_packet *packet, network_mysqld_stmt_close_packet_t *stmt_close_packet) { |
3268 | + guint8 packet_type; |
3269 | + int err = 0; |
3270 | + |
3271 | + err = err || network_mysqld_proto_get_int8(packet, &packet_type); |
3272 | + if (err) return -1; |
3273 | + |
3274 | + if (COM_STMT_CLOSE != packet_type) { |
3275 | + g_critical("%s: expected the first byte to be %02x, got %02x", |
3276 | + G_STRLOC, |
3277 | + COM_STMT_CLOSE, |
3278 | + packet_type); |
3279 | + return -1; |
3280 | + } |
3281 | + |
3282 | + err = err || network_mysqld_proto_get_int32(packet, &stmt_close_packet->stmt_id); |
3283 | + |
3284 | + return err ? -1 : 0; |
3285 | +} |
3286 | + |
3287 | +int network_mysqld_proto_append_stmt_close_packet(GString *packet, network_mysqld_stmt_close_packet_t *stmt_close_packet) { |
3288 | + network_mysqld_proto_append_int8(packet, COM_STMT_CLOSE); |
3289 | + network_mysqld_proto_append_int32(packet, stmt_close_packet->stmt_id); |
3290 | + |
3291 | + return 0; |
3292 | +} |
3293 | + |
3294 | |
3295 | |
3296 | === modified file 'src/network-mysqld-packet.h' |
3297 | --- src/network-mysqld-packet.h 2010-05-10 10:31:45 +0000 |
3298 | +++ src/network-mysqld-packet.h 2010-09-27 14:20:48 +0000 |
3299 | @@ -185,4 +185,58 @@ |
3300 | NETWORK_API int network_mysqld_proto_get_auth_response(network_packet *packet, network_mysqld_auth_response *auth); |
3301 | NETWORK_API network_mysqld_auth_response *network_mysqld_auth_response_copy(network_mysqld_auth_response *src); |
3302 | |
3303 | +/* COM_STMT_* */ |
3304 | + |
3305 | +typedef struct { |
3306 | + GString *stmt_text; |
3307 | +} network_mysqld_stmt_prepare_packet_t; |
3308 | + |
3309 | +NETWORK_API network_mysqld_stmt_prepare_packet_t *network_mysqld_stmt_prepare_packet_new(); |
3310 | +NETWORK_API void network_mysqld_stmt_prepare_packet_free(network_mysqld_stmt_prepare_packet_t *stmt_prepare_packet); |
3311 | +NETWORK_API int network_mysqld_proto_get_stmt_prepare_packet(network_packet *packet, network_mysqld_stmt_prepare_packet_t *stmt_prepare_packet); |
3312 | +NETWORK_API int network_mysqld_proto_append_stmt_prepare_packet(GString *packet, network_mysqld_stmt_prepare_packet_t *stmt_prepare_packet); |
3313 | + |
3314 | +typedef struct { |
3315 | + guint32 stmt_id; |
3316 | + guint16 num_columns; |
3317 | + guint16 num_params; |
3318 | + guint16 warnings; |
3319 | +} network_mysqld_stmt_prepare_ok_packet_t; |
3320 | + |
3321 | +NETWORK_API network_mysqld_stmt_prepare_ok_packet_t *network_mysqld_stmt_prepare_ok_packet_new(void); |
3322 | +NETWORK_API void network_mysqld_stmt_prepare_ok_packet_free(network_mysqld_stmt_prepare_ok_packet_t *stmt_prepare_ok_packet); |
3323 | +NETWORK_API int network_mysqld_proto_get_stmt_prepare_ok_packet(network_packet *packet, network_mysqld_stmt_prepare_ok_packet_t *stmt_prepare_ok_packet); |
3324 | +NETWORK_API int network_mysqld_proto_append_stmt_prepare_ok_packet(GString *packet, network_mysqld_stmt_prepare_ok_packet_t *stmt_prepare_ok_packet); |
3325 | + |
3326 | +typedef struct { |
3327 | + guint32 stmt_id; |
3328 | + guint8 flags; |
3329 | + guint32 iteration_count; |
3330 | + guint8 new_params_bound; |
3331 | + GPtrArray *params; /**< array<network_mysqld_type *> */ |
3332 | +} network_mysqld_stmt_execute_packet_t; |
3333 | + |
3334 | +NETWORK_API network_mysqld_stmt_execute_packet_t *network_mysqld_stmt_execute_packet_new(void); |
3335 | +NETWORK_API void network_mysqld_stmt_execute_packet_free(network_mysqld_stmt_execute_packet_t *stmt_execute_packet); |
3336 | +NETWORK_API int network_mysqld_proto_get_stmt_execute_packet(network_packet *packet, network_mysqld_stmt_execute_packet_t *stmt_execute_packet, guint param_count); |
3337 | +NETWORK_API int network_mysqld_proto_append_stmt_execute_packet(GString *packet, network_mysqld_stmt_execute_packet_t *stmt_execute_packet, guint param_count); |
3338 | +NETWORK_API int network_mysqld_proto_get_stmt_execute_packet_stmt_id(network_packet *packet, guint32 *stmt_id); |
3339 | + |
3340 | + |
3341 | +typedef GPtrArray network_mysqld_resultset_row_t; |
3342 | + |
3343 | +NETWORK_API network_mysqld_resultset_row_t *network_mysqld_resultset_row_new(void); |
3344 | +NETWORK_API void network_mysqld_resultset_row_free(network_mysqld_resultset_row_t *row); |
3345 | +NETWORK_API int network_mysqld_proto_get_binary_row(network_packet *packet, network_mysqld_proto_fielddefs_t *fields, network_mysqld_resultset_row_t *row); |
3346 | +NETWORK_API GList *network_mysqld_proto_get_next_binary_row(GList *chunk, network_mysqld_proto_fielddefs_t *fields, network_mysqld_resultset_row_t *row); |
3347 | + |
3348 | +typedef struct { |
3349 | + guint32 stmt_id; |
3350 | +} network_mysqld_stmt_close_packet_t; |
3351 | + |
3352 | +NETWORK_API network_mysqld_stmt_close_packet_t *network_mysqld_stmt_close_packet_new(void); |
3353 | +NETWORK_API void network_mysqld_stmt_close_packet_free(network_mysqld_stmt_close_packet_t *stmt_close_packet); |
3354 | +NETWORK_API int network_mysqld_proto_get_stmt_close_packet(network_packet *packet, network_mysqld_stmt_close_packet_t *stmt_close_packet); |
3355 | +NETWORK_API int network_mysqld_proto_append_stmt_close_packet(GString *packet, network_mysqld_stmt_close_packet_t *stmt_close_packet); |
3356 | + |
3357 | #endif |
3358 | |
3359 | === modified file 'src/network-mysqld-proto.h' |
3360 | --- src/network-mysqld-proto.h 2010-04-06 14:26:51 +0000 |
3361 | +++ src/network-mysqld-proto.h 2010-09-27 14:20:48 +0000 |
3362 | @@ -111,11 +111,14 @@ |
3363 | NETWORK_API int network_mysqld_proto_peek_lenenc_type(network_packet *packet, network_mysqld_lenenc_type *type); |
3364 | NETWORK_API int network_mysqld_proto_get_lenenc_int(network_packet *packet, guint64 *v); |
3365 | |
3366 | -NETWORK_API MYSQL_FIELD *network_mysqld_proto_fielddef_new(void); |
3367 | -NETWORK_API void network_mysqld_proto_fielddef_free(MYSQL_FIELD *fielddef); |
3368 | +typedef MYSQL_FIELD network_mysqld_proto_fielddef_t; |
3369 | +NETWORK_API network_mysqld_proto_fielddef_t *network_mysqld_proto_fielddef_new(void); |
3370 | +NETWORK_API void network_mysqld_proto_fielddef_free(network_mysqld_proto_fielddef_t *fielddef); |
3371 | +NETWORK_API int network_mysqld_proto_get_fielddef(network_packet *packet, network_mysqld_proto_fielddef_t *field, guint32 capabilities); |
3372 | |
3373 | -NETWORK_API GPtrArray *network_mysqld_proto_fielddefs_new(void); |
3374 | -NETWORK_API void network_mysqld_proto_fielddefs_free(GPtrArray *fielddefs); |
3375 | +typedef GPtrArray network_mysqld_proto_fielddefs_t; |
3376 | +NETWORK_API network_mysqld_proto_fielddefs_t *network_mysqld_proto_fielddefs_new(void); |
3377 | +NETWORK_API void network_mysqld_proto_fielddefs_free(network_mysqld_proto_fielddefs_t *fielddefs); |
3378 | |
3379 | NETWORK_API guint32 network_mysqld_proto_get_packet_len(GString *_header); |
3380 | NETWORK_API guint8 network_mysqld_proto_get_packet_id(GString *_header); |
3381 | |
3382 | === added file 'src/network_mysqld_proto_binary.c' |
3383 | --- src/network_mysqld_proto_binary.c 1970-01-01 00:00:00 +0000 |
3384 | +++ src/network_mysqld_proto_binary.c 2010-09-27 14:20:48 +0000 |
3385 | @@ -0,0 +1,436 @@ |
3386 | +/* $%BEGINLICENSE%$ |
3387 | + Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. |
3388 | + |
3389 | + This program is free software; you can redistribute it and/or |
3390 | + modify it under the terms of the GNU General Public License as |
3391 | + published by the Free Software Foundation; version 2 of the |
3392 | + License. |
3393 | + |
3394 | + This program is distributed in the hope that it will be useful, |
3395 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
3396 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3397 | + GNU General Public License for more details. |
3398 | + |
3399 | + You should have received a copy of the GNU General Public License |
3400 | + along with this program; if not, write to the Free Software |
3401 | + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA |
3402 | + 02110-1301 USA |
3403 | + |
3404 | + $%ENDLICENSE%$ */ |
3405 | + |
3406 | +/** |
3407 | + * codec's for the binary MySQL client protocol |
3408 | + */ |
3409 | + |
3410 | +#include <stdlib.h> |
3411 | +#include <stdio.h> |
3412 | +#include <string.h> |
3413 | + |
3414 | +#include "network_mysqld_proto_binary.h" |
3415 | + |
3416 | +#include "glib-ext.h" |
3417 | +#include "string-len.h" |
3418 | + |
3419 | +/* ints */ |
3420 | +static int network_mysqld_proto_binary_get_int_type(network_packet *packet, network_mysqld_type_t *type) { |
3421 | + int err = 0; |
3422 | + guint8 i8; |
3423 | + guint16 i16; |
3424 | + guint32 i32; |
3425 | + guint64 i64; |
3426 | + |
3427 | + switch (type->type) { |
3428 | + case MYSQL_TYPE_TINY: |
3429 | + err = err || network_mysqld_proto_get_int8(packet, &i8); |
3430 | + err = err || network_mysqld_type_set_int(type, (guint64)i8, type->is_unsigned); |
3431 | + break; |
3432 | + case MYSQL_TYPE_SHORT: |
3433 | + err = err || network_mysqld_proto_get_int16(packet, &i16); |
3434 | + err = err || network_mysqld_type_set_int(type, (guint64)i16, type->is_unsigned); |
3435 | + break; |
3436 | + case MYSQL_TYPE_LONG: |
3437 | + case MYSQL_TYPE_INT24: |
3438 | + err = err || network_mysqld_proto_get_int32(packet, &i32); |
3439 | + err = err || network_mysqld_type_set_int(type, (guint64)i32, type->is_unsigned); |
3440 | + break; |
3441 | + case MYSQL_TYPE_LONGLONG: |
3442 | + err = err || network_mysqld_proto_get_int64(packet, &i64); |
3443 | + err = err || network_mysqld_type_set_int(type, i64, type->is_unsigned); |
3444 | + break; |
3445 | + default: |
3446 | + err = -1; |
3447 | + break; |
3448 | + } |
3449 | + |
3450 | + return err ? -1 : 0; |
3451 | +} |
3452 | + |
3453 | +static int network_mysqld_proto_binary_append_int_type(GString *packet, network_mysqld_type_t *type) { |
3454 | + guint64 i64; |
3455 | + guint8 i8; |
3456 | + guint16 i16; |
3457 | + guint32 i32; |
3458 | + int err = 0; |
3459 | + |
3460 | + err = err || network_mysqld_type_get_int(type, &i64, NULL); |
3461 | + if (0 != err) return -1; |
3462 | + |
3463 | + switch (type->type) { |
3464 | + case MYSQL_TYPE_TINY: |
3465 | + |
3466 | + i8 = i64; |
3467 | + |
3468 | + err = err || network_mysqld_proto_append_int8(packet, i8); |
3469 | + break; |
3470 | + case MYSQL_TYPE_SHORT: |
3471 | + i16 = i64; |
3472 | + |
3473 | + err = err || network_mysqld_proto_append_int16(packet, i16); |
3474 | + break; |
3475 | + case MYSQL_TYPE_LONG: |
3476 | + case MYSQL_TYPE_INT24: |
3477 | + i32 = i64; |
3478 | + |
3479 | + err = err || network_mysqld_proto_append_int32(packet, i32); |
3480 | + break; |
3481 | + case MYSQL_TYPE_LONGLONG: |
3482 | + err = err || network_mysqld_proto_append_int64(packet, i64); |
3483 | + break; |
3484 | + default: |
3485 | + err = -1; |
3486 | + break; |
3487 | + } |
3488 | + |
3489 | + return err ? -1 : 0; |
3490 | +} |
3491 | + |
3492 | +/* double */ |
3493 | +static int network_mysqld_proto_binary_get_double_type(network_packet *packet, network_mysqld_type_t *type) { |
3494 | + int err = 0; |
3495 | + union { |
3496 | + double d; |
3497 | + char d_char_shadow[sizeof(double) + 1]; |
3498 | + } double_copy; |
3499 | + |
3500 | + GString s; |
3501 | + s.str = double_copy.d_char_shadow; |
3502 | + s.len = 0; |
3503 | + s.allocated_len = sizeof(double_copy.d_char_shadow); |
3504 | + |
3505 | + err = err || network_mysqld_proto_get_gstring_len(packet, sizeof(double), &s); |
3506 | + err = err || network_mysqld_type_set_double(type, double_copy.d); |
3507 | + |
3508 | + return err ? -1 : 0; |
3509 | +} |
3510 | + |
3511 | +static int network_mysqld_proto_binary_append_double_type(GString *packet, network_mysqld_type_t *type) { |
3512 | + union { |
3513 | + double d; |
3514 | + char d_char_shadow[sizeof(double)]; |
3515 | + } double_copy; |
3516 | + int err = 0; |
3517 | + |
3518 | + err = err || network_mysqld_type_get_double(type, &double_copy.d); |
3519 | + if (0 != err) return -1; |
3520 | + |
3521 | + g_string_append_len(packet, double_copy.d_char_shadow, sizeof(double)); |
3522 | + |
3523 | + return err ? -1 : 0; |
3524 | +} |
3525 | + |
3526 | +/* float */ |
3527 | +static int network_mysqld_proto_binary_get_float_type(network_packet *packet, network_mysqld_type_t *type) { |
3528 | + int err = 0; |
3529 | + union { |
3530 | + float d; |
3531 | + char d_char_shadow[sizeof(float) + 1]; |
3532 | + } float_copy; |
3533 | + |
3534 | + GString s; |
3535 | + s.str = float_copy.d_char_shadow; |
3536 | + s.len = 0; |
3537 | + s.allocated_len = sizeof(float_copy.d_char_shadow); |
3538 | + |
3539 | + err = err || network_mysqld_proto_get_gstring_len(packet, sizeof(float), &s); |
3540 | + err = err || network_mysqld_type_set_double(type, (double)float_copy.d); |
3541 | + |
3542 | + return err ? -1 : 0; |
3543 | +} |
3544 | + |
3545 | +static int network_mysqld_proto_binary_append_float_type(GString *packet, network_mysqld_type_t *type) { |
3546 | + double d; |
3547 | + int err = 0; |
3548 | + |
3549 | + err = err || network_mysqld_type_get_double(type, &d); /* get our float as double */ |
3550 | + |
3551 | + if (0 == err) { |
3552 | + /* copy the float directly without switching byte-order */ |
3553 | + union { |
3554 | + float f; |
3555 | + char f_char_shadow[sizeof(float)]; |
3556 | + } float_copy; /* shadow the float with a equally sized char to be able to copy it without extra type-casting */ |
3557 | + |
3558 | + float_copy.f = (float)d; |
3559 | + |
3560 | + g_string_append_len(packet, float_copy.f_char_shadow, sizeof(float)); |
3561 | + } |
3562 | + |
3563 | + return err ? -1 : 0; |
3564 | +} |
3565 | + |
3566 | +/* all kinds of strings */ |
3567 | +static int network_mysqld_proto_binary_get_string_type(network_packet *packet, network_mysqld_type_t *type) { |
3568 | + GString *str; |
3569 | + int err = 0; |
3570 | + |
3571 | + str = g_string_new(NULL); |
3572 | + |
3573 | + err = err || network_mysqld_proto_get_lenenc_gstring(packet, str); |
3574 | + |
3575 | + network_mysqld_type_set_string(type, S(str)); |
3576 | + |
3577 | + g_string_free(str, TRUE); |
3578 | + |
3579 | + return err ? -1 : 0; |
3580 | +} |
3581 | + |
3582 | +static int network_mysqld_proto_binary_append_string_type(GString *packet, network_mysqld_type_t *type) { |
3583 | + const char *s; |
3584 | + gsize s_len; |
3585 | + int err = 0; |
3586 | + |
3587 | + err = err || network_mysqld_type_get_string_const(type, &s, &s_len); |
3588 | + err = err || network_mysqld_proto_append_lenenc_string_len(packet, s, s_len); |
3589 | + |
3590 | + return err ? -1 : 0; |
3591 | +} |
3592 | + |
3593 | +/* all kinds of time */ |
3594 | + |
3595 | +/** |
3596 | + * extract the date from a binary resultset row |
3597 | + */ |
3598 | +static int network_mysqld_proto_binary_get_date_type(network_packet *packet, network_mysqld_type_t *type) { |
3599 | + int err = 0; |
3600 | + guint8 len; |
3601 | + network_mysqld_type_date_t date; |
3602 | + |
3603 | + err = err || network_mysqld_proto_get_int8(packet, &len); |
3604 | + |
3605 | + /* check the valid lengths |
3606 | + */ |
3607 | + switch (len) { |
3608 | + case 11: /* date + time + ms */ |
3609 | + case 7: /* date + time ( ms is .0000 ) */ |
3610 | + case 4: /* date ( time is 00:00:00 )*/ |
3611 | + case 0: /* date == 0000-00-00 */ |
3612 | + break; |
3613 | + default: |
3614 | + return -1; |
3615 | + } |
3616 | + |
3617 | + memset(&date, 0, sizeof(date)); |
3618 | + if (len > 0) { |
3619 | + err = err || network_mysqld_proto_get_int16(packet, &date.year); |
3620 | + err = err || network_mysqld_proto_get_int8(packet, &date.month); |
3621 | + err = err || network_mysqld_proto_get_int8(packet, &date.day); |
3622 | + |
3623 | + if (len > 4) { |
3624 | + err = err || network_mysqld_proto_get_int8(packet, &date.hour); |
3625 | + err = err || network_mysqld_proto_get_int8(packet, &date.min); |
3626 | + err = err || network_mysqld_proto_get_int8(packet, &date.sec); |
3627 | + |
3628 | + if (len > 7) { |
3629 | + err = err || network_mysqld_proto_get_int32(packet, &date.nsec); |
3630 | + } |
3631 | + } |
3632 | + } |
3633 | + |
3634 | + if (0 == err) { |
3635 | + err = err || network_mysqld_type_set_date(type, &date); |
3636 | + } |
3637 | + |
3638 | + return err ? -1 : 0; |
3639 | +} |
3640 | + |
3641 | +static int network_mysqld_proto_binary_append_date_type(GString G_GNUC_UNUSED *packet, network_mysqld_type_t G_GNUC_UNUSED *type) { |
3642 | + /* not implemented yet */ |
3643 | + return -1; |
3644 | +} |
3645 | + |
3646 | +/** |
3647 | + * extract the time from a binary resultset row |
3648 | + */ |
3649 | +static int network_mysqld_proto_binary_get_time_type(network_packet *packet, network_mysqld_type_t *type) { |
3650 | + int err = 0; |
3651 | + guint8 len; |
3652 | + network_mysqld_type_time_t t; |
3653 | + |
3654 | + err = err || network_mysqld_proto_get_int8(packet, &len); |
3655 | + |
3656 | + /* check the valid lengths |
3657 | + */ |
3658 | + switch (len) { |
3659 | + case 12: /* day + time + ms */ |
3660 | + case 8: /* day + time ( ms is .0000 ) */ |
3661 | + case 0: /* time == 00:00:00 */ |
3662 | + break; |
3663 | + default: |
3664 | + return -1; |
3665 | + } |
3666 | + |
3667 | + memset(&t, 0, sizeof(t)); |
3668 | + if (len > 0) { |
3669 | + err = err || network_mysqld_proto_get_int8(packet, &t.sign); |
3670 | + err = err || network_mysqld_proto_get_int32(packet, &t.days); |
3671 | + |
3672 | + err = err || network_mysqld_proto_get_int8(packet, &t.hour); |
3673 | + err = err || network_mysqld_proto_get_int8(packet, &t.min); |
3674 | + err = err || network_mysqld_proto_get_int8(packet, &t.sec); |
3675 | + |
3676 | + if (len > 8) { |
3677 | + err = err || network_mysqld_proto_get_int32(packet, &t.nsec); |
3678 | + } |
3679 | + } |
3680 | + |
3681 | + if (0 == err) { |
3682 | + err = err || network_mysqld_type_set_time(type, &t); |
3683 | + } |
3684 | + |
3685 | + return err ? -1 : 0; |
3686 | +} |
3687 | + |
3688 | +static int network_mysqld_proto_binary_append_time_type(GString G_GNUC_UNUSED *packet, network_mysqld_type_t G_GNUC_UNUSED *type) { |
3689 | + /* not implemented yet */ |
3690 | + return -1; |
3691 | +} |
3692 | + |
3693 | +/** |
3694 | + * valid types for prepared statements parameters we receive from the client |
3695 | + */ |
3696 | +gboolean network_mysql_proto_binary_type_is_valid_input(enum enum_field_types field_type) { |
3697 | + switch (field_type) { |
3698 | + case MYSQL_TYPE_TINY: |
3699 | + case MYSQL_TYPE_SHORT: |
3700 | + case MYSQL_TYPE_LONG: |
3701 | + case MYSQL_TYPE_LONGLONG: |
3702 | + |
3703 | + case MYSQL_TYPE_FLOAT: |
3704 | + case MYSQL_TYPE_DOUBLE: |
3705 | + |
3706 | + case MYSQL_TYPE_BLOB: |
3707 | + case MYSQL_TYPE_STRING: |
3708 | + |
3709 | + case MYSQL_TYPE_DATE: |
3710 | + case MYSQL_TYPE_DATETIME: |
3711 | + case MYSQL_TYPE_TIME: |
3712 | + case MYSQL_TYPE_TIMESTAMP: |
3713 | + |
3714 | + case MYSQL_TYPE_NULL: |
3715 | + return TRUE; |
3716 | + default: |
3717 | + return FALSE; |
3718 | + } |
3719 | +} |
3720 | + |
3721 | +/** |
3722 | + * types we allow the send back to the client |
3723 | + */ |
3724 | +gboolean network_mysql_proto_binary_is_valid_output(enum enum_field_types field_type) { |
3725 | + switch (field_type) { |
3726 | + case MYSQL_TYPE_TINY: |
3727 | + case MYSQL_TYPE_SHORT: |
3728 | + case MYSQL_TYPE_INT24: |
3729 | + case MYSQL_TYPE_LONG: |
3730 | + case MYSQL_TYPE_LONGLONG: |
3731 | + |
3732 | + case MYSQL_TYPE_FLOAT: |
3733 | + case MYSQL_TYPE_DOUBLE: |
3734 | + case MYSQL_TYPE_NEWDECIMAL: |
3735 | + |
3736 | + case MYSQL_TYPE_TINY_BLOB: |
3737 | + case MYSQL_TYPE_BLOB: |
3738 | + case MYSQL_TYPE_MEDIUM_BLOB: |
3739 | + case MYSQL_TYPE_LONG_BLOB: |
3740 | + case MYSQL_TYPE_STRING: |
3741 | + case MYSQL_TYPE_VAR_STRING: |
3742 | + |
3743 | + case MYSQL_TYPE_DATE: |
3744 | + case MYSQL_TYPE_DATETIME: |
3745 | + case MYSQL_TYPE_TIME: |
3746 | + case MYSQL_TYPE_TIMESTAMP: |
3747 | + |
3748 | + case MYSQL_TYPE_BIT: |
3749 | + return TRUE; |
3750 | + default: |
3751 | + return FALSE; |
3752 | + } |
3753 | +} |
3754 | + |
3755 | +int network_mysqld_proto_binary_get_type(network_packet *packet, network_mysqld_type_t *type) { |
3756 | + switch (type->type) { |
3757 | + case MYSQL_TYPE_TINY: |
3758 | + case MYSQL_TYPE_SHORT: |
3759 | + case MYSQL_TYPE_LONG: |
3760 | + case MYSQL_TYPE_INT24: |
3761 | + case MYSQL_TYPE_LONGLONG: |
3762 | + return network_mysqld_proto_binary_get_int_type(packet, type); |
3763 | + case MYSQL_TYPE_DATE: |
3764 | + case MYSQL_TYPE_DATETIME: |
3765 | + case MYSQL_TYPE_TIMESTAMP: |
3766 | + return network_mysqld_proto_binary_get_date_type(packet, type); |
3767 | + case MYSQL_TYPE_TIME: |
3768 | + return network_mysqld_proto_binary_get_time_type(packet, type); |
3769 | + case MYSQL_TYPE_FLOAT: |
3770 | + return network_mysqld_proto_binary_get_float_type(packet, type); |
3771 | + case MYSQL_TYPE_DOUBLE: |
3772 | + return network_mysqld_proto_binary_get_double_type(packet, type); |
3773 | + case MYSQL_TYPE_BIT: |
3774 | + case MYSQL_TYPE_NEWDECIMAL: |
3775 | + case MYSQL_TYPE_BLOB: |
3776 | + case MYSQL_TYPE_TINY_BLOB: |
3777 | + case MYSQL_TYPE_MEDIUM_BLOB: |
3778 | + case MYSQL_TYPE_LONG_BLOB: |
3779 | + case MYSQL_TYPE_STRING: |
3780 | + case MYSQL_TYPE_VAR_STRING: |
3781 | + /* they are all length-encoded strings */ |
3782 | + return network_mysqld_proto_binary_get_string_type(packet, type); |
3783 | + } |
3784 | + |
3785 | + return -1; |
3786 | +} |
3787 | + |
3788 | +int network_mysqld_proto_binary_append_type(GString *packet, network_mysqld_type_t *type) { |
3789 | + switch (type->type) { |
3790 | + case MYSQL_TYPE_TINY: |
3791 | + case MYSQL_TYPE_SHORT: |
3792 | + case MYSQL_TYPE_LONG: |
3793 | + case MYSQL_TYPE_INT24: |
3794 | + case MYSQL_TYPE_LONGLONG: |
3795 | + return network_mysqld_proto_binary_append_int_type(packet, type); |
3796 | + case MYSQL_TYPE_DATE: |
3797 | + case MYSQL_TYPE_DATETIME: |
3798 | + case MYSQL_TYPE_TIMESTAMP: |
3799 | + return network_mysqld_proto_binary_append_date_type(packet, type); |
3800 | + case MYSQL_TYPE_TIME: |
3801 | + return network_mysqld_proto_binary_append_time_type(packet, type); |
3802 | + case MYSQL_TYPE_FLOAT: |
3803 | + return network_mysqld_proto_binary_append_float_type(packet, type); |
3804 | + case MYSQL_TYPE_DOUBLE: |
3805 | + return network_mysqld_proto_binary_append_double_type(packet, type); |
3806 | + case MYSQL_TYPE_BIT: |
3807 | + case MYSQL_TYPE_NEWDECIMAL: |
3808 | + case MYSQL_TYPE_BLOB: |
3809 | + case MYSQL_TYPE_TINY_BLOB: |
3810 | + case MYSQL_TYPE_MEDIUM_BLOB: |
3811 | + case MYSQL_TYPE_LONG_BLOB: |
3812 | + case MYSQL_TYPE_STRING: |
3813 | + case MYSQL_TYPE_VAR_STRING: |
3814 | + /* they are all length-encoded strings */ |
3815 | + return network_mysqld_proto_binary_append_string_type(packet, type); |
3816 | + } |
3817 | + |
3818 | + return -1; |
3819 | +} |
3820 | + |
3821 | + |
3822 | |
3823 | === added file 'src/network_mysqld_proto_binary.h' |
3824 | --- src/network_mysqld_proto_binary.h 1970-01-01 00:00:00 +0000 |
3825 | +++ src/network_mysqld_proto_binary.h 2010-09-27 14:20:48 +0000 |
3826 | @@ -0,0 +1,12 @@ |
3827 | +#ifndef __NETWORK_MYSQLD_PROTO_BINARY_H__ |
3828 | +#define __NETWORK_MYSQLD_PROTO_BINARY_H__ |
3829 | + |
3830 | +#include <glib.h> |
3831 | + |
3832 | +#include "network-socket.h" |
3833 | +#include "network_mysqld_type.h" |
3834 | + |
3835 | +int network_mysqld_proto_binary_get_type(network_packet *packet, network_mysqld_type_t *type); |
3836 | +int network_mysqld_proto_binary_append_type(GString *packet, network_mysqld_type_t *type); |
3837 | + |
3838 | +#endif |
3839 | |
3840 | === added file 'src/network_mysqld_type.c' |
3841 | --- src/network_mysqld_type.c 1970-01-01 00:00:00 +0000 |
3842 | +++ src/network_mysqld_type.c 2010-09-27 14:20:48 +0000 |
3843 | @@ -0,0 +1,656 @@ |
3844 | +#include <string.h> |
3845 | +#include <stdlib.h> |
3846 | +#include <stdio.h> |
3847 | + |
3848 | +#include <glib.h> |
3849 | + |
3850 | +#include "network_mysqld_type.h" |
3851 | +#include "string-len.h" |
3852 | + |
3853 | +#include "glib-ext.h" |
3854 | + |
3855 | +/* expose the types itself and their internal representation */ |
3856 | + |
3857 | +typedef double network_mysqld_type_double_t; |
3858 | + |
3859 | +typedef float network_mysqld_type_float_t; |
3860 | + |
3861 | +typedef GString network_mysqld_type_string_t; |
3862 | + |
3863 | +typedef struct { |
3864 | + guint64 i; |
3865 | + gboolean is_unsigned; |
3866 | +} network_mysqld_type_int_t; |
3867 | + |
3868 | +/** |
3869 | + * create a type that can hold a MYSQL_TYPE_LONGLONG |
3870 | + */ |
3871 | +static network_mysqld_type_int_t *network_mysqld_type_int_new(void) { |
3872 | + network_mysqld_type_int_t *ll; |
3873 | + |
3874 | + ll = g_slice_new0(network_mysqld_type_int_t); |
3875 | + |
3876 | + return ll; |
3877 | +} |
3878 | + |
3879 | +/** |
3880 | + * free a network_mysqld_type_int_t |
3881 | + */ |
3882 | +static void network_mysqld_type_int_free(network_mysqld_type_int_t *ll) { |
3883 | + if (NULL == ll) return; |
3884 | + |
3885 | + g_slice_free(network_mysqld_type_int_t, ll); |
3886 | +} |
3887 | + |
3888 | +static int network_mysqld_type_data_int_get_int(network_mysqld_type_t *type, guint64 *i, gboolean *is_unsigned) { |
3889 | + network_mysqld_type_int_t *value; |
3890 | + |
3891 | + if (NULL == type->data) return -1; |
3892 | + |
3893 | + value = type->data; |
3894 | + |
3895 | + *i = value->i; |
3896 | + *is_unsigned = value->is_unsigned; |
3897 | + |
3898 | + return 0; |
3899 | +} |
3900 | + |
3901 | +static int network_mysqld_type_data_int_set_int(network_mysqld_type_t *type, guint64 i, gboolean is_unsigned) { |
3902 | + network_mysqld_type_int_t *value; |
3903 | + |
3904 | + if (NULL == type->data) { |
3905 | + type->data = network_mysqld_type_int_new(); |
3906 | + } |
3907 | + value = type->data; |
3908 | + |
3909 | + value->i = i; |
3910 | + value->is_unsigned = is_unsigned; |
3911 | + |
3912 | + return 0; |
3913 | +} |
3914 | + |
3915 | + |
3916 | +/** |
3917 | + * typesafe wrapper for network_mysqld_type_new() |
3918 | + */ |
3919 | +static void network_mysqld_type_data_int_free(network_mysqld_type_t *type) { |
3920 | + if (NULL == type) return; |
3921 | + if (NULL == type->data) return; |
3922 | + |
3923 | + network_mysqld_type_int_free(type->data); |
3924 | +} |
3925 | + |
3926 | +static void network_mysqld_type_data_int_init(network_mysqld_type_t *type, enum enum_field_types field_type) { |
3927 | + type->type = field_type; |
3928 | + type->free_data = network_mysqld_type_data_int_free; |
3929 | + type->get_int = network_mysqld_type_data_int_get_int; |
3930 | + type->set_int = network_mysqld_type_data_int_set_int; |
3931 | +} |
3932 | + |
3933 | +/* MYSQL_TYPE_DOUBLE */ |
3934 | + |
3935 | +/** |
3936 | + * create a type that can hold a MYSQL_TYPE_DOUBLE |
3937 | + */ |
3938 | +static network_mysqld_type_double_t *network_mysqld_type_double_new(void) { |
3939 | + network_mysqld_type_double_t *t; |
3940 | + |
3941 | + t = g_slice_new0(network_mysqld_type_double_t); |
3942 | + |
3943 | + return t; |
3944 | +} |
3945 | + |
3946 | +/** |
3947 | + * free a network_mysqld_type_double_t |
3948 | + */ |
3949 | +static void network_mysqld_type_double_free(network_mysqld_type_double_t *t) { |
3950 | + if (NULL == t) return; |
3951 | + |
3952 | + g_slice_free(network_mysqld_type_double_t, t); |
3953 | +} |
3954 | + |
3955 | +static void network_mysqld_type_data_double_free(network_mysqld_type_t *type) { |
3956 | + if (NULL == type) return; |
3957 | + if (NULL == type->data) return; |
3958 | + |
3959 | + network_mysqld_type_double_free(type->data); |
3960 | +} |
3961 | + |
3962 | +static int network_mysqld_type_data_double_get_double(network_mysqld_type_t *type, double *d) { |
3963 | + network_mysqld_type_double_t *value = type->data; |
3964 | + |
3965 | + if (NULL == value) return -1; |
3966 | + |
3967 | + *d = *value; |
3968 | + |
3969 | + return 0; |
3970 | +} |
3971 | + |
3972 | +static int network_mysqld_type_data_double_set_double(network_mysqld_type_t *type, double d) { |
3973 | + network_mysqld_type_double_t *value; |
3974 | + |
3975 | + if (NULL == type->data) { |
3976 | + type->data = network_mysqld_type_double_new(); |
3977 | + } |
3978 | + |
3979 | + value = type->data; |
3980 | + *value = d; |
3981 | + |
3982 | + return 0; |
3983 | +} |
3984 | + |
3985 | +static void network_mysqld_type_data_double_init(network_mysqld_type_t *type, enum enum_field_types field_type) { |
3986 | + type->type = field_type; |
3987 | + type->free_data = network_mysqld_type_data_double_free; |
3988 | + type->get_double = network_mysqld_type_data_double_get_double; |
3989 | + type->set_double = network_mysqld_type_data_double_set_double; |
3990 | +} |
3991 | + |
3992 | +/* MYSQL_TYPE_FLOAT */ |
3993 | + |
3994 | +/** |
3995 | + * create a type that can hold a MYSQL_TYPE_FLOAT |
3996 | + */ |
3997 | + |
3998 | +static network_mysqld_type_float_t *network_mysqld_type_float_new(void) { |
3999 | + network_mysqld_type_float_t *t; |
4000 | + |
4001 | + t = g_slice_new0(network_mysqld_type_float_t); |
4002 | + |
4003 | + return t; |
4004 | +} |
4005 | + |
4006 | +/** |
4007 | + * free a network_mysqld_type_float_t |
4008 | + */ |
4009 | +static void network_mysqld_type_float_free(network_mysqld_type_float_t *t) { |
4010 | + if (NULL == t) return; |
4011 | + |
4012 | + g_slice_free(network_mysqld_type_float_t, t); |
4013 | +} |
4014 | + |
4015 | +static void network_mysqld_type_data_float_free(network_mysqld_type_t *type) { |
4016 | + if (NULL == type) return; |
4017 | + if (NULL == type->data) return; |
4018 | + |
4019 | + network_mysqld_type_float_free(type->data); |
4020 | +} |
4021 | + |
4022 | +static int network_mysqld_type_data_float_get_double(network_mysqld_type_t *type, double *dst) { |
4023 | + network_mysqld_type_float_t *src = type->data; |
4024 | + |
4025 | + if (NULL == type->data) return -1; |
4026 | + |
4027 | + *dst = (double)*src; |
4028 | + |
4029 | + return 0; |
4030 | +} |
4031 | + |
4032 | +static int network_mysqld_type_data_float_set_double(network_mysqld_type_t *type, double src) { |
4033 | + network_mysqld_type_float_t *dst = type->data; |
4034 | + |
4035 | + if (NULL == type->data) { |
4036 | + type->data = network_mysqld_type_float_new(); |
4037 | + } |
4038 | + |
4039 | + dst = type->data; |
4040 | + *dst = (float)src; |
4041 | + |
4042 | + return 0; |
4043 | +} |
4044 | + |
4045 | +static void network_mysqld_type_data_float_init(network_mysqld_type_t *type, enum enum_field_types field_type) { |
4046 | + type->type = field_type; |
4047 | + type->free_data = network_mysqld_type_data_float_free; |
4048 | + type->get_double = network_mysqld_type_data_float_get_double; |
4049 | + type->set_double = network_mysqld_type_data_float_set_double; |
4050 | +} |
4051 | + |
4052 | +/* MYSQL_TYPE_STRING */ |
4053 | +static network_mysqld_type_string_t *network_mysqld_type_string_new(void) { |
4054 | + network_mysqld_type_string_t *str; |
4055 | + |
4056 | + str = g_string_new(NULL); |
4057 | + |
4058 | + return str; |
4059 | +} |
4060 | + |
4061 | +static void network_mysqld_type_string_free(network_mysqld_type_string_t *str) { |
4062 | + if (NULL == str) return; |
4063 | + |
4064 | + g_string_free(str, TRUE); |
4065 | +} |
4066 | + |
4067 | +static void network_mysqld_type_data_string_free(network_mysqld_type_t *type) { |
4068 | + if (NULL == type) return; |
4069 | + |
4070 | + network_mysqld_type_string_free(type->data); |
4071 | +} |
4072 | + |
4073 | +static int network_mysqld_type_data_string_get_string_const(network_mysqld_type_t *type, const char **dst, gsize *dst_len) { |
4074 | + GString *src = type->data; |
4075 | + |
4076 | + if (NULL == type->data) return -1; |
4077 | + |
4078 | + *dst = src->str; |
4079 | + *dst_len = src->len; |
4080 | + |
4081 | + return 0; |
4082 | +} |
4083 | + |
4084 | +static int network_mysqld_type_data_string_set_string(network_mysqld_type_t *type, const char *src, gsize src_len) { |
4085 | + GString *dst; |
4086 | + |
4087 | + if (NULL == type->data) { |
4088 | + type->data = g_string_sized_new(src_len); |
4089 | + } |
4090 | + |
4091 | + dst = type->data; |
4092 | + |
4093 | + g_string_assign_len(dst, src, src_len); |
4094 | + |
4095 | + return 0; |
4096 | +} |
4097 | + |
4098 | +static void network_mysqld_type_data_string_init(network_mysqld_type_t *type, enum enum_field_types field_type) { |
4099 | + type->type = field_type; |
4100 | + type->free_data = network_mysqld_type_data_string_free; |
4101 | + type->get_string_const = network_mysqld_type_data_string_get_string_const; |
4102 | + type->set_string = network_mysqld_type_data_string_set_string; |
4103 | +} |
4104 | + |
4105 | +/* MYSQL_TYPE_DATE */ |
4106 | +static network_mysqld_type_date_t *network_mysqld_type_date_new(void) { |
4107 | + network_mysqld_type_date_t *date; |
4108 | + |
4109 | + date = g_slice_new0(network_mysqld_type_date_t); |
4110 | + |
4111 | + return date; |
4112 | +} |
4113 | + |
4114 | +static void network_mysqld_type_date_free(network_mysqld_type_date_t *date) { |
4115 | + if (NULL == date) return; |
4116 | + |
4117 | + g_slice_free(network_mysqld_type_date_t, date); |
4118 | +} |
4119 | + |
4120 | +static void network_mysqld_type_data_date_free(network_mysqld_type_t *type) { |
4121 | + if (NULL == type) return; |
4122 | + |
4123 | + network_mysqld_type_date_free(type->data); |
4124 | +} |
4125 | + |
4126 | +static int network_mysqld_type_data_date_get_date(network_mysqld_type_t *type, network_mysqld_type_date_t *dst) { |
4127 | + network_mysqld_type_date_t *src = type->data; |
4128 | + |
4129 | + if (NULL == type->data) return -1; |
4130 | + |
4131 | + memcpy(dst, src, sizeof(*src)); |
4132 | + |
4133 | + return 0; |
4134 | +} |
4135 | + |
4136 | +static gboolean network_mysqld_type_date_time_is_valid(network_mysqld_type_date_t *date) { |
4137 | + return (date->nsec < 1000000000 && |
4138 | + date->sec < 100 && |
4139 | + date->min <= 60 && |
4140 | + date->hour <= 24); |
4141 | +} |
4142 | + |
4143 | +static gboolean network_mysqld_type_date_date_is_valid(network_mysqld_type_date_t *date) { |
4144 | + return (date->day <= 31 && |
4145 | + date->month <= 12 && |
4146 | + date->year <= 9999); |
4147 | +} |
4148 | + |
4149 | +gboolean network_mysqld_type_date_is_valid(network_mysqld_type_date_t *date) { |
4150 | + return network_mysqld_type_date_time_is_valid(date) && |
4151 | + network_mysqld_type_date_date_is_valid(date); |
4152 | +} |
4153 | + |
4154 | +static int network_mysqld_type_data_date_get_string(network_mysqld_type_t *type, char **dst, gsize *dst_len) { |
4155 | + network_mysqld_type_date_t *src = type->data; |
4156 | + |
4157 | + if (NULL == type->data) return -1; |
4158 | + |
4159 | + switch (type->type) { |
4160 | + case MYSQL_TYPE_DATE: |
4161 | + if (!network_mysqld_type_date_date_is_valid(src)) { |
4162 | + return -1; |
4163 | + } |
4164 | + break; |
4165 | + case MYSQL_TYPE_DATETIME: |
4166 | + case MYSQL_TYPE_TIMESTAMP: |
4167 | + if (!network_mysqld_type_date_is_valid(src)) { |
4168 | + return -1; |
4169 | + } |
4170 | + break; |
4171 | + default: |
4172 | + /* we shouldn't be here */ |
4173 | + return -1; |
4174 | + } |
4175 | + |
4176 | + if (NULL != *dst) { |
4177 | + switch (type->type) { |
4178 | + case MYSQL_TYPE_DATE: |
4179 | + /* dst_len already contains a size and we don't have to alloc */ |
4180 | + if (*dst_len < NETWORK_MYSQLD_TYPE_DATE_MIN_BUF_LEN) { |
4181 | + return -1; /* ... but it is too small .. we could return the right size here */ |
4182 | + } |
4183 | + *dst_len = snprintf(*dst, *dst_len, "%04u-%02u-%02u", |
4184 | + src->year, |
4185 | + src->month, |
4186 | + src->day); |
4187 | + break; |
4188 | + case MYSQL_TYPE_DATETIME: |
4189 | + case MYSQL_TYPE_TIMESTAMP: |
4190 | + /* dst_len already contains a size and we don't have to alloc */ |
4191 | + if (*dst_len < NETWORK_MYSQLD_TYPE_DATETIME_MIN_BUF_LEN) { |
4192 | + return -1; /* ... but it is too small .. we could return the right size here */ |
4193 | + } |
4194 | + *dst_len = snprintf(*dst, *dst_len, "%04u-%02u-%02u %02u:%02u:%02u.%09u", |
4195 | + src->year, |
4196 | + src->month, |
4197 | + src->day, |
4198 | + src->hour, |
4199 | + src->min, |
4200 | + src->sec, |
4201 | + src->nsec); |
4202 | + break; |
4203 | + default: |
4204 | + g_assert_not_reached(); |
4205 | + break; |
4206 | + } |
4207 | + } else { |
4208 | + switch (type->type) { |
4209 | + case MYSQL_TYPE_DATE: |
4210 | + *dst = g_strdup_printf("%04u-%02u-%02u", |
4211 | + src->year, |
4212 | + src->month, |
4213 | + src->day); |
4214 | + *dst_len = strlen(*dst); |
4215 | + break; |
4216 | + case MYSQL_TYPE_DATETIME: |
4217 | + case MYSQL_TYPE_TIMESTAMP: |
4218 | + *dst = g_strdup_printf("%04u-%02u-%02u %02u:%02u:%02u.%09u", |
4219 | + src->year, |
4220 | + src->month, |
4221 | + src->day, |
4222 | + src->hour, |
4223 | + src->min, |
4224 | + src->sec, |
4225 | + src->nsec); |
4226 | + *dst_len = strlen(*dst); |
4227 | + break; |
4228 | + default: |
4229 | + g_assert_not_reached(); |
4230 | + break; |
4231 | + } |
4232 | + } |
4233 | + |
4234 | + return 0; |
4235 | +} |
4236 | + |
4237 | + |
4238 | +static int network_mysqld_type_data_date_set_date(network_mysqld_type_t *type, network_mysqld_type_date_t *src) { |
4239 | + network_mysqld_type_date_t *dst; |
4240 | + |
4241 | + if (NULL == type->data) { |
4242 | + type->data = network_mysqld_type_date_new(); |
4243 | + } |
4244 | + |
4245 | + dst = type->data; |
4246 | + |
4247 | + memcpy(dst, src, sizeof(*src)); |
4248 | + |
4249 | + return 0; |
4250 | +} |
4251 | + |
4252 | +static void network_mysqld_type_data_date_init(network_mysqld_type_t *type, enum enum_field_types field_type) { |
4253 | + type->type = field_type; |
4254 | + type->free_data = network_mysqld_type_data_date_free; |
4255 | + type->get_date = network_mysqld_type_data_date_get_date; |
4256 | + type->get_string = network_mysqld_type_data_date_get_string; |
4257 | + type->set_date = network_mysqld_type_data_date_set_date; |
4258 | +} |
4259 | + |
4260 | + |
4261 | +/* MYSQL_TYPE_TIME */ |
4262 | +static network_mysqld_type_time_t *network_mysqld_type_time_new(void) { |
4263 | + network_mysqld_type_time_t *t; |
4264 | + |
4265 | + t = g_slice_new0(network_mysqld_type_time_t); |
4266 | + |
4267 | + return t; |
4268 | +} |
4269 | + |
4270 | +static void network_mysqld_type_time_free(network_mysqld_type_time_t *t) { |
4271 | + if (NULL == t) return; |
4272 | + |
4273 | + g_slice_free(network_mysqld_type_time_t, t); |
4274 | +} |
4275 | + |
4276 | +static void network_mysqld_type_data_time_free(network_mysqld_type_t *type) { |
4277 | + if (NULL == type) return; |
4278 | + |
4279 | + network_mysqld_type_time_free(type->data); |
4280 | +} |
4281 | + |
4282 | +static int network_mysqld_type_data_time_get_time(network_mysqld_type_t *type, network_mysqld_type_time_t *dst) { |
4283 | + network_mysqld_type_time_t *src = type->data; |
4284 | + |
4285 | + if (NULL == type->data) return -1; |
4286 | + |
4287 | + memcpy(dst, src, sizeof(*src)); |
4288 | + |
4289 | + return 0; |
4290 | +} |
4291 | + |
4292 | +static int network_mysqld_type_data_time_get_string(network_mysqld_type_t *type, char **dst, gsize *dst_len) { |
4293 | + network_mysqld_type_time_t *src = type->data; |
4294 | + |
4295 | + if (NULL == type->data) return -1; |
4296 | + |
4297 | + if (NULL != *dst) { |
4298 | + /* dst_len already contains a size and we don't have to alloc */ |
4299 | + if (*dst_len < NETWORK_MYSQLD_TYPE_TIME_MIN_BUF_LEN) { |
4300 | + return -1; /* ... but it is too small .. we could return the right size here */ |
4301 | + } |
4302 | + *dst_len = snprintf(*dst, *dst_len, "%s%d %02u:%02u:%02u.%09u", |
4303 | + src->sign ? "-" : "", |
4304 | + src->days, |
4305 | + src->hour, |
4306 | + src->min, |
4307 | + src->sec, |
4308 | + src->nsec); |
4309 | + } else { |
4310 | + *dst = g_strdup_printf("%s%d %02u:%02u:%02u.%09u", |
4311 | + src->sign ? "-" : "", |
4312 | + src->days, |
4313 | + src->hour, |
4314 | + src->min, |
4315 | + src->sec, |
4316 | + src->nsec); |
4317 | + *dst_len = strlen(*dst); |
4318 | + } |
4319 | + |
4320 | + return 0; |
4321 | +} |
4322 | + |
4323 | +static int network_mysqld_type_data_time_set_time(network_mysqld_type_t *type, network_mysqld_type_time_t *src) { |
4324 | + network_mysqld_type_date_t *dst; |
4325 | + |
4326 | + if (NULL == type->data) { |
4327 | + type->data = network_mysqld_type_time_new(); |
4328 | + } |
4329 | + dst = type->data; |
4330 | + |
4331 | + memcpy(dst, src, sizeof(*src)); |
4332 | + |
4333 | + return 0; |
4334 | +} |
4335 | + |
4336 | + |
4337 | +static void network_mysqld_type_data_time_init(network_mysqld_type_t *type, enum enum_field_types field_type) { |
4338 | + type->type = field_type; |
4339 | + type->free_data = network_mysqld_type_data_time_free; |
4340 | + type->get_time = network_mysqld_type_data_time_get_time; |
4341 | + type->get_string = network_mysqld_type_data_time_get_string; |
4342 | + type->set_time = network_mysqld_type_data_time_set_time; |
4343 | +} |
4344 | + |
4345 | + |
4346 | +/** |
4347 | + * create a type |
4348 | + */ |
4349 | +network_mysqld_type_t *network_mysqld_type_new(enum enum_field_types field_type) { |
4350 | + network_mysqld_type_t *type = NULL; |
4351 | + |
4352 | + switch (field_type) { |
4353 | + case MYSQL_TYPE_TINY: |
4354 | + case MYSQL_TYPE_SHORT: |
4355 | + case MYSQL_TYPE_LONG: |
4356 | + case MYSQL_TYPE_INT24: |
4357 | + case MYSQL_TYPE_LONGLONG: |
4358 | + type = g_slice_new0(network_mysqld_type_t); |
4359 | + |
4360 | + network_mysqld_type_data_int_init(type, field_type); |
4361 | + break; |
4362 | + case MYSQL_TYPE_FLOAT: /* 4 bytes */ |
4363 | + type = g_slice_new0(network_mysqld_type_t); |
4364 | + |
4365 | + network_mysqld_type_data_float_init(type, field_type); |
4366 | + break; |
4367 | + case MYSQL_TYPE_DOUBLE: /* 8 bytes */ |
4368 | + type = g_slice_new0(network_mysqld_type_t); |
4369 | + |
4370 | + network_mysqld_type_data_double_init(type, field_type); |
4371 | + break; |
4372 | + case MYSQL_TYPE_DATETIME: |
4373 | + case MYSQL_TYPE_DATE: |
4374 | + case MYSQL_TYPE_TIMESTAMP: |
4375 | + type = g_slice_new0(network_mysqld_type_t); |
4376 | + |
4377 | + network_mysqld_type_data_date_init(type, field_type); |
4378 | + break; |
4379 | + case MYSQL_TYPE_TIME: |
4380 | + type = g_slice_new0(network_mysqld_type_t); |
4381 | + |
4382 | + network_mysqld_type_data_time_init(type, field_type); |
4383 | + break; |
4384 | + case MYSQL_TYPE_NEWDECIMAL: |
4385 | + case MYSQL_TYPE_BLOB: |
4386 | + case MYSQL_TYPE_TINY_BLOB: |
4387 | + case MYSQL_TYPE_MEDIUM_BLOB: |
4388 | + case MYSQL_TYPE_LONG_BLOB: |
4389 | + case MYSQL_TYPE_STRING: |
4390 | + case MYSQL_TYPE_VAR_STRING: |
4391 | + case MYSQL_TYPE_VARCHAR: |
4392 | + /* they are all length-encoded strings */ |
4393 | + type = g_slice_new0(network_mysqld_type_t); |
4394 | + |
4395 | + network_mysqld_type_data_string_init(type, field_type); |
4396 | + break; |
4397 | + case MYSQL_TYPE_NULL: |
4398 | + type = g_slice_new0(network_mysqld_type_t); |
4399 | + |
4400 | + type->type = field_type; |
4401 | + break; |
4402 | + } |
4403 | + |
4404 | + return type; |
4405 | +} |
4406 | +/** |
4407 | + * free a type |
4408 | + */ |
4409 | +void network_mysqld_type_free(network_mysqld_type_t *type) { |
4410 | + if (NULL == type) return; |
4411 | + |
4412 | + if (NULL != type->free_data) { |
4413 | + type->free_data(type); |
4414 | + } |
4415 | + g_slice_free(network_mysqld_type_t, type); |
4416 | +} |
4417 | + |
4418 | +int network_mysqld_type_get_gstring(network_mysqld_type_t *type, GString *s) { |
4419 | + if (NULL == type->get_gstring) return -1; |
4420 | + |
4421 | + return type->get_gstring(type, s); |
4422 | +} |
4423 | + |
4424 | +int network_mysqld_type_get_string_const(network_mysqld_type_t *type, const char **s, gsize *s_len) { |
4425 | + if (NULL == type->get_string_const) return -1; |
4426 | + |
4427 | + return type->get_string_const(type, s, s_len); |
4428 | +} |
4429 | + |
4430 | +int network_mysqld_type_get_string(network_mysqld_type_t *type, char **s, gsize *s_len) { |
4431 | + if (NULL == type->get_string) return -1; |
4432 | + |
4433 | + return type->get_string(type, s, s_len); |
4434 | +} |
4435 | + |
4436 | + |
4437 | +int network_mysqld_type_set_string(network_mysqld_type_t *type, const char *s, gsize s_len) { |
4438 | + if (NULL == type->set_string) return -1; |
4439 | + |
4440 | + return type->set_string(type, s, s_len); |
4441 | +} |
4442 | + |
4443 | + |
4444 | +int network_mysqld_type_get_int(network_mysqld_type_t *type, guint64 *i, gboolean *is_unsigned) { |
4445 | + if (NULL == type->get_int) return -1; |
4446 | + |
4447 | + return type->get_int(type, i, is_unsigned); |
4448 | +} |
4449 | + |
4450 | + |
4451 | +int network_mysqld_type_set_int(network_mysqld_type_t *type, guint64 i, gboolean is_unsigned) { |
4452 | + if (NULL == type->set_int) return -1; |
4453 | + |
4454 | + return type->set_int(type, i, is_unsigned); |
4455 | +} |
4456 | + |
4457 | + |
4458 | +int network_mysqld_type_get_double(network_mysqld_type_t *type, double *d) { |
4459 | + if (NULL == type->get_double) return -1; |
4460 | + |
4461 | + return type->get_double(type, d); |
4462 | +} |
4463 | + |
4464 | + |
4465 | +int network_mysqld_type_set_double(network_mysqld_type_t *type, double d) { |
4466 | + if (NULL == type->set_double) return -1; |
4467 | + |
4468 | + return type->set_double(type, d); |
4469 | +} |
4470 | + |
4471 | + |
4472 | +int network_mysqld_type_get_date(network_mysqld_type_t *type, network_mysqld_type_date_t *date) { |
4473 | + if (NULL == type->get_date) return -1; |
4474 | + |
4475 | + return type->get_date(type, date); |
4476 | +} |
4477 | + |
4478 | + |
4479 | +int network_mysqld_type_set_date(network_mysqld_type_t *type, network_mysqld_type_date_t *date) { |
4480 | + if (NULL == type->set_date) return -1; |
4481 | + |
4482 | + return type->set_date(type, date); |
4483 | +} |
4484 | + |
4485 | + |
4486 | +int network_mysqld_type_get_time(network_mysqld_type_t *type, network_mysqld_type_time_t *t) { |
4487 | + if (NULL == type->get_time) return -1; |
4488 | + |
4489 | + return type->get_time(type, t); |
4490 | +} |
4491 | + |
4492 | + |
4493 | +int network_mysqld_type_set_time(network_mysqld_type_t *type, network_mysqld_type_time_t *t) { |
4494 | + if (NULL == type->set_time) return -1; |
4495 | + |
4496 | + return type->set_time(type, t); |
4497 | +} |
4498 | + |
4499 | + |
4500 | |
4501 | === added file 'src/network_mysqld_type.h' |
4502 | --- src/network_mysqld_type.h 1970-01-01 00:00:00 +0000 |
4503 | +++ src/network_mysqld_type.h 2010-09-27 14:20:48 +0000 |
4504 | @@ -0,0 +1,147 @@ |
4505 | +#ifndef __NETWORK_MYSQLD_TYPE_H__ |
4506 | +#define __NETWORK_MYSQLD_TYPE_H__ |
4507 | + |
4508 | +#include <mysql.h> |
4509 | +#include <glib.h> |
4510 | + |
4511 | +#include "network-mysqld-proto.h" |
4512 | + |
4513 | +/** |
4514 | + * struct for the MYSQL_TYPE_DATE and friends |
4515 | + */ |
4516 | +typedef struct { |
4517 | + guint16 year; |
4518 | + guint8 month; |
4519 | + guint8 day; |
4520 | + |
4521 | + guint8 hour; |
4522 | + guint8 min; |
4523 | + guint8 sec; |
4524 | + |
4525 | + guint32 nsec; /* the nano-second part */ |
4526 | +} network_mysqld_type_date_t; |
4527 | + |
4528 | +#define NETWORK_MYSQLD_TYPE_DATE_MIN_BUF_LEN (sizeof("2010-10-27")) |
4529 | +#define NETWORK_MYSQLD_TYPE_DATETIME_MIN_BUF_LEN (sizeof("2010-10-27 19:27:30.000000001")) |
4530 | +#define NETWORK_MYSQLD_TYPE_TIMESTAMP_MIN_BUF_LEN NETWORK_MYSQLD_TYPE_DATETIME_MIN_BUF_LEN |
4531 | + |
4532 | +/** |
4533 | + * struct for the MYSQL_TYPE_TIME |
4534 | + */ |
4535 | +typedef struct { |
4536 | + guint8 sign; |
4537 | + guint32 days; |
4538 | + |
4539 | + guint8 hour; |
4540 | + guint8 min; |
4541 | + guint8 sec; |
4542 | + |
4543 | + guint32 nsec; /* the nano-second part */ |
4544 | +} network_mysqld_type_time_t; |
4545 | + |
4546 | +#define NETWORK_MYSQLD_TYPE_TIME_MIN_BUF_LEN (sizeof("-2147483647 19:27:30.000000001")) |
4547 | + |
4548 | +typedef struct _network_mysqld_type_t network_mysqld_type_t; |
4549 | + |
4550 | +struct _network_mysqld_type_t { |
4551 | + enum enum_field_types type; |
4552 | + |
4553 | + gpointer data; |
4554 | + void (*free_data)(network_mysqld_type_t *type); |
4555 | + |
4556 | + /** |
4557 | + * get a copy of ->data as GString |
4558 | + * |
4559 | + * @param type the type to get the data from |
4560 | + * @param s GString that the converted data will be assigned too |
4561 | + * @return 0 on success, -1 on error |
4562 | + */ |
4563 | + int (*get_gstring)(network_mysqld_type_t *type, GString *s); |
4564 | + /** |
4565 | + * expose the ->data as constant string |
4566 | + * |
4567 | + * only available for types that have a "string" storage like _STRING, _CHAR, _BLOB |
4568 | + * the caller can copy the data out, but not change it |
4569 | + * |
4570 | + * @param type the type to get the data from |
4571 | + * @param s place to store the pointer to the const char * in |
4572 | + * @param s_len length of the const char * |
4573 | + * @return 0 on success, -1 on error |
4574 | + */ |
4575 | + int (*get_string_const)(network_mysqld_type_t *type, const char **s, gsize *s_len); |
4576 | + /** |
4577 | + * get a copy of ->data as char * |
4578 | + * |
4579 | + * has 2 modes: |
4580 | + * - no-alloc-mode if *s is not NULL where it is expected that s and s_len point |
4581 | + * to a buffer of that size that we can copy into |
4582 | + * *s_len will contain the size of the stored string on success |
4583 | + * if *s_len is too small, -1 will be returned |
4584 | + * - alloc-mode when *s is NULL where we return a alloced buffer that is large enough |
4585 | + * |
4586 | + * @param type the type to get the data from |
4587 | + * @param s pointer to a buffer of *s_len size or pointer to (char *)NULL for alloc-mode |
4588 | + * @param s_len pointer to the length of the buffer if *s is not NULL. Points to the length of the *s on success |
4589 | + * @return 0 on success, -1 on error |
4590 | + */ |
4591 | + int (*get_string)(network_mysqld_type_t *type, char **s, gsize *len); |
4592 | + /** |
4593 | + * set the ->data from a string |
4594 | + */ |
4595 | + int (*set_string)(network_mysqld_type_t *type, const char *s, gsize s_len); |
4596 | + /** |
4597 | + * get ->data as uint64 |
4598 | + */ |
4599 | + int (*get_int)(network_mysqld_type_t *type, guint64 *i, gboolean *is_unsigned); |
4600 | + /** |
4601 | + * set ->data from uint64 |
4602 | + */ |
4603 | + int (*set_int)(network_mysqld_type_t *type, guint64 i, gboolean is_unsigned); |
4604 | + /** |
4605 | + * get ->data as double |
4606 | + */ |
4607 | + int (*get_double)(network_mysqld_type_t *type, double *d); |
4608 | + /** |
4609 | + * set ->data from double |
4610 | + */ |
4611 | + int (*set_double)(network_mysqld_type_t *type, double d); |
4612 | + int (*get_date)(network_mysqld_type_t *type, network_mysqld_type_date_t *date); |
4613 | + int (*set_date)(network_mysqld_type_t *type, network_mysqld_type_date_t *date); |
4614 | + /** |
4615 | + * get the ->data as _time_t |
4616 | + */ |
4617 | + int (*get_time)(network_mysqld_type_t *type, network_mysqld_type_time_t *t); |
4618 | + /** |
4619 | + * set the ->data from a _time_t |
4620 | + */ |
4621 | + int (*set_time)(network_mysqld_type_t *type, network_mysqld_type_time_t *t); |
4622 | + |
4623 | + |
4624 | + gboolean is_null; /**< is the value of this type NULL */ |
4625 | + gboolean is_unsigned; /**< is the type signed or unsigned, only used by the integer types */ |
4626 | +}; |
4627 | + |
4628 | + |
4629 | +NETWORK_API network_mysqld_type_t *network_mysqld_type_new(enum enum_field_types _type); |
4630 | +NETWORK_API void network_mysqld_type_free(network_mysqld_type_t *type); |
4631 | + |
4632 | +/** |
4633 | + * wrappers around the gettors and settors |
4634 | + * |
4635 | + * @return -1 if no settor or gettor defined or settor or gettor failed to convert |
4636 | + */ |
4637 | +NETWORK_API int network_mysqld_type_get_gstring(network_mysqld_type_t *type, GString *s); |
4638 | +NETWORK_API int network_mysqld_type_get_gstring(network_mysqld_type_t *type, GString *s); |
4639 | +NETWORK_API int network_mysqld_type_get_string_const(network_mysqld_type_t *type, const char **s, gsize *s_len); |
4640 | +NETWORK_API int network_mysqld_type_get_string(network_mysqld_type_t *type, char **s, gsize *len); |
4641 | +NETWORK_API int network_mysqld_type_set_string(network_mysqld_type_t *type, const char *s, gsize s_len); |
4642 | +NETWORK_API int network_mysqld_type_get_int(network_mysqld_type_t *type, guint64 *i, gboolean *is_unsigned); |
4643 | +NETWORK_API int network_mysqld_type_set_int(network_mysqld_type_t *type, guint64 i, gboolean is_unsigned); |
4644 | +NETWORK_API int network_mysqld_type_get_double(network_mysqld_type_t *type, double *d); |
4645 | +NETWORK_API int network_mysqld_type_set_double(network_mysqld_type_t *type, double d); |
4646 | +NETWORK_API int network_mysqld_type_get_date(network_mysqld_type_t *type, network_mysqld_type_date_t *date); |
4647 | +NETWORK_API int network_mysqld_type_set_date(network_mysqld_type_t *type, network_mysqld_type_date_t *date); |
4648 | +NETWORK_API int network_mysqld_type_get_time(network_mysqld_type_t *type, network_mysqld_type_time_t *t); |
4649 | +NETWORK_API int network_mysqld_type_set_time(network_mysqld_type_t *type, network_mysqld_type_time_t *t); |
4650 | + |
4651 | +#endif |
4652 | |
4653 | === modified file 'tests/unit/CMakeLists.txt' |
4654 | --- tests/unit/CMakeLists.txt 2010-02-24 11:02:26 +0000 |
4655 | +++ tests/unit/CMakeLists.txt 2010-09-27 14:20:48 +0000 |
4656 | @@ -113,6 +113,7 @@ |
4657 | ../../src/glib-ext.c |
4658 | ../../src/network-mysqld-proto.c |
4659 | ../../src/network-mysqld-packet.c |
4660 | + ../../src/network_mysqld_type.c |
4661 | ../../src/chassis-timings.c |
4662 | ../../src/my_rdtsc.c |
4663 | ) |
4664 | @@ -132,6 +133,7 @@ |
4665 | ../../src/glib-ext.c |
4666 | ../../src/network-mysqld-proto.c |
4667 | ../../src/network-mysqld-packet.c |
4668 | + ../../src/network_mysqld_type.c |
4669 | ../../src/network-address.c |
4670 | ) |
4671 | |
4672 | |
4673 | === modified file 'tests/unit/Makefile.am' |
4674 | --- tests/unit/Makefile.am 2010-04-06 14:26:51 +0000 |
4675 | +++ tests/unit/Makefile.am 2010-09-27 14:20:48 +0000 |
4676 | @@ -32,6 +32,7 @@ |
4677 | t_network_backend \ |
4678 | t_network_injection \ |
4679 | t_network_mysqld_packet \ |
4680 | + t_network_mysqld_type \ |
4681 | t_network_mysqld_masterinfo \ |
4682 | t_chassis_timings \ |
4683 | t_chassis_shutdown_hooks \ |
4684 | @@ -81,10 +82,21 @@ |
4685 | check_mysqld_proto_CPPFLAGS = -I$(top_srcdir)/src/ $(GLIB_CFLAGS) $(MYSQL_CFLAGS) |
4686 | check_mysqld_proto_LDADD = $(GLIB_LIBS) |
4687 | |
4688 | +t_network_mysqld_type_SOURCES = \ |
4689 | + t_network_mysqld_type.c \ |
4690 | + $(top_srcdir)/src/network_mysqld_type.c \ |
4691 | + $(top_srcdir)/src/glib-ext.c |
4692 | + |
4693 | +t_network_mysqld_type_CPPFLAGS = -I$(top_srcdir)/src/ $(GLIB_CFLAGS) $(MYSQL_CFLAGS) $(LUA_CFLAGS) |
4694 | +t_network_mysqld_type_LDADD = $(GLIB_LIBS) $(LUA_LIBS) $(EVENT_LIBS) |
4695 | + |
4696 | + |
4697 | t_network_mysqld_packet_SOURCES = \ |
4698 | t_network_mysqld_packet.c \ |
4699 | $(top_srcdir)/src/network-mysqld-packet.c \ |
4700 | $(top_srcdir)/src/network-mysqld-proto.c \ |
4701 | + $(top_srcdir)/src/network_mysqld_type.c \ |
4702 | + $(top_srcdir)/src/network_mysqld_proto_binary.c \ |
4703 | $(top_srcdir)/src/network-queue.c \ |
4704 | $(top_srcdir)/src/network-socket.c \ |
4705 | $(top_srcdir)/src/network-address.c \ |
4706 | @@ -126,6 +138,8 @@ |
4707 | $(top_srcdir)/src/glib-ext.c \ |
4708 | $(top_srcdir)/src/network-mysqld-proto.c \ |
4709 | $(top_srcdir)/src/network-mysqld-packet.c \ |
4710 | + $(top_srcdir)/src/network_mysqld_type.c \ |
4711 | + $(top_srcdir)/src/network_mysqld_proto_binary.c \ |
4712 | $(top_srcdir)/src/network-address.c \ |
4713 | $(top_srcdir)/src/network-queue.c \ |
4714 | $(top_srcdir)/src/network-socket.c |
4715 | @@ -177,6 +191,8 @@ |
4716 | $(top_srcdir)/src/network-backend.c \ |
4717 | $(top_srcdir)/src/network-mysqld-proto.c \ |
4718 | $(top_srcdir)/src/network-mysqld-packet.c \ |
4719 | + $(top_srcdir)/src/network_mysqld_type.c \ |
4720 | + $(top_srcdir)/src/network_mysqld_proto_binary.c \ |
4721 | $(top_srcdir)/src/network-conn-pool.c \ |
4722 | $(top_srcdir)/src/network-address.c \ |
4723 | $(top_srcdir)/src/network-queue.c \ |
4724 | @@ -204,6 +220,8 @@ |
4725 | $(top_srcdir)/src/glib-ext.c \ |
4726 | $(top_srcdir)/src/network-mysqld-proto.c \ |
4727 | $(top_srcdir)/src/network-mysqld-packet.c \ |
4728 | + $(top_srcdir)/src/network_mysqld_type.c \ |
4729 | + $(top_srcdir)/src/network_mysqld_proto_binary.c \ |
4730 | $(top_srcdir)/src/network-injection.c \ |
4731 | $(top_srcdir)/src/my_rdtsc.c \ |
4732 | $(top_srcdir)/src/chassis-timings.c |
4733 | |
4734 | === modified file 'tests/unit/lua/mysql-proto.lua' |
4735 | --- tests/unit/lua/mysql-proto.lua 2010-04-06 14:26:51 +0000 |
4736 | +++ tests/unit/lua/mysql-proto.lua 2010-09-27 14:20:48 +0000 |
4737 | @@ -19,7 +19,7 @@ |
4738 | $%ENDLICENSE%$ --]] |
4739 | local proto = assert(require("mysql.proto")) |
4740 | local password = assert(require("mysql.password")) |
4741 | - |
4742 | +require("proxy.test") |
4743 | --- |
4744 | -- err packet |
4745 | |
4746 | @@ -265,3 +265,72 @@ |
4747 | |
4748 | assert(false == password.check(challenge, response, dbl_hashed)) |
4749 | |
4750 | +--- |
4751 | +-- prepared stmt decoders |
4752 | +-- |
4753 | + |
4754 | +-- EXECUTE packet, no params |
4755 | +local packet = "\023\001\000\000\000\000\001\000\000\000" |
4756 | +local execute = proto.from_stmt_execute_packet(packet, 0) |
4757 | +assert(execute) |
4758 | +assertEquals(execute.stmt_id, 1) |
4759 | +assertEquals(execute.flags, 0) |
4760 | +assertEquals(execute.iteration_count, 1) |
4761 | +assertEquals(execute.new_params_bound, false) |
4762 | + |
4763 | +-- EXECUTE packet with 14 params |
4764 | +local packet = "\023" .. |
4765 | + "\001\000\000\000" .. |
4766 | + "\000" .. |
4767 | + "\001\000\000\000" .. |
4768 | + "\003\000" .. |
4769 | + "\001" .. |
4770 | + "\254\000\006\000\254\000\008\000\008\128\003\000\002\000\001\000\005\000\004\000\010\000\012\000\007\000\011\000" .. |
4771 | + "\003\102\111\111" .. |
4772 | + "\001\000\000\000\000\000\000\000" .. |
4773 | + "\001\000\000\000\000\000\000\000" .. |
4774 | + "\001\000\000\000" .. |
4775 | + "\001\000" .. |
4776 | + "\001" .. |
4777 | + "\102\102\102\102\102\102\036\064" .. |
4778 | + "\000\000\036\065" .. |
4779 | + "\004\218\007\010\017" .. |
4780 | + "\011\218\007\010\017\019\027\030\001\000\000\000" .. |
4781 | + "\011\218\007\010\017\019\027\030\001\000\000\000" .. |
4782 | + "\012\001\120\000\000\000\019\027\030\001\000\000\000" |
4783 | + |
4784 | +local execute = proto.from_stmt_execute_packet(packet, 14) |
4785 | +assert(execute) |
4786 | +assertEquals(execute.stmt_id, 1) |
4787 | +assertEquals(execute.flags, 0) |
4788 | +assertEquals(execute.iteration_count, 1) |
4789 | +assertEquals(execute.new_params_bound, true) |
4790 | + |
4791 | +local params = execute.params |
4792 | +assert(params) |
4793 | +assertEquals(#params, 14) |
4794 | + |
4795 | +local expected_params = { |
4796 | + { type = 254, value = nil }, |
4797 | + { type = 6, value = nil }, |
4798 | + { type = 254, value = "foo" }, |
4799 | + { type = 8, value = 1 }, |
4800 | + { type = 8, value = 1 }, |
4801 | + { type = 3, value = 1 }, |
4802 | + { type = 2, value = 1 }, |
4803 | + { type = 1, value = 1 }, |
4804 | + { type = 5, value = 10.2 }, --[[ double ]]-- |
4805 | + { type = 4, value = 10.25 }, --[[ float ]]-- |
4806 | + { type = 10, value = "2010-10-17" }, --[[ date ]]-- |
4807 | + { type = 12, value = "2010-10-17 19:27:30.000000001" }, --[[ datetime ]]-- |
4808 | + { type = 7, value = "2010-10-17 19:27:30.000000001" }, --[[ timestamp ]]-- |
4809 | + { type = 11, value = "-120 19:27:30.000000001" }, --[[ time ]]-- |
4810 | +} |
4811 | + |
4812 | +for ndx, expected_param in ipairs(expected_params) do |
4813 | + local param = params[ndx] |
4814 | + assert(param) |
4815 | + assertEquals(param.type, expected_param.type) |
4816 | + assertEquals(param.value, expected_param.value) |
4817 | +end |
4818 | + |
4819 | |
4820 | === modified file 'tests/unit/t_network_mysqld_packet.c' |
4821 | --- tests/unit/t_network_mysqld_packet.c 2010-04-06 14:26:51 +0000 |
4822 | +++ tests/unit/t_network_mysqld_packet.c 2010-09-27 14:20:48 +0000 |
4823 | @@ -27,6 +27,7 @@ |
4824 | |
4825 | #include "network-mysqld-proto.h" |
4826 | #include "network-mysqld-packet.h" |
4827 | +#include "network_mysqld_type.h" |
4828 | #include "glib-ext.h" |
4829 | |
4830 | #if GLIB_CHECK_VERSION(2, 16, 0) |
4831 | @@ -695,6 +696,624 @@ |
4832 | network_queue_free(q); |
4833 | } |
4834 | |
4835 | +/* prepared statements */ |
4836 | + |
4837 | +/* COM_STMT_PREPARE */ |
4838 | +static void t_com_stmt_prepare_new(void) { |
4839 | + network_mysqld_stmt_prepare_packet_t *cmd; |
4840 | + |
4841 | + cmd = network_mysqld_stmt_prepare_packet_new(); |
4842 | + g_assert(cmd); |
4843 | + |
4844 | + network_mysqld_stmt_prepare_packet_free(cmd); |
4845 | +} |
4846 | + |
4847 | +static void t_com_stmt_prepare_from_packet(void) { |
4848 | + network_mysqld_stmt_prepare_packet_t *cmd; |
4849 | + const char raw_packet[] = "\x1c\x00\x00\x00\x16SELECT CONCAT(?, ?) AS col1"; |
4850 | + network_packet packet; |
4851 | + |
4852 | + packet.data = g_string_new_len(C(raw_packet)); |
4853 | + packet.offset = 0; |
4854 | + |
4855 | + cmd = network_mysqld_stmt_prepare_packet_new(); |
4856 | + g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet)); |
4857 | + g_assert_cmpint(0, ==, network_mysqld_proto_get_stmt_prepare_packet(&packet, cmd)); |
4858 | + g_assert_cmpint(sizeof("SELECT CONCAT(?, ?) AS col1") - 1, ==, cmd->stmt_text->len); |
4859 | + g_assert_cmpstr("SELECT CONCAT(?, ?) AS col1", ==, cmd->stmt_text->str); |
4860 | + |
4861 | + network_mysqld_stmt_prepare_packet_free(cmd); |
4862 | +} |
4863 | + |
4864 | +/* COM_STMT_PREPARE OK-result */ |
4865 | + |
4866 | +static void t_com_stmt_prepare_ok_new(void) { |
4867 | + network_mysqld_stmt_prepare_ok_packet_t *cmd; |
4868 | + |
4869 | + cmd = network_mysqld_stmt_prepare_ok_packet_new(); |
4870 | + g_assert(cmd); |
4871 | + |
4872 | + network_mysqld_stmt_prepare_ok_packet_free(cmd); |
4873 | +} |
4874 | + |
4875 | +/** |
4876 | + * test if we parse all the fields of a COM_STMT_PREPARE-ok response correctly |
4877 | + */ |
4878 | +static void t_com_stmt_prepare_ok_from_packet(void) { |
4879 | + network_mysqld_stmt_prepare_ok_packet_t *cmd; |
4880 | + network_mysqld_eof_packet_t *eof; |
4881 | + network_mysqld_proto_fielddef_t *coldef; |
4882 | + |
4883 | + /* a response for the COM_STMT_PREPARE command |
4884 | + * |
4885 | + * the OK part with stmt-id and so on is in the first packet. The others are |
4886 | + * the field-defs, a EOF, the param-defs, and the last EOF */ |
4887 | + strings packets[] = { |
4888 | + { C("\x0c\x00\x00\x01\x00\x01\x00\x00\x00\x01\x00\x02\x00\x00\x00\x00") }, /* the PREPARE OK packet */ |
4889 | + { C("\x17\x00\x00\x02\x03\x64\x65\x66\x00\x00\x00\x01\x3f\x00\x0c\x3f\x00\x00\x00\x00\x00\xfd\x80\x00\x00\x00\x00") }, /* column-def: param 1 */ |
4890 | + { C("\x17\x00\x00\x03\x03\x64\x65\x66\x00\x00\x00\x01\x3f\x00\x0c\x3f\x00\x00\x00\x00\x00\xfd\x80\x00\x00\x00\x00") }, /* column-def: param 2 */ |
4891 | + { C("\x05\x00\x00\x04\xfe\x00\x00\x02\x00") }, /* the seperator */ |
4892 | + { C("\x1a\x00\x00\x05\x03\x64\x65\x66\x00\x00\x00\x04\x63\x6f\x6c\x31\x00\x0c\x3f\x00\x00\x00\x00\x00\xfd\x80\x00\x1f\x00\x00") }, /* column-def: result-col 1 */ |
4893 | + { C("\x05\x00\x00\x06\xfe\x00\x00\x02\x00") } /* the terminator */ |
4894 | + }; |
4895 | + network_packet packet; |
4896 | + |
4897 | + packet.data = g_string_new_len(packets[0].s, packets[0].s_len); |
4898 | + packet.offset = 0; |
4899 | + |
4900 | + cmd = network_mysqld_stmt_prepare_ok_packet_new(); |
4901 | + g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet)); |
4902 | + g_assert_cmpint(0, ==, network_mysqld_proto_get_stmt_prepare_ok_packet(&packet, cmd)); |
4903 | + g_assert_cmpint(1, ==, cmd->stmt_id); |
4904 | + g_assert_cmpint(1, ==, cmd->num_columns); |
4905 | + g_assert_cmpint(2, ==, cmd->num_params); |
4906 | + g_assert_cmpint(0, ==, cmd->warnings); |
4907 | + |
4908 | + network_mysqld_stmt_prepare_ok_packet_free(cmd); |
4909 | + |
4910 | + g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */ |
4911 | + g_string_free(packet.data, TRUE); |
4912 | + |
4913 | + packet.data = g_string_new_len(packets[1].s, packets[1].s_len); |
4914 | + packet.offset = 0; |
4915 | + |
4916 | + coldef = network_mysqld_proto_fielddef_new(); |
4917 | + g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet)); |
4918 | + g_assert_cmpint(0, ==, network_mysqld_proto_get_fielddef(&packet, coldef, CLIENT_PROTOCOL_41)); |
4919 | + |
4920 | + network_mysqld_proto_fielddef_free(coldef); |
4921 | + |
4922 | + g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */ |
4923 | + g_string_free(packet.data, TRUE); |
4924 | + |
4925 | + |
4926 | + packet.data = g_string_new_len(packets[2].s, packets[2].s_len); |
4927 | + packet.offset = 0; |
4928 | + |
4929 | + coldef = network_mysqld_proto_fielddef_new(); |
4930 | + g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet)); |
4931 | + g_assert_cmpint(0, ==, network_mysqld_proto_get_fielddef(&packet, coldef, CLIENT_PROTOCOL_41)); |
4932 | + network_mysqld_proto_fielddef_free(coldef); |
4933 | + |
4934 | + g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */ |
4935 | + g_string_free(packet.data, TRUE); |
4936 | + |
4937 | + |
4938 | + packet.data = g_string_new_len(packets[3].s, packets[3].s_len); |
4939 | + packet.offset = 0; |
4940 | + |
4941 | + eof = network_mysqld_eof_packet_new(); |
4942 | + g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet)); |
4943 | + g_assert_cmpint(0, ==, network_mysqld_proto_get_eof_packet(&packet, eof)); |
4944 | + |
4945 | + network_mysqld_eof_packet_free(eof); |
4946 | + |
4947 | + g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */ |
4948 | + g_string_free(packet.data, TRUE); |
4949 | + |
4950 | + |
4951 | + packet.data = g_string_new_len(packets[4].s, packets[4].s_len); |
4952 | + packet.offset = 0; |
4953 | + |
4954 | + coldef = network_mysqld_proto_fielddef_new(); |
4955 | + g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet)); |
4956 | + g_assert_cmpint(0, ==, network_mysqld_proto_get_fielddef(&packet, coldef, CLIENT_PROTOCOL_41)); |
4957 | + network_mysqld_proto_fielddef_free(coldef); |
4958 | + |
4959 | + g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */ |
4960 | + g_string_free(packet.data, TRUE); |
4961 | + |
4962 | + |
4963 | + packet.data = g_string_new_len(packets[5].s, packets[5].s_len); |
4964 | + packet.offset = 0; |
4965 | + |
4966 | + eof = network_mysqld_eof_packet_new(); |
4967 | + g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet)); |
4968 | + g_assert_cmpint(0, ==, network_mysqld_proto_get_eof_packet(&packet, eof)); |
4969 | + |
4970 | + network_mysqld_eof_packet_free(eof); |
4971 | + |
4972 | + g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */ |
4973 | + g_string_free(packet.data, TRUE); |
4974 | +} |
4975 | + |
4976 | +/* COM_STMT_EXECUTE */ |
4977 | + |
4978 | +static void t_com_stmt_execute_new(void) { |
4979 | + network_mysqld_stmt_execute_packet_t *cmd; |
4980 | + |
4981 | + cmd = network_mysqld_stmt_execute_packet_new(); |
4982 | + g_assert(cmd); |
4983 | + |
4984 | + network_mysqld_stmt_execute_packet_free(cmd); |
4985 | +} |
4986 | + |
4987 | +/** |
4988 | + * test if we decode all valid types from EXECUTE stmt |
4989 | + */ |
4990 | +static void t_com_stmt_execute_from_packet(void) { |
4991 | + network_mysqld_stmt_execute_packet_t *cmd; |
4992 | + const char raw_packet[] = |
4993 | + "\x7a\x00\x00\x00" |
4994 | + "\x17" /* COM_STMT_EXECUTE */ |
4995 | + "\x01\x00\x00\x00" /* stmt-id */ |
4996 | + "\x00" /* flags */ |
4997 | + "\x01\x00\x00\x00" /* iteration count */ |
4998 | + "\x03\x00" /* nul-flags */ |
4999 | + "\x01" /* yeah, we have parameters */ |
5000 | + "\xfe\x00\x06\x00\xfe\x00\x08\x00\x08\x80\x03\x00\x02\x00\x01\x00\x05\x00\x04\x00\x0a\x00\x0c\x00\x07\x00\x0b\x00" /* param-defs */ |