Merge lp:~jan-kneschke/mysql-proxy/prep-stmt-codecs into lp:mysql-proxy/0.8

Proposed by Jan Kneschke
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
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.

Description of the change

* added a network_mysqld_type_t infrastructure that can store and convert types that are known to the binary row type (network_mysqld_type.[ch])
* added encoders and decoders for the binary row format (network_mysqld_proto_binary.[ch])
* 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/tutorial-prep-stmt.lua

To post a comment you must log in.
1167. By <email address hidden>

restructed the file into a valid reST file and added infos about MYSQL_TYPE_* and COM_*

  * see http://docutils.sourceforge.net/

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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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, &param_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 */
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches