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