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

Proposed by Jan Kneschke
Status: Superseded
Proposed branch: lp:~jan-kneschke/mysql-proxy/prep-stmt-codecs
Merge into: lp:mysql-proxy/0.8
Diff against target: 4036 lines (+3583/-176)
18 files modified
doc/protocol.txt (+476/-121)
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 (+441/-0)
src/network_mysqld_proto_binary.h (+12/-0)
src/network_mysqld_type.c (+656/-0)
src/network_mysqld_type.h (+147/-0)
tests/unit/CMakeLists.txt (+2/-0)
tests/unit/Makefile.am (+18/-0)
tests/unit/lua/mysql-proto.lua (+70/-1)
tests/unit/t_network_mysqld_packet.c (+636/-0)
tests/unit/t_network_mysqld_type.c (+205/-0)
To merge this branch: bzr merge lp:~jan-kneschke/mysql-proxy/prep-stmt-codecs
Reviewer Review Type Date Requested Status
Registry Administrators Pending
Review via email: mp+36129@code.launchpad.net

This proposal has been superseded by a proposal from 2010-09-22.

Description of the change

* added a network_mysqld_type_t infrastructure that can store and convert types that are known to the binary row type (network_mysqld_type.[ch])
* added encoders and decoders for the binary row format (network_mysqld_proto_binary.[ch])
* added encoders and decoders for COM_STMT_PREPARE, COM_STMT_EXECUTE, COM_STMT_CLOSE and its special response packets
* added a example on how to use them examples/tutorial-prep-stmt.lua

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

handle invalid type gracefully instead of causing a g_error()

1159. By <email address hidden>

moved the protocol dumps to doc/protocol.txt

1160. By <email address hidden>

removed unnecessary use of G_STMT_START and _END

1161. By <email address hidden>

cleaned up the code and the comments a bit

  * removed bogus comments
  * use wrapper functions like network_mysqld_type_set_* instead of type->set_*()
  * use a switch(type) instead of if'ing each value one by one

1162. By <email address hidden>

split the packet into reasonible pieces

1163. By <email address hidden>

added test-case for network_mysqld_type.c

  * expose the min-buf-len's for the _get_string() functions that use a fixed buffer

1164. By <email address hidden>

check the length of the date and time fields before we add them to the strings

  * use the _MIN_BUF_LEN's instead of counting the min-buf-lengths by hand

1165. By <email address hidden>

cosmetic changes

  * use 'param' instead of 'type' here
  * removed bogus comments

1166. By <email address hidden>

if we can't get the double, don't try to append it

1167. By <email address hidden>

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

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

1168. By <email address hidden>

streamlined the payload description

  * described the possible types of the payload
  * adjusted the payload descriptions of the packets to follow it strictly

1169. By <email address hidden>

allow COM_STMT_PREPAREs to fail and linked its OK packet

1170. By <email address hidden>

document COM_SLEEP, COM_INIT_DB, _CREATE_DB and _DROP_DB

1171. By <email address hidden>

moved OK and ERR into the Generic Packets section and EOF into the text resultset

1172. By <email address hidden>

added 'COM_STMT_EXECUTE Response' and added a few more 'response:' fields to the packet definitions

1173. By <email address hidden>

added LOCAL INFILE handling

1174. By <email address hidden>

added links to the external documents describing the protocol

1175. By <email address hidden>

documented the packets of the auth phase

1176. By <email address hidden>

added COM_STMT_RESET and _STMT_SEND_LONG_DATA

1177. By <email address hidden>

added the pre-4.1 column definition

1178. By <email address hidden>

COM_STMT_RESET has a response: OK or ERR

1179. By <email address hidden>

_SEND_LONG_DATA is 18

1180. By <email address hidden>

added COM_FIELD_LIST

1181. By <email address hidden>

added COM_PROCESS_INFO, _PROCESS_KILL and _PING

1182. By <email address hidden>

documented the commands that are not handled by the server

1183. By <email address hidden>

added COM_SET_OPTION

1184. By <email address hidden>

added COM_DEBUG, _STATISTICS and _SHUTDOWN

1185. By <email address hidden>

TABLE_DUMP and CONNECT_OUT are undefined in 5.x

1186. By <email address hidden>

added COM_CHANGE_USER

1187. By <email address hidden>

documented multi-resultsets and all the server-status flags

1188. By <email address hidden>

moved the status flags to the OK packet

1189. By <email address hidden>

added the capability flags

1190. By <email address hidden>

added some more cross-references

1191. By <email address hidden>

fixed section indention to put the COM_* responses as sub-section of the command

1192. By <email address hidden>

added the COM_STMT_EXECUTE flags and did some cosmetic changes and typo fixes

1193. By <email address hidden>

replaced doxygen version of scripting.txt by a reST version

  * added the basic structure
  * documented the mysql.proto module

1194. By <email address hidden>

removed the document headings

1195. By <email address hidden>

moved the protocol.txt and scripting.txt into the chapter/ dir

  * allow to include them into standalone documents and into the
    full book

1196. By <email address hidden>

added rules to generate a full book and standalone pieces of protocol and scripting

1197. By <email address hidden>

removed the use of the gnu-make extension

1198. By <email address hidden>

use AC_MISSING() to let "make html" fail nicely if rst2html.py isn't installed

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'doc/protocol.txt'
2--- doc/protocol.txt 2009-06-29 16:39:46 +0000
3+++ doc/protocol.txt 2010-09-22 15:13:16 +0000
4@@ -1,123 +1,478 @@
5-/**
6-@page protocol MySQL Protocol
7-
8-The MySQL Protocol is spilt into the four phases:
9-
10-@dot
11-digraph {
12-connect -> auth;
13-auth -> command;
14-command -> disconnect;
15-command -> command;
16-connect -> disconnect;
17-auth -> disconnect;
18-}
19-@enddot
20-
21-The client and the server send and receive packets as documented in http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol
22-
23-@dot
24-digraph states {
25- graph [rankdir=LR];
26- node [fontname=Helvetica, fontsize=10];
27-
28- connect [ shape=record ];
29- disconnect [ shape=record ];
30-
31- subgraph cluster_client {
32- label = "client";
33- style = filled;
34- node [ style=filled, fillcolor=lightblue ];
35- connect;
36- auth_response;
37- auth_old;
38- command;
39- command_local;
40- }
41-
42- subgraph cluster_server {
43- label = "server";
44- style = filled;
45- node [ style=filled, fillcolor=orange ];
46- auth_challenge;
47- auth_result;
48- command_result;
49- command_infile;
50- }
51-
52- subgraph {
53- edge [ fontcolor=blue, color=blue, fontsize=10, fontname=Helvetica ];
54-
55- connect->auth_challenge [ label = "connecting server" ];
56- auth_response->auth_result [ label = "capabilities, password, default-db", URL="http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Client_Authentication_Packet" ];
57- auth_old->auth_result [ label = "scrambled password" ] ;
58- command->command_result [ label = "command (COM_*)", URL="http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Command_Packet" ] ;
59- command->command_infile [ label = "LOAD DATA INFILE LOCAL" ];
60- command_local->command_result [ label = "file content"];
61- }
62-
63- subgraph {
64- edge [ fontcolor=red, color=red, fontsize=10, fontname=Helvetica ];
65- auth_challenge->disconnect [ label = "ERR: host denied", URL="http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Error_Packet" ];
66- auth_challenge->auth_response [ label = "0x10: auth_challenge", URL="http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Handshake_Initialization_Packet" ];
67- auth_result->auth_old [ label = "EOF: old password reauth" ];
68- auth_result->command [ label = "OK: auth done", URL="http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#OK_Packet" ];
69- auth_result->disconnect [ label = "ERR: auth failed", URL="http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Error_Packet" ];
70- command_result->command [ label = "OK|ERR|Resultset", URL="http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Result_Set_Header_Packet" ] ;
71- command_result->disconnect [ label = "command = COM_QUIT" ];
72- command_result->command_result [ label = "command = COM_BINLOG_DUMP" ];
73- command_infile->command_local [ label = "EOF: filename" ];
74- }
75-}
76-@enddot
77-
78-The @ref page-core exposes all the states to the @ref page-plugins.
79-
80-@section section-protocol-use-cases Use Cases
81-
82--# the client connects to the server and waits for data to return @msc
83- client, backend;
84- --- [ label = "connect to backend" ];
85- client->backend [ label = "INIT" ];
86-@endmsc
87--# the auth-phase handles the new SHA1-style passwords and the old scramble() passwords
88- -# 4.1+ passwords @msc
89- client, backend;
90- --- [ label = "authenticate" ];
91- backend->client [ label = "HANDSHAKE" ];
92- client->backend [ label = "AUTH" ];
93- backend->client [ label = "AUTH_RESULT" ];
94-@endmsc
95- -# pre-4.1 passwords @msc
96- client, backend;
97- --- [ label = "authenticate" ];
98- backend->client [ label = "HANDSHAKE" ];
99- client->backend [ label = "AUTH" ];
100- backend->client [ label = "OLD_PASSWORD_SCRAMBLE" ];
101- client->backend [ label = "OLD_PASSWORD_AUTH" ];
102- backend->client [ label = "AUTH_RESULT" ];
103-@endmsc
104--# the query-phase repeats
105- -# COM_QUERY and friends @msc
106- client, backend;
107- --- [ label = "query result phase" ];
108- client->backend [ label = "QUERY" ];
109- backend->client [ label = "QUERY_RESULT" ];
110-@endmsc
111- -# COM_QUIT @msc
112- client, backend;
113- --- [ label = "query result phase" ];
114- client->backend [ label = "QUERY" ];
115- backend->client [ label = "connection close" ];
116-@endmsc
117- -# COM_BINLOG_DUMP @msc
118- client, backend;
119- --- [ label = "query result phase" ];
120- client->backend [ label = "QUERY" ];
121- backend->client [ label = "QUERY_RESULT" ];
122- ... [ label = "more binlog entries" ];
123- backend->client [ label = "QUERY_RESULT"];
124-@endmsc
125- */
126+
127+
128+
129+The packets
130+===========
131+
132+All the examples here are captured with:
133+
134+ $ ngrep -x -q -d lo0 '' 'port 3306'
135+
136+The packets that are exchanged between client and server look like:
137+
138+ ...
139+ T 127.0.0.1:51656 -> 127.0.0.1:3306 [AP]
140+ 01 00 00 00 01
141+
142+The example shows a COM_QUIT packet. It starts (like all packets) with a 4 byte packet header:
143+
144+* 3 byte length
145+* 1 byte sequence-id
146+
147+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
148+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.
149+
150+The sequence-id is incremented with each packet for a sequence of packets. It is reset, when a new command begins.
151+
152+A mysql client logs in
153+----------------------
154+
155+Taking a look at the packet dump when a mysql-client logs in:
156+
157+ client -> server
158+ <connect>
159+
160+The client initiates the communication by connecting to the server.
161+
162+ server -> client
163+ 36 00 00 00 0a 35 2e 35 2e 32 2d 6d 32 00 03 00 6....5.5.2-m2...
164+ 00 00 27 75 3e 6f 38 66 79 4e 00 ff f7 08 02 00 ..'u>o8fyN......
165+ 00 00 00 00 00 00 00 00 00 00 00 00 00 57 4d 5d .............WM]
166+ 6a 7c 53 68 32 5c 59 2e 73 00 j|Sh2\Y.s.
167+
168+which responds with a handshake packet which contains the version, some flags and a password challenge.
169+
170+ client -> server
171+ 3a 00 00 01 05 a6 03 00 00 00 00 01 08 00 00 00 :...............
172+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
173+ 00 00 00 00 72 6f 6f 74 00 14 cb b5 ea 68 eb 6b ....root.....h.k
174+ 3b 03 cb ae fb 9b df 5a cb 0f 6d b5 de fd ;......Z..m...
175+
176+The client answers with username, some flags and the response to the challenge.
177+
178+ server -> client
179+ 07 00 00 02 00 00 00 02 00 00 00 ...........
180+
181+As the client provided the right password and the flags are fine, the server responds with a OK packet. That closes auth-phase
182+and switches to the command-phase.
183+
184+ client -> server
185+ 21 00 00 00 03 73 65 6c 65 63 74 20 40 40 76 65 !....select @@ve
186+ 72 73 69 6f 6e 5f 63 6f 6d 6d 65 6e 74 20 6c 69 rsion_comment li
187+ 6d 69 74 20 31 mit 1
188+
189+The mysql client first checks the version string of the server and sends a COM_QUERY packet.
190+
191+ server -> client
192+ 01 00 00 01 01 27 00 00 02 03 64 65 66 00 00 00 .....'....def...
193+ 11 40 40 76 65 72 73 69 6f 6e 5f 63 6f 6d 6d 65 .@@version_comme
194+ 6e 74 00 0c 08 00 1c 00 00 00 fd 00 00 1f 00 00 nt..............
195+ 05 00 00 03 fe 00 00 02 00 1d 00 00 04 1c 4d 79 ..............My
196+ 53 51 4c 20 43 6f 6d 6d 75 6e 69 74 79 20 53 65 SQL Community Se
197+ 72 76 65 72 20 28 47 50 4c 29 05 00 00 05 fe 00 rver (GPL)......
198+ 00 02 00 ...
199+
200+The server responds with a resultset containing the version-string.
201+
202+ client -> server
203+ 0e 00 00 00 03 73 65 6c 65 63 74 20 55 53 45 52 .....select USER
204+ 28 29 ()
205+
206+For the prompt (\u ...) the mysql client also asks for the current username.
207+
208+ server -> client
209+ 01 00 00 01 01 1c 00 00 02 03 64 65 66 00 00 00 ..........def...
210+ 06 55 53 45 52 28 29 00 0c 08 00 4d 00 00 00 fd .USER()....M....
211+ 01 00 1f 00 00 05 00 00 03 fe 00 00 02 00 0f 00 ................
212+ 00 04 0e 72 6f 6f 74 40 6c 6f 63 61 6c 68 6f 73 ...root@localhos
213+ 74 05 00 00 05 fe 00 00 02 00 t.........
214+
215+which is 'root@localhost' in this example.
216+
217+You can also see how the sequence-id starts with 00 for each new sequence of packets.
218+
219+Describing packets
220+------------------
221+
222+In this document we describe the packets by first defining their payload and provide examples with packet header and payload as
223+you would see it on the wire.
224+
225+ COM_QUIT
226+ <description>
227+
228+ direction: client -> server
229+ response: ...
230+
231+ payload:
232+ <type> <description>
233+
234+ Example:
235+ 01 00 00 00 01
236+
237+The payload types
238+.................
239+
240+The MySQL Protocol has a set of possible encodings for integers:
241+
242+ * fixed length intergers
243+ * length encoded integers
244+
245+The fixed length integers are described by their byte-length (1, 2, 3, 4, 8) and send their first byte first as seen in the packet length
246+above:
247+
248+ 01 00 00 00 01
249+
250+is the packet length 1 as it is a 3-byte fixed length integer.
251+
252+In other places integers have a variable size if (1, 3, 4, 9) bytes depending on their value and are described as 'lenenc-int'.
253+
254+ < 251 - 1 byte
255+ >= 251 < (2^16 - 1) - 3 byte
256+ >= (2^16) < (2^24 - 1) - 4 byte
257+ >= (2^24) - 9 byte
258+
259+The 1-byte values from 251 to 255 have a special meaning and aren't used for integers:
260+
261+ * 0xfb -> 251 - NULL
262+ * 0xfc -> 252 - next is a 2-byte integer
263+ * 0xfd -> 253 - next is a 3-byte integer
264+ * 0xfe -> 254 - next is a 8-byte integer or a EOF packet
265+ * 0xff -> 255 - ERR packet
266+
267+The auth phase
268+--------------
269+
270+ * auth-challenge
271+ * auth-response
272+ * old-password
273+ * ok, err
274+
275+The command phase
276+-----------------
277+
278+In the command phase the client sends a command packet with the sequence-id 0:
279+
280+ 13 00 00 00 03 53 ...
281+ 01 00 00 00 01
282+ ^^
283+
284+The first byte of the payload describes the command-type like:
285+
286+* COM_QUERY
287+* COM_QUIT
288+* ...
289+
290+COM_QUIT
291+--------
292+
293+ COM_QUIT
294+ tells the server that the client wants to close the connection
295+
296+ direction: client -> server
297+ response: either a connection close or a OK packet
298+
299+ payload:
300+ \x01 command-byte: COM_QUIT
301+
302+ Example:
303+ 01 00 00 00 01
304+
305+
306+COM_QUERY
307+---------
308+
309+ COM_QUERY
310+ tells the server to execute a text-based query
311+
312+ direction: client -> server
313+ response: a query-response packet
314+
315+ payload:
316+ 1 command-byte: COM_QUERY
317+ n the query the server shall execute
318+
319+ Example:
320+
321+Query-Response packet
322+---------------------
323+
324+The query-response packet is a meta packet which can be one of
325+
326+ * a ERR packet
327+ * a OK packet
328+ * a LOCAL INFILE packet
329+ * a resultset
330+
331+The type of the packet is defined by the type-identifier:
332+
333+ COM_QUERY response
334+ response to a COM_QUERY packet
335+
336+ payload
337+ lenenc-int number of columns in the resultset
338+
339+If the number of columns in the resultset is 0, this is a OK packet.
340+
341+If it is not a valid lenenc-int (ERR, EOF) it is a either a ERR packet or a LOCAL INFILE packet.
342+
343+OK packet
344+---------
345+
346+ OK
347+
348+ direction: server -> client
349+
350+ payload:
351+ 1 [00] the OK header
352+ lenenc-int affected rows
353+ lenenc-int last-insert-id
354+ 2 flags
355+ if capabilities & PROTOCOL_41:
356+ 2 warnings
357+
358+ example:
359+ 07 00 00 02 00 00 00 02 00 00 00 ...........
360+
361+ERR packet
362+----------
363+
364+ ERR
365+
366+ direction: server -> client
367+
368+ payload:
369+ 1 [ff] the ERR header
370+ 2 error code
371+ if capabilities & PROTOCOL_41:
372+ 1 '#' the sql-state marker
373+ string[5] sql-state
374+ all protocols:
375+ string* error-message
376+
377+ example:
378+ 17 00 00 01 ff 48 04 23 48 59 30 30 30 4e 6f 20 .....H.#HY000No
379+ 74 61 62 6c 65 73 20 75 73 65 64 tables used
380+
381+
382+EOF packet
383+----------
384+
385+ EOF
386+
387+ direction: server -> client
388+
389+ payload:
390+ 1 [fe] the EOF header
391+ if capabilities & PROTOCOL_41:
392+ 2 warning count
393+ 2 server-status
394+
395+ example:
396+ ... 05 00 00 05 fe 00 00 02 00
397+
398+The server-status is a bit-field:
399+
400+ * _AUTOCOMMIT == 2
401+
402+The prepare statement protocol
403+------------------------------
404+
405+ COM_STMT_PREPARE
406+ create a prepared statement
407+
408+ payload:
409+ 1 [16] the COM_STMT_PREPARE command
410+ string the query to prepare
411+
412+ example:
413+ 1c 00 00 00 16 53 45 4c 45 43 54 20 43 4f 4e 43 .....SELECT CONC
414+ 41 54 28 3f 2c 20 3f 29 20 41 53 20 63 6f 6c 31 AT(?, ?) AS col1
415+
416+
417+COM_STMT_PREPARE response
418+-------------------------
419+
420+* COM_STMT_PREPARE OK
421+* num-params * <param-defs> <EOF packet> if num-params > 0
422+* num-colums * <column-defs> <EOF packet> if num-columns > 0
423+
424+Example:
425+
426+ 0c 00 00 01 00 01 00 00 00 01 00 02 00 00 00 00| ................
427+ 17 00 00 02 03 64 65 66 00 00 00 01 3f 00 0c 3f .....def....?..?
428+ 00 00 00 00 00 fd 80 00 00 00 00|17 00 00 03 03 ................
429+ 64 65 66 00 00 00 01 3f 00 0c 3f 00 00 00 00 00 def....?..?.....
430+ fd 80 00 00 00 00|05 00 00 04 fe 00 00 02 00|1a ................
431+ 00 00 05 03 64 65 66 00 00 00 04 63 6f 6c 31 00 ....def....col1.
432+ 0c 3f 00 00 00 00 00 fd 80 00 1f 00 00|05 00 00 .?..............
433+ 06 fe 00 00 02 00 ......
434+
435+for a query without parameters and resultset like "DO 1" it is:
436+
437+ 0c 00 00 01 00 01 00 00 00 00 00 00 00 00 00 00
438+
439+COM_STMT_PREPARE OK packet
440+--------------------------
441+
442+ COM_STMT_PREPARE OK
443+ OK response to a COM_STMT_PREPARE packet
444+
445+ direction: server -> client
446+
447+ payload:
448+ 4 statement-id
449+ 2 num columns
450+ 2 num params
451+ 1 filler
452+ 2 warning count
453+
454+
455+COM_STMT_EXECUTE
456+----------------
457+
458+ COM_STMT_EXECUTE
459+ execute a prepared statement
460+
461+ direction: client -> server
462+
463+ payload:
464+ 1 [17] COM_STMT_EXECUTE
465+ 4 stmt-id
466+ 1 flags
467+ 4 iteration-count
468+ nul-bit-map
469+ 1 new-params-bound-flag
470+ if new-params-bound-flag == 1:
471+ param-count*2 type of each parameter
472+ data<n> value of each parameter, see Binary Resultset value format
473+
474+ example:
475+
476+Binary Resultset value format
477+---------------------------
478+
479+ Strings
480+ lenenc-int length of the string
481+ string<len> string
482+
483+ example:
484+ 03 66 6f 6f -- string = "foo"
485+
486+ int64
487+ 8 integer least significant byte first
488+
489+ example:
490+ 01 00 00 00 00 00 00 00 -- int64 = 1
491+
492+ int32
493+ 4 integer least significant byte first
494+
495+ example:
496+ 01 00 00 00 -- int32 = 1
497+
498+ int16
499+ 2 integer least significant byte first
500+
501+ example:
502+ 01 00 -- int16 = 1
503+
504+ int8
505+ 1 integer
506+
507+ example:
508+ 01 -- int8 = 1
509+
510+ double
511+ 8 double
512+
513+ example:
514+ 66 66 66 66 66 66 24 40 -- double = 10.2
515+
516+ float
517+ 4 float
518+
519+ example:
520+ 33 33 23 41 -- float = 10.2
521+
522+ date
523+ 1 length == [04]
524+ 2 year
525+ 1 month
526+ 1 day
527+
528+ example:
529+ 04 da 07 0a 11 -- date = 2010-10-17
530+
531+ datetime
532+ 1 length == [0b]
533+ 2 year
534+ 1 month
535+ 1 day
536+ 1 hour
537+ 1 minutes
538+ 1 seconds
539+ 4 nseconds
540+
541+ example:
542+ 0b da 07 0a 11 13 1b 1e 01 00 00 00 -- datetime 2010-10-17 19:27:30.000 000 001
543+
544+ time
545+ 1 length == [0c]
546+ 1 sign (1 if minus, 0 for plus)
547+ 4 days
548+ 1 hour
549+ 1 minutes
550+ 1 seconds
551+ 4 nseconds
552+
553+ example:
554+ 0c 01 78 00 00 00 13 1b 1e 01 00 00 00 -- time -120d 19:27:30.000 000 001
555+
556+ timestamp
557+ 1 length == [0b]
558+ 2 year
559+ 1 month
560+ 1 day
561+ 1 hour
562+ 1 minutes
563+ 1 seconds
564+ 4 nseconds
565+
566+ example:
567+ 0b da 07 0a 11 13 1b 1e 01 00 00 00 -- timestamp
568+
569+COM_STMT_EXECUTE resultset
570+--------------------------
571+
572+COM_STMT_EXECUTE resultset is similar the COM_QUERY resulset. It just contains the rows in
573+Binary Row Format.
574+
575+ lenenc field-count
576+ field-count * fielddef
577+ <EOF>
578+ <rows>
579+ <EOF>
580+
581+ example:
582+ 01 00 00 01 01|1a 00 00 02 03 64 65 66 00 00 00 ..........def...
583+ 04 63 6f 6c 31 00 0c 08 00 06 00 00 00 fd 00 00 .col1...........
584+ 1f 00 00|05 00 00 03 fe 00 00 02 00|09 00 00 04 ................
585+ 00 00 06 66 6f 6f 62 61 72|05 00 00 05 fe 00 00 ...foobar.......
586+ 02 00 ..
587+
588+
589+COM_STMT_CLOSE
590+--------------
591+
592+ COM_STMT_CLOSE
593+ payload:
594+ 1 [19]
595+ 4 statement-id
596+
597+ example:
598+ 05 00 00 00 19 01 00 00 00 .........
599+
600+
601+
602
603
604
605=== modified file 'examples/Makefile.am'
606--- examples/Makefile.am 2009-07-03 12:28:02 +0000
607+++ examples/Makefile.am 2010-09-22 15:13:16 +0000
608@@ -8,6 +8,7 @@
609 tutorial-monitor.lua \
610 tutorial-packets.lua \
611 tutorial-query-time.lua \
612+ tutorial-prep-stmts.lua \
613 tutorial-resultset.lua \
614 tutorial-rewrite.lua \
615 tutorial-routing.lua \
616
617=== added file 'examples/tutorial-prep-stmts.lua'
618--- examples/tutorial-prep-stmts.lua 1970-01-01 00:00:00 +0000
619+++ examples/tutorial-prep-stmts.lua 2010-09-22 15:13:16 +0000
620@@ -0,0 +1,74 @@
621+--[[ $%BEGINLICENSE%$
622+ Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
623+
624+ This program is free software; you can redistribute it and/or
625+ modify it under the terms of the GNU General Public License as
626+ published by the Free Software Foundation; version 2 of the
627+ License.
628+
629+ This program is distributed in the hope that it will be useful,
630+ but WITHOUT ANY WARRANTY; without even the implied warranty of
631+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
632+ GNU General Public License for more details.
633+
634+ You should have received a copy of the GNU General Public License
635+ along with this program; if not, write to the Free Software
636+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
637+ 02110-1301 USA
638+
639+ $%ENDLICENSE%$ --]]
640+
641+local proto = require("mysql.proto")
642+
643+local prep_stmts = { }
644+
645+function read_query( packet )
646+ local cmd_type = packet:byte()
647+ if cmd_type == proxy.COM_STMT_PREPARE then
648+ proxy.queries:append(1, packet, { resultset_is_needed = true } )
649+ return proxy.PROXY_SEND_QUERY
650+ elseif cmd_type == proxy.COM_STMT_EXECUTE then
651+ proxy.queries:append(2, packet, { resultset_is_needed = true } )
652+ return proxy.PROXY_SEND_QUERY
653+ elseif cmd_type == proxy.COM_STMT_CLOSE then
654+ proxy.queries:append(3, packet, { resultset_is_needed = true } )
655+ return proxy.PROXY_SEND_QUERY
656+ end
657+end
658+
659+function read_query_result(inj)
660+ if inj.id == 1 then
661+ -- print the query we sent
662+ local stmt_prepare = assert(proto.from_stmt_prepare_packet(inj.query))
663+ print(("> PREPARE: %s"):format(stmt_prepare.stmt_text))
664+
665+ -- and the stmt-id we got for it
666+ if inj.resultset.raw:byte() == 0 then
667+ local stmt_prepare_ok = assert(proto.from_stmt_prepare_ok_packet(inj.resultset.raw))
668+ print(("< PREPARE: stmt-id = %d (resultset-cols = %d, params = %d)"):format(
669+ stmt_prepare_ok.stmt_id,
670+ stmt_prepare_ok.num_columns,
671+ stmt_prepare_ok.num_params))
672+
673+ prep_stmts[stmt_prepare_ok.stmt_id] = {
674+ num_columns = stmt_prepare_ok.num_columns,
675+ num_params = stmt_prepare_ok.num_params,
676+ }
677+ end
678+ elseif inj.id == 2 then
679+ local stmt_id = assert(proto.stmt_id_from_stmt_execute_packet(inj.query))
680+ local stmt_execute = assert(proto.from_stmt_execute_packet(inj.query, prep_stmts[stmt_id].num_params))
681+ print(("> EXECUTE: stmt-id = %d"):format(stmt_execute.stmt_id))
682+ if stmt_execute.new_params_bound then
683+ for ndx, v in ipairs(stmt_execute.params) do
684+ print((" [%d] %s (type = %d)"):format(ndx, tostring(v.value), v.type))
685+ end
686+ end
687+ elseif inj.id == 3 then
688+ local stmt_close = assert(proto.from_stmt_close_packet(inj.query))
689+ print(("> CLOSE: stmt-id = %d"):format(stmt_close.stmt_id))
690+
691+ prep_stmts[stmt_close.stmt_id] = nil -- cleanup
692+ end
693+end
694+
695
696=== modified file 'lib/mysql-proto.c'
697--- lib/mysql-proto.c 2010-04-06 14:26:51 +0000
698+++ lib/mysql-proto.c 2010-09-22 15:13:16 +0000
699@@ -30,6 +30,7 @@
700
701 #include "network-mysqld-proto.h"
702 #include "network-mysqld-packet.h"
703+#include "network_mysqld_type.h"
704 #include "network-mysqld-masterinfo.h"
705 #include "glib-ext.h"
706 #include "lua-env.h"
707@@ -57,6 +58,10 @@
708 lua_pushinteger(L, x->y); \
709 lua_setfield(L, -2, G_STRINGIFY(y));
710
711+#define LUA_EXPORT_BOOL(x, y) \
712+ lua_pushboolean(L, x->y); \
713+ lua_setfield(L, -2, G_STRINGIFY(y));
714+
715 #define LUA_EXPORT_STR(x, y) \
716 if (x->y->len) { \
717 lua_pushlstring(L, S(x->y)); \
718@@ -466,6 +471,266 @@
719 return 1;
720 }
721
722+static int lua_proto_get_stmt_prepare_packet (lua_State *L) {
723+ size_t packet_len;
724+ const char *packet_str = luaL_checklstring(L, 1, &packet_len);
725+ network_mysqld_stmt_prepare_packet_t *cmd;
726+ network_packet packet;
727+ GString s;
728+ int err = 0;
729+
730+ s.str = (char *)packet_str;
731+ s.len = packet_len;
732+
733+ packet.data = &s;
734+ packet.offset = 0;
735+
736+ cmd = network_mysqld_stmt_prepare_packet_new();
737+
738+ err = err || network_mysqld_proto_get_stmt_prepare_packet(&packet, cmd);
739+ if (err) {
740+ network_mysqld_stmt_prepare_packet_free(cmd);
741+
742+ luaL_error(L, "%s: network_mysqld_proto_get_stmt_prepare_packet() failed", G_STRLOC);
743+ return 0;
744+ }
745+
746+ lua_newtable(L);
747+
748+ LUA_EXPORT_STR(cmd, stmt_text);
749+
750+ network_mysqld_stmt_prepare_packet_free(cmd);
751+
752+ return 1;
753+}
754+
755+/**
756+ * transform the OK packet of a COM_STMT_PREPARE result into a table
757+ */
758+static int lua_proto_get_stmt_prepare_ok_packet (lua_State *L) {
759+ size_t packet_len;
760+ const char *packet_str = luaL_checklstring(L, 1, &packet_len);
761+ network_mysqld_stmt_prepare_ok_packet_t *cmd;
762+ network_packet packet;
763+ GString s;
764+ int err = 0;
765+
766+ s.str = (char *)packet_str;
767+ s.len = packet_len;
768+
769+ packet.data = &s;
770+ packet.offset = 0;
771+
772+ cmd = network_mysqld_stmt_prepare_ok_packet_new();
773+
774+ err = err || network_mysqld_proto_get_stmt_prepare_ok_packet(&packet, cmd);
775+ if (err) {
776+ network_mysqld_stmt_prepare_ok_packet_free(cmd);
777+
778+ luaL_error(L, "%s: network_mysqld_proto_get_stmt_prepare_ok_packet() failed", G_STRLOC);
779+ return 0;
780+ }
781+
782+ lua_newtable(L);
783+
784+ LUA_EXPORT_INT(cmd, stmt_id);
785+ LUA_EXPORT_INT(cmd, num_columns);
786+ LUA_EXPORT_INT(cmd, num_params);
787+ LUA_EXPORT_INT(cmd, warnings);
788+
789+ network_mysqld_stmt_prepare_ok_packet_free(cmd);
790+
791+ return 1;
792+}
793+
794+/**
795+ * get the stmt-id from the com-stmt-execute packet
796+ */
797+static int lua_proto_get_stmt_execute_packet (lua_State *L) {
798+ size_t packet_len;
799+ const char *packet_str = luaL_checklstring(L, 1, &packet_len);
800+ int param_count = luaL_checkint(L, 2);
801+ network_mysqld_stmt_execute_packet_t *cmd;
802+ network_packet packet;
803+ GString s;
804+ int err = 0;
805+
806+ s.str = (char *)packet_str;
807+ s.len = packet_len;
808+
809+ packet.data = &s;
810+ packet.offset = 0;
811+
812+ cmd = network_mysqld_stmt_execute_packet_new();
813+
814+ err = err || network_mysqld_proto_get_stmt_execute_packet(&packet, cmd, param_count);
815+ if (err) {
816+ network_mysqld_stmt_execute_packet_free(cmd);
817+
818+ luaL_error(L, "%s: network_mysqld_proto_get_stmt_execute_packet() failed", G_STRLOC);
819+ return 0;
820+ }
821+
822+ lua_newtable(L);
823+
824+ LUA_EXPORT_INT(cmd, stmt_id);
825+ LUA_EXPORT_INT(cmd, flags);
826+ LUA_EXPORT_INT(cmd, iteration_count);
827+ LUA_EXPORT_BOOL(cmd, new_params_bound);
828+
829+ if (cmd->new_params_bound) {
830+ guint i;
831+
832+ lua_newtable(L);
833+ for (i = 0; i < cmd->params->len; i++) {
834+ network_mysqld_type_t *param = g_ptr_array_index(cmd->params, i);
835+
836+ lua_newtable(L);
837+ lua_pushnumber(L, param->type);
838+ lua_setfield(L, -2, "type");
839+
840+ if (param->is_null) {
841+ lua_pushnil(L);
842+ } else {
843+ const char *const_s;
844+ char *_s;
845+ gsize s_len;
846+ guint64 _i;
847+ gboolean is_unsigned;
848+ double d;
849+
850+ switch (param->type) {
851+ case MYSQL_TYPE_BLOB:
852+ case MYSQL_TYPE_MEDIUM_BLOB:
853+ case MYSQL_TYPE_LONG_BLOB:
854+ case MYSQL_TYPE_STRING:
855+ case MYSQL_TYPE_VARCHAR:
856+ case MYSQL_TYPE_VAR_STRING:
857+ if (0 != network_mysqld_type_get_string_const(param, &const_s, &s_len)) {
858+ return luaL_error(L, "%s: _get_string_const() failed for type = %d",
859+ G_STRLOC,
860+ param->type);
861+ }
862+
863+ lua_pushlstring(L, const_s, s_len);
864+ break;
865+ case MYSQL_TYPE_TINY:
866+ case MYSQL_TYPE_SHORT:
867+ case MYSQL_TYPE_LONG:
868+ case MYSQL_TYPE_LONGLONG:
869+ if (0 != network_mysqld_type_get_int(param, &_i, &is_unsigned)) {
870+ return luaL_error(L, "%s: _get_int() failed for type = %d",
871+ G_STRLOC,
872+ param->type);
873+ }
874+
875+ lua_pushinteger(L, _i);
876+ break;
877+ case MYSQL_TYPE_DOUBLE:
878+ case MYSQL_TYPE_FLOAT:
879+ if (0 != network_mysqld_type_get_double(param, &d)) {
880+ return luaL_error(L, "%s: _get_double() failed for type = %d",
881+ G_STRLOC,
882+ param->type);
883+ }
884+
885+ lua_pushnumber(L, d);
886+ break;
887+ case MYSQL_TYPE_DATETIME:
888+ case MYSQL_TYPE_TIMESTAMP:
889+ case MYSQL_TYPE_DATE:
890+ case MYSQL_TYPE_TIME:
891+ _s = NULL;
892+ s_len = 0;
893+
894+ if (0 != network_mysqld_type_get_string(param, &_s, &s_len)) {
895+ return luaL_error(L, "%s: _get_string() failed for type = %d",
896+ G_STRLOC,
897+ param->type);
898+ }
899+
900+ lua_pushlstring(L, _s, s_len);
901+
902+ if (NULL != _s) g_free(_s);
903+ break;
904+ default:
905+ luaL_error(L, "%s: can't decode type %d yet",
906+ G_STRLOC,
907+ param->type); /* we don't have that value yet */
908+ break;
909+ }
910+ }
911+ lua_setfield(L, -2, "value");
912+ lua_rawseti(L, -2, i + 1);
913+ }
914+ lua_setfield(L, -2, "params");
915+ }
916+
917+ network_mysqld_stmt_execute_packet_free(cmd);
918+
919+ return 1;
920+}
921+
922+static int lua_proto_get_stmt_execute_packet_stmt_id (lua_State *L) {
923+ size_t packet_len;
924+ const char *packet_str = luaL_checklstring(L, 1, &packet_len);
925+ network_packet packet;
926+ GString s;
927+ int err = 0;
928+ guint32 stmt_id;
929+
930+ s.str = (char *)packet_str;
931+ s.len = packet_len;
932+
933+ packet.data = &s;
934+ packet.offset = 0;
935+
936+ err = err || network_mysqld_proto_get_stmt_execute_packet_stmt_id(&packet, &stmt_id);
937+ if (err) {
938+ luaL_error(L, "%s: network_mysqld_proto_get_stmt_execute_packet_stmt_id() failed", G_STRLOC);
939+ return 0;
940+ }
941+
942+ lua_pushinteger(L, stmt_id);
943+
944+ return 1;
945+}
946+
947+
948+static int lua_proto_get_stmt_close_packet (lua_State *L) {
949+ size_t packet_len;
950+ const char *packet_str = luaL_checklstring(L, 1, &packet_len);
951+ network_mysqld_stmt_close_packet_t *cmd;
952+ network_packet packet;
953+ GString s;
954+ int err = 0;
955+
956+ s.str = (char *)packet_str;
957+ s.len = packet_len;
958+
959+ packet.data = &s;
960+ packet.offset = 0;
961+
962+ cmd = network_mysqld_stmt_close_packet_new();
963+
964+ err = err || network_mysqld_proto_get_stmt_close_packet(&packet, cmd);
965+ if (err) {
966+ network_mysqld_stmt_close_packet_free(cmd);
967+
968+ luaL_error(L, "%s: network_mysqld_proto_get_stmt_close_packet() failed", G_STRLOC);
969+ return 0;
970+ }
971+
972+ lua_newtable(L);
973+
974+ LUA_EXPORT_INT(cmd, stmt_id);
975+
976+ network_mysqld_stmt_close_packet_free(cmd);
977+
978+ return 1;
979+}
980+
981+
982
983
984 /*
985@@ -497,6 +762,11 @@
986 {"to_response_packet", lua_proto_append_response_packet},
987 {"from_masterinfo_string", lua_proto_get_masterinfo_string},
988 {"to_masterinfo_string", lua_proto_append_masterinfo_string},
989+ {"from_stmt_prepare_packet", lua_proto_get_stmt_prepare_packet},
990+ {"from_stmt_prepare_ok_packet", lua_proto_get_stmt_prepare_ok_packet},
991+ {"from_stmt_execute_packet", lua_proto_get_stmt_execute_packet},
992+ {"stmt_id_from_stmt_execute_packet", lua_proto_get_stmt_execute_packet_stmt_id},
993+ {"from_stmt_close_packet", lua_proto_get_stmt_close_packet},
994 {NULL, NULL},
995 };
996
997
998=== modified file 'src/CMakeLists.txt'
999--- src/CMakeLists.txt 2010-04-06 15:18:47 +0000
1000+++ src/CMakeLists.txt 2010-09-22 15:13:16 +0000
1001@@ -69,6 +69,8 @@
1002 network-mysqld.c
1003 network-mysqld-lua.c
1004 network-mysqld-proto.c
1005+ network_mysqld_type.c
1006+ network_mysqld_proto_binary.c
1007 network-mysqld-binlog.c
1008 network-mysqld-packet.c
1009 network-mysqld-masterinfo.c
1010@@ -206,6 +208,8 @@
1011 network-mysqld.h
1012 network-mysqld-lua.h
1013 network-mysqld-proto.h
1014+ network_mysqld_type.h
1015+ network_mysqld_proto_binary.h
1016 network-mysqld-binlog.h
1017 network-mysqld-packet.h
1018 network-mysqld-masterinfo.h
1019
1020=== modified file 'src/Makefile.am'
1021--- src/Makefile.am 2010-05-03 14:26:32 +0000
1022+++ src/Makefile.am 2010-09-22 15:13:16 +0000
1023@@ -109,6 +109,8 @@
1024 network-mysqld-proto.c \
1025 network-mysqld-binlog.c \
1026 network-mysqld-packet.c \
1027+ network_mysqld_type.c \
1028+ network_mysqld_proto_binary.c \
1029 network-mysqld-masterinfo.c \
1030 network-conn-pool.c \
1031 network-conn-pool-lua.c \
1032@@ -137,6 +139,8 @@
1033 network-mysqld-proto.h \
1034 network-mysqld-binlog.h \
1035 network-mysqld-packet.h \
1036+ network_mysqld_type.h \
1037+ network_mysqld_proto_binary.h \
1038 network-mysqld-masterinfo.h \
1039 network-conn-pool.h \
1040 network-conn-pool-lua.h \
1041
1042=== modified file 'src/network-mysqld-packet.c'
1043--- src/network-mysqld-packet.c 2010-05-10 10:31:45 +0000
1044+++ src/network-mysqld-packet.c 2010-09-22 15:13:16 +0000
1045@@ -23,8 +23,11 @@
1046
1047 #include <stdlib.h>
1048 #include <stdio.h>
1049+#include <string.h>
1050
1051 #include "network-mysqld-packet.h"
1052+#include "network_mysqld_type.h"
1053+#include "network_mysqld_proto_binary.h"
1054
1055 #include "glib-ext.h"
1056
1057@@ -668,6 +671,57 @@
1058 return is_finished;
1059 }
1060
1061+int network_mysqld_proto_get_fielddef(network_packet *packet, network_mysqld_proto_fielddef_t *field, guint32 capabilities) {
1062+ int err = 0;
1063+
1064+ if (capabilities & CLIENT_PROTOCOL_41) {
1065+ err = err || network_mysqld_proto_get_lenenc_string(packet, &field->catalog, NULL);
1066+ err = err || network_mysqld_proto_get_lenenc_string(packet, &field->db, NULL);
1067+ err = err || network_mysqld_proto_get_lenenc_string(packet, &field->table, NULL);
1068+ err = err || network_mysqld_proto_get_lenenc_string(packet, &field->org_table, NULL);
1069+ err = err || network_mysqld_proto_get_lenenc_string(packet, &field->name, NULL);
1070+ err = err || network_mysqld_proto_get_lenenc_string(packet, &field->org_name, NULL);
1071+
1072+ err = err || network_mysqld_proto_skip(packet, 1); /* filler */
1073+
1074+ err = err || network_mysqld_proto_get_int16(packet, (guint16 *)&field->charsetnr);
1075+ err = err || network_mysqld_proto_get_int32(packet, (guint32 *)&field->length);
1076+ err = err || network_mysqld_proto_get_int8(packet, (guint8 *)&field->type);
1077+ err = err || network_mysqld_proto_get_int16(packet, (guint16 *)&field->flags);
1078+ err = err || network_mysqld_proto_get_int8(packet, (guint8 *)&field->decimals);
1079+
1080+ err = err || network_mysqld_proto_skip(packet, 2); /* filler */
1081+ } else {
1082+ guint8 len;
1083+
1084+ /* see protocol.cc Protocol::send_fields */
1085+
1086+ err = err || network_mysqld_proto_get_lenenc_string(packet, &field->table, NULL);
1087+ err = err || network_mysqld_proto_get_lenenc_string(packet, &field->name, NULL);
1088+ err = err || network_mysqld_proto_get_int8(packet, &len);
1089+ err = err || (len != 3);
1090+ err = err || network_mysqld_proto_get_int24(packet, (guint32 *)&field->length);
1091+ err = err || network_mysqld_proto_get_int8(packet, &len);
1092+ err = err || (len != 1);
1093+ err = err || network_mysqld_proto_get_int8(packet, (guint8 *)&field->type);
1094+ err = err || network_mysqld_proto_get_int8(packet, &len);
1095+ if (len == 3) { /* the CLIENT_LONG_FLAG is set */
1096+ err = err || network_mysqld_proto_get_int16(packet, (guint16 *)&field->flags);
1097+ err = err || network_mysqld_proto_get_int8(packet, (guint8 *)&field->decimals);
1098+ } else if (len == 2) {
1099+ guint8 flags = 0;
1100+ err = err || network_mysqld_proto_get_int8(packet, &flags);
1101+ err = err || network_mysqld_proto_get_int8(packet, (guint8 *)&field->decimals);
1102+
1103+ if (!err) field->flags = flags;
1104+ } else {
1105+ /* well */
1106+ }
1107+ }
1108+
1109+ return err ? -1 : 0;
1110+}
1111+
1112 /**
1113 * parse the result-set packet and extract the fields
1114 *
1115@@ -714,7 +768,7 @@
1116
1117 /* the next chunk, the field-def */
1118 for (i = 0; i < field_count; i++) {
1119- MYSQL_FIELD *field;
1120+ network_mysqld_proto_fielddef_t *field;
1121
1122 chunk = chunk->next;
1123 g_assert(chunk);
1124@@ -722,56 +776,11 @@
1125 packet.data = chunk->data;
1126 packet.offset = 0;
1127
1128+ field = network_mysqld_proto_fielddef_new();
1129+
1130 err = err || network_mysqld_proto_skip_network_header(&packet);
1131-
1132- field = network_mysqld_proto_fielddef_new();
1133-
1134- if (capabilities & CLIENT_PROTOCOL_41) {
1135- err = err || network_mysqld_proto_get_lenenc_string(&packet, &field->catalog, NULL);
1136- err = err || network_mysqld_proto_get_lenenc_string(&packet, &field->db, NULL);
1137- err = err || network_mysqld_proto_get_lenenc_string(&packet, &field->table, NULL);
1138- err = err || network_mysqld_proto_get_lenenc_string(&packet, &field->org_table, NULL);
1139- err = err || network_mysqld_proto_get_lenenc_string(&packet, &field->name, NULL);
1140- err = err || network_mysqld_proto_get_lenenc_string(&packet, &field->org_name, NULL);
1141-
1142- err = err || network_mysqld_proto_skip(&packet, 1); /* filler */
1143-
1144- err = err || network_mysqld_proto_get_int16(&packet, (guint16 *)&field->charsetnr);
1145- err = err || network_mysqld_proto_get_int32(&packet, (guint32 *)&field->length);
1146- err = err || network_mysqld_proto_get_int8(&packet, (guint8 *)&field->type);
1147- err = err || network_mysqld_proto_get_int16(&packet, (guint16 *)&field->flags);
1148- err = err || network_mysqld_proto_get_int8(&packet, (guint8 *)&field->decimals);
1149-
1150- err = err || network_mysqld_proto_skip(&packet, 2); /* filler */
1151- } else {
1152- guint8 len;
1153-
1154- /* see protocol.cc Protocol::send_fields */
1155-
1156- err = err || network_mysqld_proto_get_lenenc_string(&packet, &field->table, NULL);
1157- err = err || network_mysqld_proto_get_lenenc_string(&packet, &field->name, NULL);
1158- err = err || network_mysqld_proto_get_int8(&packet, &len);
1159- err = err || (len != 3);
1160- err = err || network_mysqld_proto_get_int24(&packet, (guint32 *)&field->length);
1161- err = err || network_mysqld_proto_get_int8(&packet, &len);
1162- err = err || (len != 1);
1163- err = err || network_mysqld_proto_get_int8(&packet, (guint8 *)&field->type);
1164- err = err || network_mysqld_proto_get_int8(&packet, &len);
1165- if (len == 3) { /* the CLIENT_LONG_FLAG is set */
1166- err = err || network_mysqld_proto_get_int16(&packet, (guint16 *)&field->flags);
1167- err = err || network_mysqld_proto_get_int8(&packet, (guint8 *)&field->decimals);
1168- } else if (len == 2) {
1169- guint8 flags = 0;
1170- err = err || network_mysqld_proto_get_int8(&packet, &flags);
1171- err = err || network_mysqld_proto_get_int8(&packet, (guint8 *)&field->decimals);
1172-
1173- if (!err) field->flags = flags;
1174- } else {
1175- /* well */
1176- }
1177-
1178- }
1179-
1180+ err = err || network_mysqld_proto_get_fielddef(&packet, field, capabilities);
1181+
1182 g_ptr_array_add(fields, field); /* even if we had an error, append it so that we can free it later */
1183
1184 if (err) return NULL;
1185@@ -1358,4 +1367,451 @@
1186 return dst;
1187 }
1188
1189+/*
1190+ * prepared statements
1191+ */
1192+
1193+/**
1194+ *
1195+ */
1196+network_mysqld_stmt_prepare_packet_t *network_mysqld_stmt_prepare_packet_new() {
1197+ network_mysqld_stmt_prepare_packet_t *stmt_prepare_packet;
1198+
1199+ stmt_prepare_packet = g_slice_new0(network_mysqld_stmt_prepare_packet_t);
1200+ stmt_prepare_packet->stmt_text = g_string_new(NULL);
1201+
1202+ return stmt_prepare_packet;
1203+}
1204+
1205+/**
1206+ *
1207+ */
1208+void network_mysqld_stmt_prepare_packet_free(network_mysqld_stmt_prepare_packet_t *stmt_prepare_packet) {
1209+ if (NULL == stmt_prepare_packet) return;
1210+
1211+ if (NULL != stmt_prepare_packet->stmt_text) g_string_free(stmt_prepare_packet->stmt_text, TRUE);
1212+
1213+ g_slice_free(network_mysqld_stmt_prepare_packet_t, stmt_prepare_packet);
1214+}
1215+
1216+/**
1217+ *
1218+ */
1219+int network_mysqld_proto_get_stmt_prepare_packet(network_packet *packet, network_mysqld_stmt_prepare_packet_t *stmt_prepare_packet) {
1220+ guint8 packet_type;
1221+
1222+ int err = 0;
1223+
1224+ err = err || network_mysqld_proto_get_int8(packet, &packet_type);
1225+ if (err) return -1;
1226+
1227+ if (COM_STMT_PREPARE != packet_type) {
1228+ g_critical("%s: expected the first byte to be %02x, got %02x",
1229+ G_STRLOC,
1230+ COM_STMT_PREPARE,
1231+ packet_type);
1232+ return -1;
1233+ }
1234+
1235+ g_string_assign_len(stmt_prepare_packet->stmt_text, packet->data->str + packet->offset, packet->data->len - packet->offset);
1236+
1237+ return err ? -1 : 0;
1238+}
1239+
1240+int network_mysqld_proto_append_stmt_prepare_packet(GString *packet, network_mysqld_stmt_prepare_packet_t *stmt_prepare_packet) {
1241+ network_mysqld_proto_append_int8(packet, COM_STMT_PREPARE);
1242+ g_string_append_len(packet, S(stmt_prepare_packet->stmt_text));
1243+
1244+ return 0;
1245+}
1246+
1247+/**
1248+ *
1249+ */
1250+network_mysqld_stmt_prepare_ok_packet_t *network_mysqld_stmt_prepare_ok_packet_new() {
1251+ network_mysqld_stmt_prepare_ok_packet_t *stmt_prepare_ok_packet;
1252+
1253+ stmt_prepare_ok_packet = g_slice_new0(network_mysqld_stmt_prepare_ok_packet_t);
1254+
1255+ return stmt_prepare_ok_packet;
1256+}
1257+
1258+/**
1259+ *
1260+ */
1261+void network_mysqld_stmt_prepare_ok_packet_free(network_mysqld_stmt_prepare_ok_packet_t *stmt_prepare_ok_packet) {
1262+ if (NULL == stmt_prepare_ok_packet) return;
1263+
1264+ g_slice_free(network_mysqld_stmt_prepare_ok_packet_t, stmt_prepare_ok_packet);
1265+}
1266+
1267+/**
1268+ * parse the first packet of the OK response for a COM_STMT_PREPARE
1269+ *
1270+ * it is followed by the field defs for the params and the columns and their EOF packets which is handled elsewhere
1271+ */
1272+int network_mysqld_proto_get_stmt_prepare_ok_packet(network_packet *packet, network_mysqld_stmt_prepare_ok_packet_t *stmt_prepare_ok_packet) {
1273+ guint8 packet_type;
1274+ guint16 num_columns;
1275+ guint16 num_params;
1276+ guint16 warnings;
1277+ guint32 stmt_id;
1278+
1279+ int err = 0;
1280+
1281+ err = err || network_mysqld_proto_get_int8(packet, &packet_type);
1282+ if (err) return -1;
1283+
1284+ if (0x00 != packet_type) {
1285+ g_critical("%s: expected the first byte to be %02x, got %02x",
1286+ G_STRLOC,
1287+ 0x00,
1288+ packet_type);
1289+ return -1;
1290+ }
1291+ err = err || network_mysqld_proto_get_int32(packet, &stmt_id);
1292+ err = err || network_mysqld_proto_get_int16(packet, &num_columns);
1293+ err = err || network_mysqld_proto_get_int16(packet, &num_params);
1294+ err = err || network_mysqld_proto_skip(packet, 1); /* the filler */
1295+ err = err || network_mysqld_proto_get_int16(packet, &warnings);
1296+
1297+ if (!err) {
1298+ stmt_prepare_ok_packet->stmt_id = stmt_id;
1299+ stmt_prepare_ok_packet->num_columns = num_columns;
1300+ stmt_prepare_ok_packet->num_params = num_params;
1301+ stmt_prepare_ok_packet->warnings = warnings;
1302+ }
1303+
1304+ return err ? -1 : 0;
1305+}
1306+
1307+int network_mysqld_proto_append_stmt_prepare_ok_packet(GString *packet, network_mysqld_stmt_prepare_ok_packet_t *stmt_prepare_ok_packet) {
1308+ int err = 0;
1309+
1310+ err = err || network_mysqld_proto_append_int8(packet, MYSQLD_PACKET_OK);
1311+ err = err || network_mysqld_proto_append_int32(packet, stmt_prepare_ok_packet->stmt_id);
1312+ err = err || network_mysqld_proto_append_int16(packet, stmt_prepare_ok_packet->num_columns);
1313+ err = err || network_mysqld_proto_append_int16(packet, stmt_prepare_ok_packet->num_params);
1314+ err = err || network_mysqld_proto_append_int8(packet, 0x00);
1315+ err = err || network_mysqld_proto_append_int16(packet, stmt_prepare_ok_packet->warnings);
1316+
1317+ return err ? -1 : 0;
1318+}
1319+
1320+/**
1321+ * create a struct for a COM_STMT_EXECUTE packet
1322+ */
1323+network_mysqld_stmt_execute_packet_t *network_mysqld_stmt_execute_packet_new() {
1324+ network_mysqld_stmt_execute_packet_t *stmt_execute_packet;
1325+
1326+ stmt_execute_packet = g_slice_new0(network_mysqld_stmt_execute_packet_t);
1327+ stmt_execute_packet->params = g_ptr_array_new();
1328+
1329+ return stmt_execute_packet;
1330+}
1331+
1332+/**
1333+ * free a struct for a COM_STMT_EXECUTE packet
1334+ */
1335+void network_mysqld_stmt_execute_packet_free(network_mysqld_stmt_execute_packet_t *stmt_execute_packet) {
1336+ guint i;
1337+
1338+ if (NULL == stmt_execute_packet) return;
1339+
1340+ for (i = 0; i < stmt_execute_packet->params->len; i++) {
1341+ network_mysqld_type_t *param = g_ptr_array_index(stmt_execute_packet->params, i);
1342+
1343+ network_mysqld_type_free(param);
1344+ }
1345+
1346+ g_ptr_array_free(stmt_execute_packet->params, TRUE);
1347+
1348+ g_slice_free(network_mysqld_stmt_execute_packet_t, stmt_execute_packet);
1349+}
1350+
1351+/**
1352+ * get the statement-id from the COM_STMT_EXECUTE packet
1353+ *
1354+ * as network_mysqld_proto_get_stmt_execute_packet() needs the parameter count
1355+ * to calculate the number of null-bits, we need a way to look it up in a
1356+ * external store which is very likely indexed by the stmt-id
1357+ *
1358+ * @see network_mysqld_proto_get_stmt_execute_packet()
1359+ */
1360+int network_mysqld_proto_get_stmt_execute_packet_stmt_id(network_packet *packet,
1361+ guint32 *stmt_id) {
1362+ guint8 packet_type;
1363+ int err = 0;
1364+
1365+ err = err || network_mysqld_proto_get_int8(packet, &packet_type);
1366+ if (err) return -1;
1367+
1368+ if (COM_STMT_EXECUTE != packet_type) {
1369+ g_critical("%s: expected the first byte to be %02x, got %02x",
1370+ G_STRLOC,
1371+ COM_STMT_EXECUTE,
1372+ packet_type);
1373+ return -1;
1374+ }
1375+
1376+ err = err || network_mysqld_proto_get_int32(packet, stmt_id);
1377+
1378+ return err ? -1 : 0;
1379+}
1380+
1381+/**
1382+ *
1383+ * param_count has to be taken from the response of the prepare-stmt-ok packet
1384+ *
1385+ * @param param_count number of parameters that we expect to see here
1386+ */
1387+int network_mysqld_proto_get_stmt_execute_packet(network_packet *packet,
1388+ network_mysqld_stmt_execute_packet_t *stmt_execute_packet,
1389+ guint param_count) {
1390+ int err = 0;
1391+ GString *nul_bits;
1392+ gsize nul_bits_len;
1393+
1394+ err = err || network_mysqld_proto_get_stmt_execute_packet_stmt_id(packet, &stmt_execute_packet->stmt_id);
1395+ err = err || network_mysqld_proto_get_int8(packet, &stmt_execute_packet->flags);
1396+ err = err || network_mysqld_proto_get_int32(packet, &stmt_execute_packet->iteration_count);
1397+
1398+ if (0 == param_count) {
1399+ return err ? -1 : 0;
1400+ }
1401+
1402+ nul_bits_len = (param_count + 7) / 8;
1403+ nul_bits = g_string_sized_new(nul_bits_len);
1404+ err = err || network_mysqld_proto_get_gstring_len(packet, nul_bits_len, nul_bits);
1405+ err = err || network_mysqld_proto_get_int8(packet, &stmt_execute_packet->new_params_bound);
1406+
1407+ if (0 != err) {
1408+ g_string_free(nul_bits, TRUE);
1409+
1410+ return -1; /* exit early if something failed up to now */
1411+ }
1412+
1413+ if (stmt_execute_packet->new_params_bound) {
1414+ guint i;
1415+
1416+ for (i = 0; 0 == err && i < param_count; i++) {
1417+ guint16 param_type;
1418+
1419+ err = err || network_mysqld_proto_get_int16(packet, &param_type);
1420+
1421+ if (0 == err) {
1422+ network_mysqld_type_t *param;
1423+
1424+ param = network_mysqld_type_new(param_type & 0xff);
1425+ if (NULL == param) {
1426+ g_critical("%s: couldn't create type = %d", G_STRLOC, param_type & 0xff);
1427+
1428+ err = -1;
1429+ break;
1430+ }
1431+ param->is_null = (nul_bits->str[i / 8] & (1 << (i % 8))) != 0;
1432+ param->is_unsigned = (param_type & 0x8000) != 0;
1433+
1434+ g_ptr_array_add(stmt_execute_packet->params, param);
1435+ }
1436+ }
1437+
1438+ for (i = 0; 0 == err && i < param_count; i++) {
1439+ network_mysqld_type_t *param = g_ptr_array_index(stmt_execute_packet->params, i);
1440+
1441+ if (!param->is_null) {
1442+ err = err || network_mysqld_proto_binary_get_type(packet, param);
1443+ }
1444+ }
1445+ }
1446+
1447+ g_string_free(nul_bits, TRUE);
1448+
1449+ return err ? -1 : 0;
1450+}
1451+
1452+int network_mysqld_proto_append_stmt_execute_packet(GString *packet,
1453+ network_mysqld_stmt_execute_packet_t *stmt_execute_packet,
1454+ guint param_count) {
1455+ gsize nul_bits_len;
1456+ GString *nul_bits;
1457+ guint i;
1458+ int err = 0;
1459+
1460+ nul_bits_len = (param_count + 7) / 8;
1461+ nul_bits = g_string_sized_new(nul_bits_len);
1462+ memset(nul_bits->str, 0, nul_bits->len); /* set it all to zero */
1463+
1464+ for (i = 0; i < param_count; i++) {
1465+ network_mysqld_type_t *param = g_ptr_array_index(stmt_execute_packet->params, i);
1466+
1467+ if (param->is_null) {
1468+ nul_bits->str[i / 8] |= 1 << (i % 8);
1469+ }
1470+ }
1471+
1472+ network_mysqld_proto_append_int8(packet, COM_STMT_EXECUTE);
1473+ network_mysqld_proto_append_int32(packet, stmt_execute_packet->stmt_id);
1474+ network_mysqld_proto_append_int8(packet, stmt_execute_packet->flags);
1475+ network_mysqld_proto_append_int32(packet, stmt_execute_packet->iteration_count);
1476+ g_string_append_len(packet, S(nul_bits));
1477+ network_mysqld_proto_append_int8(packet, stmt_execute_packet->new_params_bound);
1478+
1479+ if (stmt_execute_packet->new_params_bound) {
1480+ for (i = 0; i < stmt_execute_packet->params->len; i++) {
1481+ network_mysqld_type_t *param = g_ptr_array_index(stmt_execute_packet->params, i);
1482+
1483+ network_mysqld_proto_append_int16(packet, (guint16)param->type);
1484+ }
1485+ for (i = 0; 0 == err && i < stmt_execute_packet->params->len; i++) {
1486+ network_mysqld_type_t *param = g_ptr_array_index(stmt_execute_packet->params, i);
1487+
1488+ if (!param->is_null) {
1489+ err = err || network_mysqld_proto_binary_append_type(packet, param);
1490+ }
1491+ }
1492+ }
1493+
1494+ return err ? -1 : 0;
1495+}
1496+
1497+/**
1498+ * create a struct for a COM_STMT_EXECUTE resultset row
1499+ */
1500+network_mysqld_resultset_row_t *network_mysqld_resultset_row_new() {
1501+ return g_ptr_array_new();
1502+}
1503+
1504+/**
1505+ * free a struct for a COM_STMT_EXECUTE resultset row
1506+ */
1507+void network_mysqld_resultset_row_free(network_mysqld_resultset_row_t *row) {
1508+ guint i;
1509+
1510+ if (NULL == row) return;
1511+
1512+ for (i = 0; i < row->len; i++) {
1513+ network_mysqld_type_t *field = g_ptr_array_index(row, i);
1514+
1515+ network_mysqld_type_free(field);
1516+ }
1517+
1518+ g_ptr_array_free(row, TRUE);
1519+}
1520+
1521+/**
1522+ * get the fields of a row that is in binary row format
1523+ */
1524+int network_mysqld_proto_get_binary_row(network_packet *packet, network_mysqld_proto_fielddefs_t *coldefs, network_mysqld_resultset_row_t *row) {
1525+ int err = 0;
1526+ guint i;
1527+ guint nul_bytes_len;
1528+ GString *nul_bytes;
1529+
1530+ err = err || network_mysqld_proto_skip(packet, 1); /* the packet header which seems to be always 0 */
1531+
1532+ nul_bytes_len = (coldefs->len + 7 + 2) / 8; /* the first 2 bits are reserved */
1533+ nul_bytes = g_string_sized_new(nul_bytes_len);
1534+ err = err || network_mysqld_proto_get_gstring_len(packet, nul_bytes_len, nul_bytes);
1535+
1536+ for (i = 0; 0 == err && i < coldefs->len; i++) {
1537+ network_mysqld_type_t *param;
1538+ network_mysqld_proto_fielddef_t *coldef = g_ptr_array_index(coldefs, i);
1539+
1540+ param = network_mysqld_type_new(coldef->type);
1541+ if (NULL == param) {
1542+ g_critical("%s: coulnd't create type = %d", G_STRLOC, coldef->type);
1543+
1544+ err = -1;
1545+ break;
1546+ }
1547+
1548+ if (nul_bytes->str[(i + 2) / 8] & (1 << ((i + 2) % 8))) {
1549+ param->is_null = TRUE;
1550+ } else {
1551+ err = err || network_mysqld_proto_binary_get_type(packet, param);
1552+ }
1553+
1554+ g_ptr_array_add(row, param);
1555+ }
1556+
1557+ g_string_free(nul_bytes, TRUE);
1558+
1559+ return err ? -1 : 0;
1560+}
1561+
1562+/**
1563+ */
1564+GList *network_mysqld_proto_get_next_binary_row(GList *chunk, network_mysqld_proto_fielddefs_t *fields, network_mysqld_resultset_row_t *row) {
1565+ network_packet packet;
1566+ int err = 0;
1567+ network_mysqld_lenenc_type lenenc_type;
1568+
1569+ packet.data = chunk->data;
1570+ packet.offset = 0;
1571+
1572+ err = err || network_mysqld_proto_skip_network_header(&packet);
1573+
1574+ err = err || network_mysqld_proto_peek_lenenc_type(&packet, &lenenc_type);
1575+ if (0 != err) return NULL;
1576+
1577+ if (NETWORK_MYSQLD_LENENC_TYPE_EOF == lenenc_type) {
1578+ /* this is a EOF packet, we are done */
1579+ return NULL;
1580+ }
1581+
1582+ err = err || network_mysqld_proto_get_binary_row(&packet, fields, row);
1583+
1584+ return err ? NULL : chunk->next;
1585+}
1586+
1587+/**
1588+ * create a struct for a COM_STMT_CLOSE packet
1589+ */
1590+network_mysqld_stmt_close_packet_t *network_mysqld_stmt_close_packet_new() {
1591+ network_mysqld_stmt_close_packet_t *stmt_close_packet;
1592+
1593+ stmt_close_packet = g_slice_new0(network_mysqld_stmt_close_packet_t);
1594+
1595+ return stmt_close_packet;
1596+}
1597+
1598+/**
1599+ * free a struct for a COM_STMT_CLOSE packet
1600+ */
1601+void network_mysqld_stmt_close_packet_free(network_mysqld_stmt_close_packet_t *stmt_close_packet) {
1602+ if (NULL == stmt_close_packet) return;
1603+
1604+ g_slice_free(network_mysqld_stmt_close_packet_t, stmt_close_packet);
1605+}
1606+
1607+/**
1608+ */
1609+int network_mysqld_proto_get_stmt_close_packet(network_packet *packet, network_mysqld_stmt_close_packet_t *stmt_close_packet) {
1610+ guint8 packet_type;
1611+ int err = 0;
1612+
1613+ err = err || network_mysqld_proto_get_int8(packet, &packet_type);
1614+ if (err) return -1;
1615+
1616+ if (COM_STMT_CLOSE != packet_type) {
1617+ g_critical("%s: expected the first byte to be %02x, got %02x",
1618+ G_STRLOC,
1619+ COM_STMT_CLOSE,
1620+ packet_type);
1621+ return -1;
1622+ }
1623+
1624+ err = err || network_mysqld_proto_get_int32(packet, &stmt_close_packet->stmt_id);
1625+
1626+ return err ? -1 : 0;
1627+}
1628+
1629+int network_mysqld_proto_append_stmt_close_packet(GString *packet, network_mysqld_stmt_close_packet_t *stmt_close_packet) {
1630+ network_mysqld_proto_append_int8(packet, COM_STMT_CLOSE);
1631+ network_mysqld_proto_append_int32(packet, stmt_close_packet->stmt_id);
1632+
1633+ return 0;
1634+}
1635+
1636
1637
1638=== modified file 'src/network-mysqld-packet.h'
1639--- src/network-mysqld-packet.h 2010-05-10 10:31:45 +0000
1640+++ src/network-mysqld-packet.h 2010-09-22 15:13:16 +0000
1641@@ -185,4 +185,58 @@
1642 NETWORK_API int network_mysqld_proto_get_auth_response(network_packet *packet, network_mysqld_auth_response *auth);
1643 NETWORK_API network_mysqld_auth_response *network_mysqld_auth_response_copy(network_mysqld_auth_response *src);
1644
1645+/* COM_STMT_* */
1646+
1647+typedef struct {
1648+ GString *stmt_text;
1649+} network_mysqld_stmt_prepare_packet_t;
1650+
1651+NETWORK_API network_mysqld_stmt_prepare_packet_t *network_mysqld_stmt_prepare_packet_new();
1652+NETWORK_API void network_mysqld_stmt_prepare_packet_free(network_mysqld_stmt_prepare_packet_t *stmt_prepare_packet);
1653+NETWORK_API int network_mysqld_proto_get_stmt_prepare_packet(network_packet *packet, network_mysqld_stmt_prepare_packet_t *stmt_prepare_packet);
1654+NETWORK_API int network_mysqld_proto_append_stmt_prepare_packet(GString *packet, network_mysqld_stmt_prepare_packet_t *stmt_prepare_packet);
1655+
1656+typedef struct {
1657+ guint32 stmt_id;
1658+ guint16 num_columns;
1659+ guint16 num_params;
1660+ guint16 warnings;
1661+} network_mysqld_stmt_prepare_ok_packet_t;
1662+
1663+NETWORK_API network_mysqld_stmt_prepare_ok_packet_t *network_mysqld_stmt_prepare_ok_packet_new(void);
1664+NETWORK_API void network_mysqld_stmt_prepare_ok_packet_free(network_mysqld_stmt_prepare_ok_packet_t *stmt_prepare_ok_packet);
1665+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);
1666+NETWORK_API int network_mysqld_proto_append_stmt_prepare_ok_packet(GString *packet, network_mysqld_stmt_prepare_ok_packet_t *stmt_prepare_ok_packet);
1667+
1668+typedef struct {
1669+ guint32 stmt_id;
1670+ guint8 flags;
1671+ guint32 iteration_count;
1672+ guint8 new_params_bound;
1673+ GPtrArray *params; /**< array<network_mysqld_type *> */
1674+} network_mysqld_stmt_execute_packet_t;
1675+
1676+NETWORK_API network_mysqld_stmt_execute_packet_t *network_mysqld_stmt_execute_packet_new(void);
1677+NETWORK_API void network_mysqld_stmt_execute_packet_free(network_mysqld_stmt_execute_packet_t *stmt_execute_packet);
1678+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);
1679+NETWORK_API int network_mysqld_proto_append_stmt_execute_packet(GString *packet, network_mysqld_stmt_execute_packet_t *stmt_execute_packet, guint param_count);
1680+NETWORK_API int network_mysqld_proto_get_stmt_execute_packet_stmt_id(network_packet *packet, guint32 *stmt_id);
1681+
1682+
1683+typedef GPtrArray network_mysqld_resultset_row_t;
1684+
1685+NETWORK_API network_mysqld_resultset_row_t *network_mysqld_resultset_row_new(void);
1686+NETWORK_API void network_mysqld_resultset_row_free(network_mysqld_resultset_row_t *row);
1687+NETWORK_API int network_mysqld_proto_get_binary_row(network_packet *packet, network_mysqld_proto_fielddefs_t *fields, network_mysqld_resultset_row_t *row);
1688+NETWORK_API GList *network_mysqld_proto_get_next_binary_row(GList *chunk, network_mysqld_proto_fielddefs_t *fields, network_mysqld_resultset_row_t *row);
1689+
1690+typedef struct {
1691+ guint32 stmt_id;
1692+} network_mysqld_stmt_close_packet_t;
1693+
1694+NETWORK_API network_mysqld_stmt_close_packet_t *network_mysqld_stmt_close_packet_new(void);
1695+NETWORK_API void network_mysqld_stmt_close_packet_free(network_mysqld_stmt_close_packet_t *stmt_close_packet);
1696+NETWORK_API int network_mysqld_proto_get_stmt_close_packet(network_packet *packet, network_mysqld_stmt_close_packet_t *stmt_close_packet);
1697+NETWORK_API int network_mysqld_proto_append_stmt_close_packet(GString *packet, network_mysqld_stmt_close_packet_t *stmt_close_packet);
1698+
1699 #endif
1700
1701=== modified file 'src/network-mysqld-proto.h'
1702--- src/network-mysqld-proto.h 2010-04-06 14:26:51 +0000
1703+++ src/network-mysqld-proto.h 2010-09-22 15:13:16 +0000
1704@@ -111,11 +111,14 @@
1705 NETWORK_API int network_mysqld_proto_peek_lenenc_type(network_packet *packet, network_mysqld_lenenc_type *type);
1706 NETWORK_API int network_mysqld_proto_get_lenenc_int(network_packet *packet, guint64 *v);
1707
1708-NETWORK_API MYSQL_FIELD *network_mysqld_proto_fielddef_new(void);
1709-NETWORK_API void network_mysqld_proto_fielddef_free(MYSQL_FIELD *fielddef);
1710+typedef MYSQL_FIELD network_mysqld_proto_fielddef_t;
1711+NETWORK_API network_mysqld_proto_fielddef_t *network_mysqld_proto_fielddef_new(void);
1712+NETWORK_API void network_mysqld_proto_fielddef_free(network_mysqld_proto_fielddef_t *fielddef);
1713+NETWORK_API int network_mysqld_proto_get_fielddef(network_packet *packet, network_mysqld_proto_fielddef_t *field, guint32 capabilities);
1714
1715-NETWORK_API GPtrArray *network_mysqld_proto_fielddefs_new(void);
1716-NETWORK_API void network_mysqld_proto_fielddefs_free(GPtrArray *fielddefs);
1717+typedef GPtrArray network_mysqld_proto_fielddefs_t;
1718+NETWORK_API network_mysqld_proto_fielddefs_t *network_mysqld_proto_fielddefs_new(void);
1719+NETWORK_API void network_mysqld_proto_fielddefs_free(network_mysqld_proto_fielddefs_t *fielddefs);
1720
1721 NETWORK_API guint32 network_mysqld_proto_get_packet_len(GString *_header);
1722 NETWORK_API guint8 network_mysqld_proto_get_packet_id(GString *_header);
1723
1724=== added file 'src/network_mysqld_proto_binary.c'
1725--- src/network_mysqld_proto_binary.c 1970-01-01 00:00:00 +0000
1726+++ src/network_mysqld_proto_binary.c 2010-09-22 15:13:16 +0000
1727@@ -0,0 +1,441 @@
1728+/* $%BEGINLICENSE%$
1729+ Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
1730+
1731+ This program is free software; you can redistribute it and/or
1732+ modify it under the terms of the GNU General Public License as
1733+ published by the Free Software Foundation; version 2 of the
1734+ License.
1735+
1736+ This program is distributed in the hope that it will be useful,
1737+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1738+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1739+ GNU General Public License for more details.
1740+
1741+ You should have received a copy of the GNU General Public License
1742+ along with this program; if not, write to the Free Software
1743+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
1744+ 02110-1301 USA
1745+
1746+ $%ENDLICENSE%$ */
1747+
1748+/**
1749+ * codec's for the binary MySQL client protocol
1750+ */
1751+
1752+#include <stdlib.h>
1753+#include <stdio.h>
1754+#include <string.h>
1755+
1756+#include "network_mysqld_proto_binary.h"
1757+
1758+#include "glib-ext.h"
1759+#include "string-len.h"
1760+
1761+/* ints */
1762+static int network_mysqld_proto_binary_get_int_type(network_packet *packet, network_mysqld_type_t *type) {
1763+ int err = 0;
1764+ guint8 i8;
1765+ guint16 i16;
1766+ guint32 i32;
1767+ guint64 i64;
1768+
1769+ switch (type->type) {
1770+ case MYSQL_TYPE_TINY:
1771+ err = err || network_mysqld_proto_get_int8(packet, &i8);
1772+ err = err || network_mysqld_type_set_int(type, (guint64)i8, type->is_unsigned);
1773+ break;
1774+ case MYSQL_TYPE_SHORT:
1775+ err = err || network_mysqld_proto_get_int16(packet, &i16);
1776+ err = err || network_mysqld_type_set_int(type, (guint64)i16, type->is_unsigned);
1777+ break;
1778+ case MYSQL_TYPE_LONG:
1779+ case MYSQL_TYPE_INT24:
1780+ err = err || network_mysqld_proto_get_int32(packet, &i32);
1781+ err = err || network_mysqld_type_set_int(type, (guint64)i32, type->is_unsigned);
1782+ break;
1783+ case MYSQL_TYPE_LONGLONG:
1784+ err = err || network_mysqld_proto_get_int64(packet, &i64);
1785+ err = err || network_mysqld_type_set_int(type, i64, type->is_unsigned);
1786+ break;
1787+ default:
1788+ err = -1;
1789+ break;
1790+ }
1791+
1792+ return err ? -1 : 0;
1793+}
1794+
1795+static int network_mysqld_proto_binary_append_int_type(GString *packet, network_mysqld_type_t *type) {
1796+ guint64 i64;
1797+ guint8 i8;
1798+ guint16 i16;
1799+ guint32 i32;
1800+ int err = 0;
1801+
1802+ err = err || network_mysqld_type_get_int(type, &i64, NULL);
1803+ if (0 != err) return -1;
1804+
1805+ switch (type->type) {
1806+ case MYSQL_TYPE_TINY:
1807+
1808+ i8 = i64;
1809+
1810+ err = err || network_mysqld_proto_append_int8(packet, i8);
1811+ break;
1812+ case MYSQL_TYPE_SHORT:
1813+ i16 = i64;
1814+
1815+ err = err || network_mysqld_proto_append_int16(packet, i16);
1816+ break;
1817+ case MYSQL_TYPE_LONG:
1818+ case MYSQL_TYPE_INT24:
1819+ i32 = i64;
1820+
1821+ err = err || network_mysqld_proto_append_int32(packet, i32);
1822+ break;
1823+ case MYSQL_TYPE_LONGLONG:
1824+ err = err || network_mysqld_proto_append_int64(packet, i64);
1825+ break;
1826+ default:
1827+ err = -1;
1828+ break;
1829+ }
1830+
1831+ return err ? -1 : 0;
1832+}
1833+
1834+/* double */
1835+static int network_mysqld_proto_binary_get_double_type(network_packet *packet, network_mysqld_type_t *type) {
1836+ int err = 0;
1837+ union {
1838+ double d;
1839+ char d_char_shadow[sizeof(double) + 1];
1840+ } double_copy;
1841+
1842+ GString s;
1843+ s.str = double_copy.d_char_shadow;
1844+ s.len = 0;
1845+ s.allocated_len = sizeof(double_copy.d_char_shadow);
1846+
1847+ err = err || network_mysqld_proto_get_gstring_len(packet, sizeof(double), &s);
1848+
1849+ if (0 == err) {
1850+ err = err || network_mysqld_type_set_double(type, double_copy.d);
1851+ }
1852+
1853+ return err ? -1 : 0;
1854+}
1855+
1856+static int network_mysqld_proto_binary_append_double_type(GString *packet, network_mysqld_type_t *type) {
1857+ union {
1858+ double d;
1859+ char d_char_shadow[sizeof(double)];
1860+ } double_copy;
1861+ int err = 0;
1862+
1863+ err = err || network_mysqld_type_get_double(type, &double_copy.d);
1864+
1865+ g_string_append_len(packet, double_copy.d_char_shadow, sizeof(double));
1866+
1867+ return err ? -1 : 0;
1868+}
1869+
1870+/* float */
1871+static int network_mysqld_proto_binary_get_float_type(network_packet *packet, network_mysqld_type_t *type) {
1872+ int err = 0;
1873+ union {
1874+ float d;
1875+ char d_char_shadow[sizeof(float) + 1];
1876+ } float_copy;
1877+
1878+ GString s;
1879+ s.str = float_copy.d_char_shadow;
1880+ s.len = 0;
1881+ s.allocated_len = sizeof(float_copy.d_char_shadow);
1882+
1883+ err = err || network_mysqld_proto_get_gstring_len(packet, sizeof(float), &s);
1884+
1885+ if (0 == err) {
1886+ err = err || network_mysqld_type_set_double(type, (double)float_copy.d);
1887+ }
1888+
1889+ return err ? -1 : 0;
1890+}
1891+
1892+static int network_mysqld_proto_binary_append_float_type(GString *packet, network_mysqld_type_t *type) {
1893+ double d;
1894+ int err = 0;
1895+
1896+ err = err || network_mysqld_type_get_double(type, &d); /* get our float as double */
1897+
1898+ if (0 == err) {
1899+ /* copy the float directly without switching byte-order */
1900+ union {
1901+ float f;
1902+ char f_char_shadow[sizeof(float)];
1903+ } float_copy; /* shadow the float with a equally sized char to be able to copy it without extra type-casting */
1904+
1905+ float_copy.f = (float)d;
1906+
1907+ g_string_append_len(packet, float_copy.f_char_shadow, sizeof(float));
1908+ }
1909+
1910+ return err ? -1 : 0;
1911+}
1912+
1913+/* all kinds of strings */
1914+static int network_mysqld_proto_binary_get_string_type(network_packet *packet, network_mysqld_type_t *type) {
1915+ GString *str;
1916+ int err = 0;
1917+
1918+ str = g_string_new(NULL);
1919+
1920+ err = err || network_mysqld_proto_get_lenenc_gstring(packet, str);
1921+
1922+ network_mysqld_type_set_string(type, S(str));
1923+
1924+ g_string_free(str, TRUE);
1925+
1926+ return err ? -1 : 0;
1927+}
1928+
1929+static int network_mysqld_proto_binary_append_string_type(GString *packet, network_mysqld_type_t *type) {
1930+ const char *s;
1931+ gsize s_len;
1932+ int err = 0;
1933+
1934+ err = err || network_mysqld_type_get_string_const(type, &s, &s_len);
1935+ err = err || network_mysqld_proto_append_lenenc_string_len(packet, s, s_len);
1936+
1937+ return err ? -1 : 0;
1938+}
1939+
1940+/* all kinds of time */
1941+
1942+/**
1943+ * extract the date from a binary resultset row
1944+ */
1945+static int network_mysqld_proto_binary_get_date_type(network_packet *packet, network_mysqld_type_t *type) {
1946+ int err = 0;
1947+ guint8 len;
1948+ network_mysqld_type_date_t date;
1949+
1950+ err = err || network_mysqld_proto_get_int8(packet, &len);
1951+
1952+ /* check the valid lengths
1953+ */
1954+ switch (len) {
1955+ case 11: /* date + time + ms */
1956+ case 7: /* date + time ( ms is .0000 ) */
1957+ case 4: /* date ( time is 00:00:00 )*/
1958+ case 0: /* date == 0000-00-00 */
1959+ break;
1960+ default:
1961+ return -1;
1962+ }
1963+
1964+ memset(&date, 0, sizeof(date));
1965+ if (len > 0) {
1966+ err = err || network_mysqld_proto_get_int16(packet, &date.year);
1967+ err = err || network_mysqld_proto_get_int8(packet, &date.month);
1968+ err = err || network_mysqld_proto_get_int8(packet, &date.day);
1969+
1970+ if (len > 4) {
1971+ err = err || network_mysqld_proto_get_int8(packet, &date.hour);
1972+ err = err || network_mysqld_proto_get_int8(packet, &date.min);
1973+ err = err || network_mysqld_proto_get_int8(packet, &date.sec);
1974+
1975+ if (len > 7) {
1976+ err = err || network_mysqld_proto_get_int32(packet, &date.nsec);
1977+ }
1978+ }
1979+ }
1980+
1981+ if (0 == err) {
1982+ err = err || network_mysqld_type_set_date(type, &date);
1983+ }
1984+
1985+ return err ? -1 : 0;
1986+}
1987+
1988+static int network_mysqld_proto_binary_append_date_type(GString G_GNUC_UNUSED *packet, network_mysqld_type_t G_GNUC_UNUSED *type) {
1989+ /* not implemented yet */
1990+ return -1;
1991+}
1992+
1993+/**
1994+ * extract the time from a binary resultset row
1995+ */
1996+static int network_mysqld_proto_binary_get_time_type(network_packet *packet, network_mysqld_type_t *type) {
1997+ int err = 0;
1998+ guint8 len;
1999+ network_mysqld_type_time_t t;
2000+
2001+ err = err || network_mysqld_proto_get_int8(packet, &len);
2002+
2003+ /* check the valid lengths
2004+ */
2005+ switch (len) {
2006+ case 12: /* day + time + ms */
2007+ case 8: /* day + time ( ms is .0000 ) */
2008+ case 0: /* time == 00:00:00 */
2009+ break;
2010+ default:
2011+ return -1;
2012+ }
2013+
2014+ memset(&t, 0, sizeof(t));
2015+ if (len > 0) {
2016+ err = err || network_mysqld_proto_get_int8(packet, &t.sign);
2017+ err = err || network_mysqld_proto_get_int32(packet, &t.days);
2018+
2019+ err = err || network_mysqld_proto_get_int8(packet, &t.hour);
2020+ err = err || network_mysqld_proto_get_int8(packet, &t.min);
2021+ err = err || network_mysqld_proto_get_int8(packet, &t.sec);
2022+
2023+ if (len > 8) {
2024+ err = err || network_mysqld_proto_get_int32(packet, &t.nsec);
2025+ }
2026+ }
2027+
2028+ if (0 == err) {
2029+ err = err || network_mysqld_type_set_time(type, &t);
2030+ }
2031+
2032+ return err ? -1 : 0;
2033+}
2034+
2035+static int network_mysqld_proto_binary_append_time_type(GString G_GNUC_UNUSED *packet, network_mysqld_type_t G_GNUC_UNUSED *type) {
2036+ /* not implemented yet */
2037+ return -1;
2038+}
2039+
2040+/**
2041+ * valid types for prepared statements parameters we receive from the client
2042+ */
2043+gboolean network_mysql_proto_binary_type_is_valid_input(enum enum_field_types field_type) {
2044+ switch (field_type) {
2045+ case MYSQL_TYPE_TINY:
2046+ case MYSQL_TYPE_SHORT:
2047+ case MYSQL_TYPE_LONG:
2048+ case MYSQL_TYPE_LONGLONG:
2049+
2050+ case MYSQL_TYPE_FLOAT:
2051+ case MYSQL_TYPE_DOUBLE:
2052+
2053+ case MYSQL_TYPE_BLOB:
2054+ case MYSQL_TYPE_STRING:
2055+
2056+ case MYSQL_TYPE_DATE:
2057+ case MYSQL_TYPE_DATETIME:
2058+ case MYSQL_TYPE_TIME:
2059+ case MYSQL_TYPE_TIMESTAMP:
2060+
2061+ case MYSQL_TYPE_NULL:
2062+ return TRUE;
2063+ default:
2064+ return FALSE;
2065+ }
2066+}
2067+
2068+/**
2069+ * types we allow the send back to the client
2070+ */
2071+gboolean network_mysql_proto_binary_is_valid_output(enum enum_field_types field_type) {
2072+ switch (field_type) {
2073+ case MYSQL_TYPE_TINY:
2074+ case MYSQL_TYPE_SHORT:
2075+ case MYSQL_TYPE_INT24:
2076+ case MYSQL_TYPE_LONG:
2077+ case MYSQL_TYPE_LONGLONG:
2078+
2079+ case MYSQL_TYPE_FLOAT:
2080+ case MYSQL_TYPE_DOUBLE:
2081+ case MYSQL_TYPE_NEWDECIMAL:
2082+
2083+ case MYSQL_TYPE_TINY_BLOB:
2084+ case MYSQL_TYPE_BLOB:
2085+ case MYSQL_TYPE_MEDIUM_BLOB:
2086+ case MYSQL_TYPE_LONG_BLOB:
2087+ case MYSQL_TYPE_STRING:
2088+ case MYSQL_TYPE_VAR_STRING:
2089+
2090+ case MYSQL_TYPE_DATE:
2091+ case MYSQL_TYPE_DATETIME:
2092+ case MYSQL_TYPE_TIME:
2093+ case MYSQL_TYPE_TIMESTAMP:
2094+
2095+ case MYSQL_TYPE_BIT:
2096+ return TRUE;
2097+ default:
2098+ return FALSE;
2099+ }
2100+}
2101+
2102+int network_mysqld_proto_binary_get_type(network_packet *packet, network_mysqld_type_t *type) {
2103+ switch (type->type) {
2104+ case MYSQL_TYPE_TINY:
2105+ case MYSQL_TYPE_SHORT:
2106+ case MYSQL_TYPE_LONG:
2107+ case MYSQL_TYPE_INT24:
2108+ case MYSQL_TYPE_LONGLONG:
2109+ return network_mysqld_proto_binary_get_int_type(packet, type);
2110+ case MYSQL_TYPE_DATE:
2111+ case MYSQL_TYPE_DATETIME:
2112+ case MYSQL_TYPE_TIMESTAMP:
2113+ return network_mysqld_proto_binary_get_date_type(packet, type);
2114+ case MYSQL_TYPE_TIME:
2115+ return network_mysqld_proto_binary_get_time_type(packet, type);
2116+ case MYSQL_TYPE_FLOAT:
2117+ return network_mysqld_proto_binary_get_float_type(packet, type);
2118+ case MYSQL_TYPE_DOUBLE:
2119+ return network_mysqld_proto_binary_get_double_type(packet, type);
2120+ case MYSQL_TYPE_BIT:
2121+ case MYSQL_TYPE_NEWDECIMAL:
2122+ case MYSQL_TYPE_BLOB:
2123+ case MYSQL_TYPE_TINY_BLOB:
2124+ case MYSQL_TYPE_MEDIUM_BLOB:
2125+ case MYSQL_TYPE_LONG_BLOB:
2126+ case MYSQL_TYPE_STRING:
2127+ case MYSQL_TYPE_VAR_STRING:
2128+ /* they are all length-encoded strings */
2129+ return network_mysqld_proto_binary_get_string_type(packet, type);
2130+ }
2131+
2132+ return -1;
2133+}
2134+
2135+int network_mysqld_proto_binary_append_type(GString *packet, network_mysqld_type_t *type) {
2136+ switch (type->type) {
2137+ case MYSQL_TYPE_TINY:
2138+ case MYSQL_TYPE_SHORT:
2139+ case MYSQL_TYPE_LONG:
2140+ case MYSQL_TYPE_INT24:
2141+ case MYSQL_TYPE_LONGLONG:
2142+ return network_mysqld_proto_binary_append_int_type(packet, type);
2143+ case MYSQL_TYPE_DATE:
2144+ case MYSQL_TYPE_DATETIME:
2145+ case MYSQL_TYPE_TIMESTAMP:
2146+ return network_mysqld_proto_binary_append_date_type(packet, type);
2147+ case MYSQL_TYPE_TIME:
2148+ return network_mysqld_proto_binary_append_time_type(packet, type);
2149+ case MYSQL_TYPE_FLOAT:
2150+ return network_mysqld_proto_binary_append_float_type(packet, type);
2151+ case MYSQL_TYPE_DOUBLE:
2152+ return network_mysqld_proto_binary_append_double_type(packet, type);
2153+ case MYSQL_TYPE_BIT:
2154+ case MYSQL_TYPE_NEWDECIMAL:
2155+ case MYSQL_TYPE_BLOB:
2156+ case MYSQL_TYPE_TINY_BLOB:
2157+ case MYSQL_TYPE_MEDIUM_BLOB:
2158+ case MYSQL_TYPE_LONG_BLOB:
2159+ case MYSQL_TYPE_STRING:
2160+ case MYSQL_TYPE_VAR_STRING:
2161+ /* they are all length-encoded strings */
2162+ return network_mysqld_proto_binary_append_string_type(packet, type);
2163+ }
2164+
2165+ return -1;
2166+}
2167+
2168+
2169
2170=== added file 'src/network_mysqld_proto_binary.h'
2171--- src/network_mysqld_proto_binary.h 1970-01-01 00:00:00 +0000
2172+++ src/network_mysqld_proto_binary.h 2010-09-22 15:13:16 +0000
2173@@ -0,0 +1,12 @@
2174+#ifndef __NETWORK_MYSQLD_PROTO_BINARY_H__
2175+#define __NETWORK_MYSQLD_PROTO_BINARY_H__
2176+
2177+#include <glib.h>
2178+
2179+#include "network-socket.h"
2180+#include "network_mysqld_type.h"
2181+
2182+int network_mysqld_proto_binary_get_type(network_packet *packet, network_mysqld_type_t *type);
2183+int network_mysqld_proto_binary_append_type(GString *packet, network_mysqld_type_t *type);
2184+
2185+#endif
2186
2187=== added file 'src/network_mysqld_type.c'
2188--- src/network_mysqld_type.c 1970-01-01 00:00:00 +0000
2189+++ src/network_mysqld_type.c 2010-09-22 15:13:16 +0000
2190@@ -0,0 +1,656 @@
2191+#include <string.h>
2192+#include <stdlib.h>
2193+#include <stdio.h>
2194+
2195+#include <glib.h>
2196+
2197+#include "network_mysqld_type.h"
2198+#include "string-len.h"
2199+
2200+#include "glib-ext.h"
2201+
2202+/* expose the types itself and their internal representation */
2203+
2204+typedef double network_mysqld_type_double_t;
2205+
2206+typedef float network_mysqld_type_float_t;
2207+
2208+typedef GString network_mysqld_type_string_t;
2209+
2210+typedef struct {
2211+ guint64 i;
2212+ gboolean is_unsigned;
2213+} network_mysqld_type_int_t;
2214+
2215+/**
2216+ * create a type that can hold a MYSQL_TYPE_LONGLONG
2217+ */
2218+static network_mysqld_type_int_t *network_mysqld_type_int_new(void) {
2219+ network_mysqld_type_int_t *ll;
2220+
2221+ ll = g_slice_new0(network_mysqld_type_int_t);
2222+
2223+ return ll;
2224+}
2225+
2226+/**
2227+ * free a network_mysqld_type_int_t
2228+ */
2229+static void network_mysqld_type_int_free(network_mysqld_type_int_t *ll) {
2230+ if (NULL == ll) return;
2231+
2232+ g_slice_free(network_mysqld_type_int_t, ll);
2233+}
2234+
2235+static int network_mysqld_type_data_int_get_int(network_mysqld_type_t *type, guint64 *i, gboolean *is_unsigned) {
2236+ network_mysqld_type_int_t *value;
2237+
2238+ if (NULL == type->data) return -1;
2239+
2240+ value = type->data;
2241+
2242+ *i = value->i;
2243+ *is_unsigned = value->is_unsigned;
2244+
2245+ return 0;
2246+}
2247+
2248+static int network_mysqld_type_data_int_set_int(network_mysqld_type_t *type, guint64 i, gboolean is_unsigned) {
2249+ network_mysqld_type_int_t *value;
2250+
2251+ if (NULL == type->data) {
2252+ type->data = network_mysqld_type_int_new();
2253+ }
2254+ value = type->data;
2255+
2256+ value->i = i;
2257+ value->is_unsigned = is_unsigned;
2258+
2259+ return 0;
2260+}
2261+
2262+
2263+/**
2264+ * typesafe wrapper for network_mysqld_type_new()
2265+ */
2266+static void network_mysqld_type_data_int_free(network_mysqld_type_t *type) {
2267+ if (NULL == type) return;
2268+ if (NULL == type->data) return;
2269+
2270+ network_mysqld_type_int_free(type->data);
2271+}
2272+
2273+static void network_mysqld_type_data_int_init(network_mysqld_type_t *type, enum enum_field_types field_type) {
2274+ type->type = field_type;
2275+ type->free_data = network_mysqld_type_data_int_free;
2276+ type->get_int = network_mysqld_type_data_int_get_int;
2277+ type->set_int = network_mysqld_type_data_int_set_int;
2278+}
2279+
2280+/* MYSQL_TYPE_DOUBLE */
2281+
2282+/**
2283+ * create a type that can hold a MYSQL_TYPE_DOUBLE
2284+ */
2285+static network_mysqld_type_double_t *network_mysqld_type_double_new(void) {
2286+ network_mysqld_type_double_t *t;
2287+
2288+ t = g_slice_new0(network_mysqld_type_double_t);
2289+
2290+ return t;
2291+}
2292+
2293+/**
2294+ * free a network_mysqld_type_double_t
2295+ */
2296+static void network_mysqld_type_double_free(network_mysqld_type_double_t *t) {
2297+ if (NULL == t) return;
2298+
2299+ g_slice_free(network_mysqld_type_double_t, t);
2300+}
2301+
2302+static void network_mysqld_type_data_double_free(network_mysqld_type_t *type) {
2303+ if (NULL == type) return;
2304+ if (NULL == type->data) return;
2305+
2306+ network_mysqld_type_double_free(type->data);
2307+}
2308+
2309+static int network_mysqld_type_data_double_get_double(network_mysqld_type_t *type, double *d) {
2310+ network_mysqld_type_double_t *value = type->data;
2311+
2312+ if (NULL == value) return -1;
2313+
2314+ *d = *value;
2315+
2316+ return 0;
2317+}
2318+
2319+static int network_mysqld_type_data_double_set_double(network_mysqld_type_t *type, double d) {
2320+ network_mysqld_type_double_t *value;
2321+
2322+ if (NULL == type->data) {
2323+ type->data = network_mysqld_type_double_new();
2324+ }
2325+
2326+ value = type->data;
2327+ *value = d;
2328+
2329+ return 0;
2330+}
2331+
2332+static void network_mysqld_type_data_double_init(network_mysqld_type_t *type, enum enum_field_types field_type) {
2333+ type->type = field_type;
2334+ type->free_data = network_mysqld_type_data_double_free;
2335+ type->get_double = network_mysqld_type_data_double_get_double;
2336+ type->set_double = network_mysqld_type_data_double_set_double;
2337+}
2338+
2339+/* MYSQL_TYPE_FLOAT */
2340+
2341+/**
2342+ * create a type that can hold a MYSQL_TYPE_FLOAT
2343+ */
2344+
2345+static network_mysqld_type_float_t *network_mysqld_type_float_new(void) {
2346+ network_mysqld_type_float_t *t;
2347+
2348+ t = g_slice_new0(network_mysqld_type_float_t);
2349+
2350+ return t;
2351+}
2352+
2353+/**
2354+ * free a network_mysqld_type_float_t
2355+ */
2356+static void network_mysqld_type_float_free(network_mysqld_type_float_t *t) {
2357+ if (NULL == t) return;
2358+
2359+ g_slice_free(network_mysqld_type_float_t, t);
2360+}
2361+
2362+static void network_mysqld_type_data_float_free(network_mysqld_type_t *type) {
2363+ if (NULL == type) return;
2364+ if (NULL == type->data) return;
2365+
2366+ network_mysqld_type_float_free(type->data);
2367+}
2368+
2369+static int network_mysqld_type_data_float_get_double(network_mysqld_type_t *type, double *dst) {
2370+ network_mysqld_type_float_t *src = type->data;
2371+
2372+ if (NULL == type->data) return -1;
2373+
2374+ *dst = (double)*src;
2375+
2376+ return 0;
2377+}
2378+
2379+static int network_mysqld_type_data_float_set_double(network_mysqld_type_t *type, double src) {
2380+ network_mysqld_type_float_t *dst = type->data;
2381+
2382+ if (NULL == type->data) {
2383+ type->data = network_mysqld_type_float_new();
2384+ }
2385+
2386+ dst = type->data;
2387+ *dst = (float)src;
2388+
2389+ return 0;
2390+}
2391+
2392+static void network_mysqld_type_data_float_init(network_mysqld_type_t *type, enum enum_field_types field_type) {
2393+ type->type = field_type;
2394+ type->free_data = network_mysqld_type_data_float_free;
2395+ type->get_double = network_mysqld_type_data_float_get_double;
2396+ type->set_double = network_mysqld_type_data_float_set_double;
2397+}
2398+
2399+/* MYSQL_TYPE_STRING */
2400+static network_mysqld_type_string_t *network_mysqld_type_string_new(void) {
2401+ network_mysqld_type_string_t *str;
2402+
2403+ str = g_string_new(NULL);
2404+
2405+ return str;
2406+}
2407+
2408+static void network_mysqld_type_string_free(network_mysqld_type_string_t *str) {
2409+ if (NULL == str) return;
2410+
2411+ g_string_free(str, TRUE);
2412+}
2413+
2414+static void network_mysqld_type_data_string_free(network_mysqld_type_t *type) {
2415+ if (NULL == type) return;
2416+
2417+ network_mysqld_type_string_free(type->data);
2418+}
2419+
2420+static int network_mysqld_type_data_string_get_string_const(network_mysqld_type_t *type, const char **dst, gsize *dst_len) {
2421+ GString *src = type->data;
2422+
2423+ if (NULL == type->data) return -1;
2424+
2425+ *dst = src->str;
2426+ *dst_len = src->len;
2427+
2428+ return 0;
2429+}
2430+
2431+static int network_mysqld_type_data_string_set_string(network_mysqld_type_t *type, const char *src, gsize src_len) {
2432+ GString *dst;
2433+
2434+ if (NULL == type->data) {
2435+ type->data = g_string_sized_new(src_len);
2436+ }
2437+
2438+ dst = type->data;
2439+
2440+ g_string_assign_len(dst, src, src_len);
2441+
2442+ return 0;
2443+}
2444+
2445+static void network_mysqld_type_data_string_init(network_mysqld_type_t *type, enum enum_field_types field_type) {
2446+ type->type = field_type;
2447+ type->free_data = network_mysqld_type_data_string_free;
2448+ type->get_string_const = network_mysqld_type_data_string_get_string_const;
2449+ type->set_string = network_mysqld_type_data_string_set_string;
2450+}
2451+
2452+/* MYSQL_TYPE_DATE */
2453+static network_mysqld_type_date_t *network_mysqld_type_date_new(void) {
2454+ network_mysqld_type_date_t *date;
2455+
2456+ date = g_slice_new0(network_mysqld_type_date_t);
2457+
2458+ return date;
2459+}
2460+
2461+static void network_mysqld_type_date_free(network_mysqld_type_date_t *date) {
2462+ if (NULL == date) return;
2463+
2464+ g_slice_free(network_mysqld_type_date_t, date);
2465+}
2466+
2467+static void network_mysqld_type_data_date_free(network_mysqld_type_t *type) {
2468+ if (NULL == type) return;
2469+
2470+ network_mysqld_type_date_free(type->data);
2471+}
2472+
2473+static int network_mysqld_type_data_date_get_date(network_mysqld_type_t *type, network_mysqld_type_date_t *dst) {
2474+ network_mysqld_type_date_t *src = type->data;
2475+
2476+ if (NULL == type->data) return -1;
2477+
2478+ memcpy(dst, src, sizeof(*src));
2479+
2480+ return 0;
2481+}
2482+
2483+static gboolean network_mysqld_type_date_time_is_valid(network_mysqld_type_date_t *date) {
2484+ return (date->nsec < 1000000000 &&
2485+ date->sec < 100 &&
2486+ date->min <= 60 &&
2487+ date->hour <= 24);
2488+}
2489+
2490+static gboolean network_mysqld_type_date_date_is_valid(network_mysqld_type_date_t *date) {
2491+ return (date->day <= 31 &&
2492+ date->month <= 12 &&
2493+ date->year <= 9999);
2494+}
2495+
2496+gboolean network_mysqld_type_date_is_valid(network_mysqld_type_date_t *date) {
2497+ return network_mysqld_type_date_time_is_valid(date) &&
2498+ network_mysqld_type_date_date_is_valid(date);
2499+}
2500+
2501+static int network_mysqld_type_data_date_get_string(network_mysqld_type_t *type, char **dst, gsize *dst_len) {
2502+ network_mysqld_type_date_t *src = type->data;
2503+
2504+ if (NULL == type->data) return -1;
2505+
2506+ switch (type->type) {
2507+ case MYSQL_TYPE_DATE:
2508+ if (!network_mysqld_type_date_date_is_valid(src)) {
2509+ return -1;
2510+ }
2511+ break;
2512+ case MYSQL_TYPE_DATETIME:
2513+ case MYSQL_TYPE_TIMESTAMP:
2514+ if (!network_mysqld_type_date_is_valid(src)) {
2515+ return -1;
2516+ }
2517+ break;
2518+ default:
2519+ /* we shouldn't be here */
2520+ return -1;
2521+ }
2522+
2523+ if (NULL != *dst) {
2524+ switch (type->type) {
2525+ case MYSQL_TYPE_DATE:
2526+ /* dst_len already contains a size and we don't have to alloc */
2527+ if (*dst_len < NETWORK_MYSQLD_TYPE_DATE_MIN_BUF_LEN) {
2528+ return -1; /* ... but it is too small .. we could return the right size here */
2529+ }
2530+ *dst_len = snprintf(*dst, *dst_len, "%04u-%02u-%02u",
2531+ src->year,
2532+ src->month,
2533+ src->day);
2534+ break;
2535+ case MYSQL_TYPE_DATETIME:
2536+ case MYSQL_TYPE_TIMESTAMP:
2537+ /* dst_len already contains a size and we don't have to alloc */
2538+ if (*dst_len < NETWORK_MYSQLD_TYPE_DATETIME_MIN_BUF_LEN) {
2539+ return -1; /* ... but it is too small .. we could return the right size here */
2540+ }
2541+ *dst_len = snprintf(*dst, *dst_len, "%04u-%02u-%02u %02u:%02u:%02u.%09u",
2542+ src->year,
2543+ src->month,
2544+ src->day,
2545+ src->hour,
2546+ src->min,
2547+ src->sec,
2548+ src->nsec);
2549+ break;
2550+ default:
2551+ g_assert_not_reached();
2552+ break;
2553+ }
2554+ } else {
2555+ switch (type->type) {
2556+ case MYSQL_TYPE_DATE:
2557+ *dst = g_strdup_printf("%04u-%02u-%02u",
2558+ src->year,
2559+ src->month,
2560+ src->day);
2561+ *dst_len = strlen(*dst);
2562+ break;
2563+ case MYSQL_TYPE_DATETIME:
2564+ case MYSQL_TYPE_TIMESTAMP:
2565+ *dst = g_strdup_printf("%04u-%02u-%02u %02u:%02u:%02u.%09u",
2566+ src->year,
2567+ src->month,
2568+ src->day,
2569+ src->hour,
2570+ src->min,
2571+ src->sec,
2572+ src->nsec);
2573+ *dst_len = strlen(*dst);
2574+ break;
2575+ default:
2576+ g_assert_not_reached();
2577+ break;
2578+ }
2579+ }
2580+
2581+ return 0;
2582+}
2583+
2584+
2585+static int network_mysqld_type_data_date_set_date(network_mysqld_type_t *type, network_mysqld_type_date_t *src) {
2586+ network_mysqld_type_date_t *dst;
2587+
2588+ if (NULL == type->data) {
2589+ type->data = network_mysqld_type_date_new();
2590+ }
2591+
2592+ dst = type->data;
2593+
2594+ memcpy(dst, src, sizeof(*src));
2595+
2596+ return 0;
2597+}
2598+
2599+static void network_mysqld_type_data_date_init(network_mysqld_type_t *type, enum enum_field_types field_type) {
2600+ type->type = field_type;
2601+ type->free_data = network_mysqld_type_data_date_free;
2602+ type->get_date = network_mysqld_type_data_date_get_date;
2603+ type->get_string = network_mysqld_type_data_date_get_string;
2604+ type->set_date = network_mysqld_type_data_date_set_date;
2605+}
2606+
2607+
2608+/* MYSQL_TYPE_TIME */
2609+static network_mysqld_type_time_t *network_mysqld_type_time_new(void) {
2610+ network_mysqld_type_time_t *t;
2611+
2612+ t = g_slice_new0(network_mysqld_type_time_t);
2613+
2614+ return t;
2615+}
2616+
2617+static void network_mysqld_type_time_free(network_mysqld_type_time_t *t) {
2618+ if (NULL == t) return;
2619+
2620+ g_slice_free(network_mysqld_type_time_t, t);
2621+}
2622+
2623+static void network_mysqld_type_data_time_free(network_mysqld_type_t *type) {
2624+ if (NULL == type) return;
2625+
2626+ network_mysqld_type_time_free(type->data);
2627+}
2628+
2629+static int network_mysqld_type_data_time_get_time(network_mysqld_type_t *type, network_mysqld_type_time_t *dst) {
2630+ network_mysqld_type_time_t *src = type->data;
2631+
2632+ if (NULL == type->data) return -1;
2633+
2634+ memcpy(dst, src, sizeof(*src));
2635+
2636+ return 0;
2637+}
2638+
2639+static int network_mysqld_type_data_time_get_string(network_mysqld_type_t *type, char **dst, gsize *dst_len) {
2640+ network_mysqld_type_time_t *src = type->data;
2641+
2642+ if (NULL == type->data) return -1;
2643+
2644+ if (NULL != *dst) {
2645+ /* dst_len already contains a size and we don't have to alloc */
2646+ if (*dst_len < NETWORK_MYSQLD_TYPE_TIME_MIN_BUF_LEN) {
2647+ return -1; /* ... but it is too small .. we could return the right size here */
2648+ }
2649+ *dst_len = snprintf(*dst, *dst_len, "%s%d %02u:%02u:%02u.%09u",
2650+ src->sign ? "-" : "",
2651+ src->days,
2652+ src->hour,
2653+ src->min,
2654+ src->sec,
2655+ src->nsec);
2656+ } else {
2657+ *dst = g_strdup_printf("%s%d %02u:%02u:%02u.%09u",
2658+ src->sign ? "-" : "",
2659+ src->days,
2660+ src->hour,
2661+ src->min,
2662+ src->sec,
2663+ src->nsec);
2664+ *dst_len = strlen(*dst);
2665+ }
2666+
2667+ return 0;
2668+}
2669+
2670+static int network_mysqld_type_data_time_set_time(network_mysqld_type_t *type, network_mysqld_type_time_t *src) {
2671+ network_mysqld_type_date_t *dst;
2672+
2673+ if (NULL == type->data) {
2674+ type->data = network_mysqld_type_time_new();
2675+ }
2676+ dst = type->data;
2677+
2678+ memcpy(dst, src, sizeof(*src));
2679+
2680+ return 0;
2681+}
2682+
2683+
2684+static void network_mysqld_type_data_time_init(network_mysqld_type_t *type, enum enum_field_types field_type) {
2685+ type->type = field_type;
2686+ type->free_data = network_mysqld_type_data_time_free;
2687+ type->get_time = network_mysqld_type_data_time_get_time;
2688+ type->get_string = network_mysqld_type_data_time_get_string;
2689+ type->set_time = network_mysqld_type_data_time_set_time;
2690+}
2691+
2692+
2693+/**
2694+ * create a type
2695+ */
2696+network_mysqld_type_t *network_mysqld_type_new(enum enum_field_types field_type) {
2697+ network_mysqld_type_t *type = NULL;
2698+
2699+ switch (field_type) {
2700+ case MYSQL_TYPE_TINY:
2701+ case MYSQL_TYPE_SHORT:
2702+ case MYSQL_TYPE_LONG:
2703+ case MYSQL_TYPE_INT24:
2704+ case MYSQL_TYPE_LONGLONG:
2705+ type = g_slice_new0(network_mysqld_type_t);
2706+
2707+ network_mysqld_type_data_int_init(type, field_type);
2708+ break;
2709+ case MYSQL_TYPE_FLOAT: /* 4 bytes */
2710+ type = g_slice_new0(network_mysqld_type_t);
2711+
2712+ network_mysqld_type_data_float_init(type, field_type);
2713+ break;
2714+ case MYSQL_TYPE_DOUBLE: /* 8 bytes */
2715+ type = g_slice_new0(network_mysqld_type_t);
2716+
2717+ network_mysqld_type_data_double_init(type, field_type);
2718+ break;
2719+ case MYSQL_TYPE_DATETIME:
2720+ case MYSQL_TYPE_DATE:
2721+ case MYSQL_TYPE_TIMESTAMP:
2722+ type = g_slice_new0(network_mysqld_type_t);
2723+
2724+ network_mysqld_type_data_date_init(type, field_type);
2725+ break;
2726+ case MYSQL_TYPE_TIME:
2727+ type = g_slice_new0(network_mysqld_type_t);
2728+
2729+ network_mysqld_type_data_time_init(type, field_type);
2730+ break;
2731+ case MYSQL_TYPE_NEWDECIMAL:
2732+ case MYSQL_TYPE_BLOB:
2733+ case MYSQL_TYPE_TINY_BLOB:
2734+ case MYSQL_TYPE_MEDIUM_BLOB:
2735+ case MYSQL_TYPE_LONG_BLOB:
2736+ case MYSQL_TYPE_STRING:
2737+ case MYSQL_TYPE_VAR_STRING:
2738+ case MYSQL_TYPE_VARCHAR:
2739+ /* they are all length-encoded strings */
2740+ type = g_slice_new0(network_mysqld_type_t);
2741+
2742+ network_mysqld_type_data_string_init(type, field_type);
2743+ break;
2744+ case MYSQL_TYPE_NULL:
2745+ type = g_slice_new0(network_mysqld_type_t);
2746+
2747+ type->type = field_type;
2748+ break;
2749+ }
2750+
2751+ return type;
2752+}
2753+/**
2754+ * free a type
2755+ */
2756+void network_mysqld_type_free(network_mysqld_type_t *type) {
2757+ if (NULL == type) return;
2758+
2759+ if (NULL != type->free_data) {
2760+ type->free_data(type);
2761+ }
2762+ g_slice_free(network_mysqld_type_t, type);
2763+}
2764+
2765+int network_mysqld_type_get_gstring(network_mysqld_type_t *type, GString *s) {
2766+ if (NULL == type->get_gstring) return -1;
2767+
2768+ return type->get_gstring(type, s);
2769+}
2770+
2771+int network_mysqld_type_get_string_const(network_mysqld_type_t *type, const char **s, gsize *s_len) {
2772+ if (NULL == type->get_string_const) return -1;
2773+
2774+ return type->get_string_const(type, s, s_len);
2775+}
2776+
2777+int network_mysqld_type_get_string(network_mysqld_type_t *type, char **s, gsize *s_len) {
2778+ if (NULL == type->get_string) return -1;
2779+
2780+ return type->get_string(type, s, s_len);
2781+}
2782+
2783+
2784+int network_mysqld_type_set_string(network_mysqld_type_t *type, const char *s, gsize s_len) {
2785+ if (NULL == type->set_string) return -1;
2786+
2787+ return type->set_string(type, s, s_len);
2788+}
2789+
2790+
2791+int network_mysqld_type_get_int(network_mysqld_type_t *type, guint64 *i, gboolean *is_unsigned) {
2792+ if (NULL == type->get_int) return -1;
2793+
2794+ return type->get_int(type, i, is_unsigned);
2795+}
2796+
2797+
2798+int network_mysqld_type_set_int(network_mysqld_type_t *type, guint64 i, gboolean is_unsigned) {
2799+ if (NULL == type->set_int) return -1;
2800+
2801+ return type->set_int(type, i, is_unsigned);
2802+}
2803+
2804+
2805+int network_mysqld_type_get_double(network_mysqld_type_t *type, double *d) {
2806+ if (NULL == type->get_double) return -1;
2807+
2808+ return type->get_double(type, d);
2809+}
2810+
2811+
2812+int network_mysqld_type_set_double(network_mysqld_type_t *type, double d) {
2813+ if (NULL == type->set_double) return -1;
2814+
2815+ return type->set_double(type, d);
2816+}
2817+
2818+
2819+int network_mysqld_type_get_date(network_mysqld_type_t *type, network_mysqld_type_date_t *date) {
2820+ if (NULL == type->get_date) return -1;
2821+
2822+ return type->get_date(type, date);
2823+}
2824+
2825+
2826+int network_mysqld_type_set_date(network_mysqld_type_t *type, network_mysqld_type_date_t *date) {
2827+ if (NULL == type->set_date) return -1;
2828+
2829+ return type->set_date(type, date);
2830+}
2831+
2832+
2833+int network_mysqld_type_get_time(network_mysqld_type_t *type, network_mysqld_type_time_t *t) {
2834+ if (NULL == type->get_time) return -1;
2835+
2836+ return type->get_time(type, t);
2837+}
2838+
2839+
2840+int network_mysqld_type_set_time(network_mysqld_type_t *type, network_mysqld_type_time_t *t) {
2841+ if (NULL == type->set_time) return -1;
2842+
2843+ return type->set_time(type, t);
2844+}
2845+
2846+
2847
2848=== added file 'src/network_mysqld_type.h'
2849--- src/network_mysqld_type.h 1970-01-01 00:00:00 +0000
2850+++ src/network_mysqld_type.h 2010-09-22 15:13:16 +0000
2851@@ -0,0 +1,147 @@
2852+#ifndef __NETWORK_MYSQLD_TYPE_H__
2853+#define __NETWORK_MYSQLD_TYPE_H__
2854+
2855+#include <mysql.h>
2856+#include <glib.h>
2857+
2858+#include "network-mysqld-proto.h"
2859+
2860+/**
2861+ * struct for the MYSQL_TYPE_DATE and friends
2862+ */
2863+typedef struct {
2864+ guint16 year;
2865+ guint8 month;
2866+ guint8 day;
2867+
2868+ guint8 hour;
2869+ guint8 min;
2870+ guint8 sec;
2871+
2872+ guint32 nsec; /* the nano-second part */
2873+} network_mysqld_type_date_t;
2874+
2875+#define NETWORK_MYSQLD_TYPE_DATE_MIN_BUF_LEN (sizeof("2010-10-27"))
2876+#define NETWORK_MYSQLD_TYPE_DATETIME_MIN_BUF_LEN (sizeof("2010-10-27 19:27:30.000000001"))
2877+#define NETWORK_MYSQLD_TYPE_TIMESTAMP_MIN_BUF_LEN NETWORK_MYSQLD_TYPE_DATETIME_MIN_BUF_LEN
2878+
2879+/**
2880+ * struct for the MYSQL_TYPE_TIME
2881+ */
2882+typedef struct {
2883+ guint8 sign;
2884+ guint32 days;
2885+
2886+ guint8 hour;
2887+ guint8 min;
2888+ guint8 sec;
2889+
2890+ guint32 nsec; /* the nano-second part */
2891+} network_mysqld_type_time_t;
2892+
2893+#define NETWORK_MYSQLD_TYPE_TIME_MIN_BUF_LEN (sizeof("-2147483647 19:27:30.000000001"))
2894+
2895+typedef struct _network_mysqld_type_t network_mysqld_type_t;
2896+
2897+struct _network_mysqld_type_t {
2898+ enum enum_field_types type;
2899+
2900+ gpointer data;
2901+ void (*free_data)(network_mysqld_type_t *type);
2902+
2903+ /**
2904+ * get a copy of ->data as GString
2905+ *
2906+ * @param type the type to get the data from
2907+ * @param s GString that the converted data will be assigned too
2908+ * @return 0 on success, -1 on error
2909+ */
2910+ int (*get_gstring)(network_mysqld_type_t *type, GString *s);
2911+ /**
2912+ * expose the ->data as constant string
2913+ *
2914+ * only available for types that have a "string" storage like _STRING, _CHAR, _BLOB
2915+ * the caller can copy the data out, but not change it
2916+ *
2917+ * @param type the type to get the data from
2918+ * @param s place to store the pointer to the const char * in
2919+ * @param s_len length of the const char *
2920+ * @return 0 on success, -1 on error
2921+ */
2922+ int (*get_string_const)(network_mysqld_type_t *type, const char **s, gsize *s_len);
2923+ /**
2924+ * get a copy of ->data as char *
2925+ *
2926+ * has 2 modes:
2927+ * - no-alloc-mode if *s is not NULL where it is expected that s and s_len point
2928+ * to a buffer of that size that we can copy into
2929+ * *s_len will contain the size of the stored string on success
2930+ * if *s_len is too small, -1 will be returned
2931+ * - alloc-mode when *s is NULL where we return a alloced buffer that is large enough
2932+ *
2933+ * @param type the type to get the data from
2934+ * @param s pointer to a buffer of *s_len size or pointer to (char *)NULL for alloc-mode
2935+ * @param s_len pointer to the length of the buffer if *s is not NULL. Points to the length of the *s on success
2936+ * @return 0 on success, -1 on error
2937+ */
2938+ int (*get_string)(network_mysqld_type_t *type, char **s, gsize *len);
2939+ /**
2940+ * set the ->data from a string
2941+ */
2942+ int (*set_string)(network_mysqld_type_t *type, const char *s, gsize s_len);
2943+ /**
2944+ * get ->data as uint64
2945+ */
2946+ int (*get_int)(network_mysqld_type_t *type, guint64 *i, gboolean *is_unsigned);
2947+ /**
2948+ * set ->data from uint64
2949+ */
2950+ int (*set_int)(network_mysqld_type_t *type, guint64 i, gboolean is_unsigned);
2951+ /**
2952+ * get ->data as double
2953+ */
2954+ int (*get_double)(network_mysqld_type_t *type, double *d);
2955+ /**
2956+ * set ->data from double
2957+ */
2958+ int (*set_double)(network_mysqld_type_t *type, double d);
2959+ int (*get_date)(network_mysqld_type_t *type, network_mysqld_type_date_t *date);
2960+ int (*set_date)(network_mysqld_type_t *type, network_mysqld_type_date_t *date);
2961+ /**
2962+ * get the ->data as _time_t
2963+ */
2964+ int (*get_time)(network_mysqld_type_t *type, network_mysqld_type_time_t *t);
2965+ /**
2966+ * set the ->data from a _time_t
2967+ */
2968+ int (*set_time)(network_mysqld_type_t *type, network_mysqld_type_time_t *t);
2969+
2970+
2971+ gboolean is_null; /**< is the value of this type NULL */
2972+ gboolean is_unsigned; /**< is the type signed or unsigned, only used by the integer types */
2973+};
2974+
2975+
2976+NETWORK_API network_mysqld_type_t *network_mysqld_type_new(enum enum_field_types _type);
2977+NETWORK_API void network_mysqld_type_free(network_mysqld_type_t *type);
2978+
2979+/**
2980+ * wrappers around the gettors and settors
2981+ *
2982+ * @return -1 if no settor or gettor defined or settor or gettor failed to convert
2983+ */
2984+NETWORK_API int network_mysqld_type_get_gstring(network_mysqld_type_t *type, GString *s);
2985+NETWORK_API int network_mysqld_type_get_gstring(network_mysqld_type_t *type, GString *s);
2986+NETWORK_API int network_mysqld_type_get_string_const(network_mysqld_type_t *type, const char **s, gsize *s_len);
2987+NETWORK_API int network_mysqld_type_get_string(network_mysqld_type_t *type, char **s, gsize *len);
2988+NETWORK_API int network_mysqld_type_set_string(network_mysqld_type_t *type, const char *s, gsize s_len);
2989+NETWORK_API int network_mysqld_type_get_int(network_mysqld_type_t *type, guint64 *i, gboolean *is_unsigned);
2990+NETWORK_API int network_mysqld_type_set_int(network_mysqld_type_t *type, guint64 i, gboolean is_unsigned);
2991+NETWORK_API int network_mysqld_type_get_double(network_mysqld_type_t *type, double *d);
2992+NETWORK_API int network_mysqld_type_set_double(network_mysqld_type_t *type, double d);
2993+NETWORK_API int network_mysqld_type_get_date(network_mysqld_type_t *type, network_mysqld_type_date_t *date);
2994+NETWORK_API int network_mysqld_type_set_date(network_mysqld_type_t *type, network_mysqld_type_date_t *date);
2995+NETWORK_API int network_mysqld_type_get_time(network_mysqld_type_t *type, network_mysqld_type_time_t *t);
2996+NETWORK_API int network_mysqld_type_set_time(network_mysqld_type_t *type, network_mysqld_type_time_t *t);
2997+
2998+#endif
2999
3000=== modified file 'tests/unit/CMakeLists.txt'
3001--- tests/unit/CMakeLists.txt 2010-02-24 11:02:26 +0000
3002+++ tests/unit/CMakeLists.txt 2010-09-22 15:13:16 +0000
3003@@ -113,6 +113,7 @@
3004 ../../src/glib-ext.c
3005 ../../src/network-mysqld-proto.c
3006 ../../src/network-mysqld-packet.c
3007+ ../../src/network_mysqld_type.c
3008 ../../src/chassis-timings.c
3009 ../../src/my_rdtsc.c
3010 )
3011@@ -132,6 +133,7 @@
3012 ../../src/glib-ext.c
3013 ../../src/network-mysqld-proto.c
3014 ../../src/network-mysqld-packet.c
3015+ ../../src/network_mysqld_type.c
3016 ../../src/network-address.c
3017 )
3018
3019
3020=== modified file 'tests/unit/Makefile.am'
3021--- tests/unit/Makefile.am 2010-04-06 14:26:51 +0000
3022+++ tests/unit/Makefile.am 2010-09-22 15:13:16 +0000
3023@@ -32,6 +32,7 @@
3024 t_network_backend \
3025 t_network_injection \
3026 t_network_mysqld_packet \
3027+ t_network_mysqld_type \
3028 t_network_mysqld_masterinfo \
3029 t_chassis_timings \
3030 t_chassis_shutdown_hooks \
3031@@ -81,10 +82,21 @@
3032 check_mysqld_proto_CPPFLAGS = -I$(top_srcdir)/src/ $(GLIB_CFLAGS) $(MYSQL_CFLAGS)
3033 check_mysqld_proto_LDADD = $(GLIB_LIBS)
3034
3035+t_network_mysqld_type_SOURCES = \
3036+ t_network_mysqld_type.c \
3037+ $(top_srcdir)/src/network_mysqld_type.c \
3038+ $(top_srcdir)/src/glib-ext.c
3039+
3040+t_network_mysqld_type_CPPFLAGS = -I$(top_srcdir)/src/ $(GLIB_CFLAGS) $(MYSQL_CFLAGS) $(LUA_CFLAGS)
3041+t_network_mysqld_type_LDADD = $(GLIB_LIBS) $(LUA_LIBS) $(EVENT_LIBS)
3042+
3043+
3044 t_network_mysqld_packet_SOURCES = \
3045 t_network_mysqld_packet.c \
3046 $(top_srcdir)/src/network-mysqld-packet.c \
3047 $(top_srcdir)/src/network-mysqld-proto.c \
3048+ $(top_srcdir)/src/network_mysqld_type.c \
3049+ $(top_srcdir)/src/network_mysqld_proto_binary.c \
3050 $(top_srcdir)/src/network-queue.c \
3051 $(top_srcdir)/src/network-socket.c \
3052 $(top_srcdir)/src/network-address.c \
3053@@ -126,6 +138,8 @@
3054 $(top_srcdir)/src/glib-ext.c \
3055 $(top_srcdir)/src/network-mysqld-proto.c \
3056 $(top_srcdir)/src/network-mysqld-packet.c \
3057+ $(top_srcdir)/src/network_mysqld_type.c \
3058+ $(top_srcdir)/src/network_mysqld_proto_binary.c \
3059 $(top_srcdir)/src/network-address.c \
3060 $(top_srcdir)/src/network-queue.c \
3061 $(top_srcdir)/src/network-socket.c
3062@@ -177,6 +191,8 @@
3063 $(top_srcdir)/src/network-backend.c \
3064 $(top_srcdir)/src/network-mysqld-proto.c \
3065 $(top_srcdir)/src/network-mysqld-packet.c \
3066+ $(top_srcdir)/src/network_mysqld_type.c \
3067+ $(top_srcdir)/src/network_mysqld_proto_binary.c \
3068 $(top_srcdir)/src/network-conn-pool.c \
3069 $(top_srcdir)/src/network-address.c \
3070 $(top_srcdir)/src/network-queue.c \
3071@@ -204,6 +220,8 @@
3072 $(top_srcdir)/src/glib-ext.c \
3073 $(top_srcdir)/src/network-mysqld-proto.c \
3074 $(top_srcdir)/src/network-mysqld-packet.c \
3075+ $(top_srcdir)/src/network_mysqld_type.c \
3076+ $(top_srcdir)/src/network_mysqld_proto_binary.c \
3077 $(top_srcdir)/src/network-injection.c \
3078 $(top_srcdir)/src/my_rdtsc.c \
3079 $(top_srcdir)/src/chassis-timings.c
3080
3081=== modified file 'tests/unit/lua/mysql-proto.lua'
3082--- tests/unit/lua/mysql-proto.lua 2010-04-06 14:26:51 +0000
3083+++ tests/unit/lua/mysql-proto.lua 2010-09-22 15:13:16 +0000
3084@@ -19,7 +19,7 @@
3085 $%ENDLICENSE%$ --]]
3086 local proto = assert(require("mysql.proto"))
3087 local password = assert(require("mysql.password"))
3088-
3089+require("proxy.test")
3090 ---
3091 -- err packet
3092
3093@@ -265,3 +265,72 @@
3094
3095 assert(false == password.check(challenge, response, dbl_hashed))
3096
3097+---
3098+-- prepared stmt decoders
3099+--
3100+
3101+-- EXECUTE packet, no params
3102+local packet = "\023\001\000\000\000\000\001\000\000\000"
3103+local execute = proto.from_stmt_execute_packet(packet, 0)
3104+assert(execute)
3105+assertEquals(execute.stmt_id, 1)
3106+assertEquals(execute.flags, 0)
3107+assertEquals(execute.iteration_count, 1)
3108+assertEquals(execute.new_params_bound, false)
3109+
3110+-- EXECUTE packet with 14 params
3111+local packet = "\023" ..
3112+ "\001\000\000\000" ..
3113+ "\000" ..
3114+ "\001\000\000\000" ..
3115+ "\003\000" ..
3116+ "\001" ..
3117+ "\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" ..
3118+ "\003\102\111\111" ..
3119+ "\001\000\000\000\000\000\000\000" ..
3120+ "\001\000\000\000\000\000\000\000" ..
3121+ "\001\000\000\000" ..
3122+ "\001\000" ..
3123+ "\001" ..
3124+ "\102\102\102\102\102\102\036\064" ..
3125+ "\000\000\036\065" ..
3126+ "\004\218\007\010\017" ..
3127+ "\011\218\007\010\017\019\027\030\001\000\000\000" ..
3128+ "\011\218\007\010\017\019\027\030\001\000\000\000" ..
3129+ "\012\001\120\000\000\000\019\027\030\001\000\000\000"
3130+
3131+local execute = proto.from_stmt_execute_packet(packet, 14)
3132+assert(execute)
3133+assertEquals(execute.stmt_id, 1)
3134+assertEquals(execute.flags, 0)
3135+assertEquals(execute.iteration_count, 1)
3136+assertEquals(execute.new_params_bound, true)
3137+
3138+local params = execute.params
3139+assert(params)
3140+assertEquals(#params, 14)
3141+
3142+local expected_params = {
3143+ { type = 254, value = nil },
3144+ { type = 6, value = nil },
3145+ { type = 254, value = "foo" },
3146+ { type = 8, value = 1 },
3147+ { type = 8, value = 1 },
3148+ { type = 3, value = 1 },
3149+ { type = 2, value = 1 },
3150+ { type = 1, value = 1 },
3151+ { type = 5, value = 10.2 }, --[[ double ]]--
3152+ { type = 4, value = 10.25 }, --[[ float ]]--
3153+ { type = 10, value = "2010-10-17" }, --[[ date ]]--
3154+ { type = 12, value = "2010-10-17 19:27:30.000000001" }, --[[ datetime ]]--
3155+ { type = 7, value = "2010-10-17 19:27:30.000000001" }, --[[ timestamp ]]--
3156+ { type = 11, value = "-120 19:27:30.000000001" }, --[[ time ]]--
3157+}
3158+
3159+for ndx, expected_param in ipairs(expected_params) do
3160+ local param = params[ndx]
3161+ assert(param)
3162+ assertEquals(param.type, expected_param.type)
3163+ assertEquals(param.value, expected_param.value)
3164+end
3165+
3166
3167=== modified file 'tests/unit/t_network_mysqld_packet.c'
3168--- tests/unit/t_network_mysqld_packet.c 2010-04-06 14:26:51 +0000
3169+++ tests/unit/t_network_mysqld_packet.c 2010-09-22 15:13:16 +0000
3170@@ -27,6 +27,7 @@
3171
3172 #include "network-mysqld-proto.h"
3173 #include "network-mysqld-packet.h"
3174+#include "network_mysqld_type.h"
3175 #include "glib-ext.h"
3176
3177 #if GLIB_CHECK_VERSION(2, 16, 0)
3178@@ -695,6 +696,624 @@
3179 network_queue_free(q);
3180 }
3181
3182+/* prepared statements */
3183+
3184+/* COM_STMT_PREPARE */
3185+static void t_com_stmt_prepare_new(void) {
3186+ network_mysqld_stmt_prepare_packet_t *cmd;
3187+
3188+ cmd = network_mysqld_stmt_prepare_packet_new();
3189+ g_assert(cmd);
3190+
3191+ network_mysqld_stmt_prepare_packet_free(cmd);
3192+}
3193+
3194+static void t_com_stmt_prepare_from_packet(void) {
3195+ network_mysqld_stmt_prepare_packet_t *cmd;
3196+ const char raw_packet[] = "\x1c\x00\x00\x00\x16SELECT CONCAT(?, ?) AS col1";
3197+ network_packet packet;
3198+
3199+ packet.data = g_string_new_len(C(raw_packet));
3200+ packet.offset = 0;
3201+
3202+ cmd = network_mysqld_stmt_prepare_packet_new();
3203+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3204+ g_assert_cmpint(0, ==, network_mysqld_proto_get_stmt_prepare_packet(&packet, cmd));
3205+ g_assert_cmpint(sizeof("SELECT CONCAT(?, ?) AS col1") - 1, ==, cmd->stmt_text->len);
3206+ g_assert_cmpstr("SELECT CONCAT(?, ?) AS col1", ==, cmd->stmt_text->str);
3207+
3208+ network_mysqld_stmt_prepare_packet_free(cmd);
3209+}
3210+
3211+/* COM_STMT_PREPARE OK-result */
3212+
3213+static void t_com_stmt_prepare_ok_new(void) {
3214+ network_mysqld_stmt_prepare_ok_packet_t *cmd;
3215+
3216+ cmd = network_mysqld_stmt_prepare_ok_packet_new();
3217+ g_assert(cmd);
3218+
3219+ network_mysqld_stmt_prepare_ok_packet_free(cmd);
3220+}
3221+
3222+/**
3223+ * test if we parse all the fields of a COM_STMT_PREPARE-ok response correctly
3224+ */
3225+static void t_com_stmt_prepare_ok_from_packet(void) {
3226+ network_mysqld_stmt_prepare_ok_packet_t *cmd;
3227+ network_mysqld_eof_packet_t *eof;
3228+ network_mysqld_proto_fielddef_t *coldef;
3229+
3230+ /* a response for the COM_STMT_PREPARE command
3231+ *
3232+ * the OK part with stmt-id and so on is in the first packet. The others are
3233+ * the field-defs, a EOF, the param-defs, and the last EOF */
3234+ strings packets[] = {
3235+ { C("\x0c\x00\x00\x01\x00\x01\x00\x00\x00\x01\x00\x02\x00\x00\x00\x00") }, /* the PREPARE OK packet */
3236+ { 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 */
3237+ { 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 */
3238+ { C("\x05\x00\x00\x04\xfe\x00\x00\x02\x00") }, /* the seperator */
3239+ { 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 */
3240+ { C("\x05\x00\x00\x06\xfe\x00\x00\x02\x00") } /* the terminator */
3241+ };
3242+ network_packet packet;
3243+
3244+ packet.data = g_string_new_len(packets[0].s, packets[0].s_len);
3245+ packet.offset = 0;
3246+
3247+ cmd = network_mysqld_stmt_prepare_ok_packet_new();
3248+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3249+ g_assert_cmpint(0, ==, network_mysqld_proto_get_stmt_prepare_ok_packet(&packet, cmd));
3250+ g_assert_cmpint(1, ==, cmd->stmt_id);
3251+ g_assert_cmpint(1, ==, cmd->num_columns);
3252+ g_assert_cmpint(2, ==, cmd->num_params);
3253+ g_assert_cmpint(0, ==, cmd->warnings);
3254+
3255+ network_mysqld_stmt_prepare_ok_packet_free(cmd);
3256+
3257+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3258+ g_string_free(packet.data, TRUE);
3259+
3260+ packet.data = g_string_new_len(packets[1].s, packets[1].s_len);
3261+ packet.offset = 0;
3262+
3263+ coldef = network_mysqld_proto_fielddef_new();
3264+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3265+ g_assert_cmpint(0, ==, network_mysqld_proto_get_fielddef(&packet, coldef, CLIENT_PROTOCOL_41));
3266+
3267+ network_mysqld_proto_fielddef_free(coldef);
3268+
3269+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3270+ g_string_free(packet.data, TRUE);
3271+
3272+
3273+ packet.data = g_string_new_len(packets[2].s, packets[2].s_len);
3274+ packet.offset = 0;
3275+
3276+ coldef = network_mysqld_proto_fielddef_new();
3277+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3278+ g_assert_cmpint(0, ==, network_mysqld_proto_get_fielddef(&packet, coldef, CLIENT_PROTOCOL_41));
3279+ network_mysqld_proto_fielddef_free(coldef);
3280+
3281+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3282+ g_string_free(packet.data, TRUE);
3283+
3284+
3285+ packet.data = g_string_new_len(packets[3].s, packets[3].s_len);
3286+ packet.offset = 0;
3287+
3288+ eof = network_mysqld_eof_packet_new();
3289+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3290+ g_assert_cmpint(0, ==, network_mysqld_proto_get_eof_packet(&packet, eof));
3291+
3292+ network_mysqld_eof_packet_free(eof);
3293+
3294+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3295+ g_string_free(packet.data, TRUE);
3296+
3297+
3298+ packet.data = g_string_new_len(packets[4].s, packets[4].s_len);
3299+ packet.offset = 0;
3300+
3301+ coldef = network_mysqld_proto_fielddef_new();
3302+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3303+ g_assert_cmpint(0, ==, network_mysqld_proto_get_fielddef(&packet, coldef, CLIENT_PROTOCOL_41));
3304+ network_mysqld_proto_fielddef_free(coldef);
3305+
3306+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3307+ g_string_free(packet.data, TRUE);
3308+
3309+
3310+ packet.data = g_string_new_len(packets[5].s, packets[5].s_len);
3311+ packet.offset = 0;
3312+
3313+ eof = network_mysqld_eof_packet_new();
3314+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3315+ g_assert_cmpint(0, ==, network_mysqld_proto_get_eof_packet(&packet, eof));
3316+
3317+ network_mysqld_eof_packet_free(eof);
3318+
3319+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3320+ g_string_free(packet.data, TRUE);
3321+}
3322+
3323+/* COM_STMT_EXECUTE */
3324+
3325+static void t_com_stmt_execute_new(void) {
3326+ network_mysqld_stmt_execute_packet_t *cmd;
3327+
3328+ cmd = network_mysqld_stmt_execute_packet_new();
3329+ g_assert(cmd);
3330+
3331+ network_mysqld_stmt_execute_packet_free(cmd);
3332+}
3333+
3334+/**
3335+ * test if we decode all valid types from EXECUTE stmt
3336+ */
3337+static void t_com_stmt_execute_from_packet(void) {
3338+ network_mysqld_stmt_execute_packet_t *cmd;
3339+ const char raw_packet[] =
3340+ "\x7a\x00\x00\x00"
3341+ "\x17" /* COM_STMT_EXECUTE */
3342+ "\x01\x00\x00\x00" /* stmt-id */
3343+ "\x00" /* flags */
3344+ "\x01\x00\x00\x00" /* iteration count */
3345+ "\x03\x00" /* nul-flags */
3346+ "\x01" /* yeah, we have parameters */
3347+ "\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 */
3348+ "\x03\x66\x6f\x6f" /* the string */
3349+ "\x01\x00\x00\x00\x00\x00\x00\x00" /* int64 */
3350+ "\x01\x00\x00\x00\x00\x00\x00\x00" /* int64 (unsigned) */
3351+ "\x01\x00\x00\x00" /* int32 */
3352+ "\x01\x00" /* int16 */
3353+ "\x01" /* int8 */
3354+ "\x66\x66\x66\x66\x66\x66\x24\x40"
3355+ "\x33\x33\x23\x41"
3356+ "\x04\xda\x07\x0a\x11"
3357+ "\x0b\xda\x07\x0a\x11\x13\x1b\x1e\x01\x00\x00\x00"
3358+ "\x0b\xda\x07\x0a\x11\x13\x1b\x1e\x01\x00\x00\x00"
3359+ "\x0c\x01\x78\x00\x00\x00\x13\x1b\x1e\x01\x00\x00\x00";
3360+
3361+ network_packet packet;
3362+ network_mysqld_type_t *param;
3363+ int param_ndx = 0;
3364+
3365+ packet.data = g_string_new_len(C(raw_packet));
3366+ packet.offset = 0;
3367+
3368+#define EXPECTED_NUM_PARAMS 14
3369+ cmd = network_mysqld_stmt_execute_packet_new();
3370+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3371+ g_assert_cmpint(0, ==, network_mysqld_proto_get_stmt_execute_packet(&packet, cmd, EXPECTED_NUM_PARAMS));
3372+ g_assert_cmpint(1, ==, cmd->stmt_id);
3373+ g_assert_cmpint(0, ==, cmd->flags);
3374+ g_assert_cmpint(1, ==, cmd->iteration_count);
3375+ g_assert_cmpint(1, ==, cmd->new_params_bound);
3376+ g_assert_cmpint(EXPECTED_NUM_PARAMS, ==, cmd->params->len);
3377+#undef EXPECTED_NUM_PARAMS
3378+
3379+ /* (_STRING)NULL */
3380+ param = g_ptr_array_index(cmd->params, param_ndx++);
3381+ g_assert(param);
3382+ g_assert_cmpint(MYSQL_TYPE_STRING, ==, param->type);
3383+ g_assert_cmpint(TRUE, ==, param->is_null);
3384+
3385+ /* (_NULL) */
3386+ param = g_ptr_array_index(cmd->params, param_ndx++);
3387+ g_assert(param);
3388+ g_assert_cmpint(MYSQL_TYPE_NULL, ==, param->type);
3389+ g_assert_cmpint(TRUE, ==, param->is_null);
3390+
3391+ /* (_STRING)"foo" */
3392+ param = g_ptr_array_index(cmd->params, param_ndx++);
3393+ g_assert(param);
3394+ g_assert_cmpint(MYSQL_TYPE_STRING, ==, param->type);
3395+ g_assert_cmpint(FALSE, ==, param->is_null);
3396+ {
3397+ const char *s;
3398+ gsize s_len;
3399+
3400+ g_assert_cmpint(0, ==, param->get_string_const(param, &s, &s_len));
3401+ g_assert_cmpint(s_len, ==, 3);
3402+ g_assert_cmpstr(s, ==, "foo");
3403+ };
3404+
3405+ /* (_INT64)1 */
3406+ param = g_ptr_array_index(cmd->params, param_ndx++);
3407+ g_assert(param);
3408+ g_assert_cmpint(MYSQL_TYPE_LONGLONG, ==, param->type);
3409+ g_assert_cmpint(FALSE, ==, param->is_null);
3410+ g_assert_cmpint(FALSE, ==, param->is_unsigned);
3411+ {
3412+ guint64 i;
3413+ gboolean is_unsigned;
3414+
3415+ g_assert_cmpint(0, ==, param->get_int(param, &i, &is_unsigned));
3416+ g_assert_cmpint(i, ==, 1);
3417+ g_assert_cmpint(is_unsigned, ==, FALSE);
3418+ };
3419+
3420+ /* (_UINT64)1 */
3421+ param = g_ptr_array_index(cmd->params, param_ndx++);
3422+ g_assert(param);
3423+ g_assert_cmpint(MYSQL_TYPE_LONGLONG, ==, param->type);
3424+ g_assert_cmpint(FALSE, ==, param->is_null);
3425+ g_assert_cmpint(TRUE, ==, param->is_unsigned);
3426+ {
3427+ guint64 i;
3428+ gboolean is_unsigned;
3429+
3430+ g_assert_cmpint(0, ==, param->get_int(param, &i, &is_unsigned));
3431+ g_assert_cmpint(i, ==, 1);
3432+ };
3433+
3434+ /* (_INT32)1 */
3435+ param = g_ptr_array_index(cmd->params, param_ndx++);
3436+ g_assert(param);
3437+ g_assert_cmpint(MYSQL_TYPE_LONG, ==, param->type);
3438+ g_assert_cmpint(FALSE, ==, param->is_null);
3439+ g_assert_cmpint(FALSE, ==, param->is_unsigned);
3440+ {
3441+ guint64 i;
3442+ gboolean is_unsigned;
3443+
3444+ g_assert_cmpint(0, ==, param->get_int(param, &i, &is_unsigned));
3445+ g_assert_cmpint(i, ==, 1);
3446+ };
3447+
3448+ /* (_INT16)1 */
3449+ param = g_ptr_array_index(cmd->params, param_ndx++);
3450+ g_assert(param);
3451+ g_assert_cmpint(MYSQL_TYPE_SHORT, ==, param->type);
3452+ g_assert_cmpint(FALSE, ==, param->is_null);
3453+ g_assert_cmpint(FALSE, ==, param->is_unsigned);
3454+ {
3455+ guint64 i;
3456+ gboolean is_unsigned;
3457+
3458+ g_assert_cmpint(0, ==, param->get_int(param, &i, &is_unsigned));
3459+ g_assert_cmpint(i, ==, 1);
3460+ };
3461+
3462+ /* (_INT8)1 */
3463+ param = g_ptr_array_index(cmd->params, param_ndx++);
3464+ g_assert(param);
3465+ g_assert_cmpint(MYSQL_TYPE_TINY, ==, param->type);
3466+ g_assert_cmpint(FALSE, ==, param->is_null);
3467+ g_assert_cmpint(FALSE, ==, param->is_unsigned);
3468+ {
3469+ guint64 i;
3470+ gboolean is_unsigned;
3471+
3472+ g_assert_cmpint(0, ==, param->get_int(param, &i, &is_unsigned));
3473+ g_assert_cmpint(i, ==, 1);
3474+ };
3475+
3476+ /* (_DOUBLE)10.2 */
3477+ param = g_ptr_array_index(cmd->params, param_ndx++);
3478+ g_assert(param);
3479+ g_assert_cmpint(MYSQL_TYPE_DOUBLE, ==, param->type);
3480+ g_assert_cmpint(FALSE, ==, param->is_null);
3481+ {
3482+ double d;
3483+
3484+ g_assert_cmpint(0, ==, param->get_double(param, &d));
3485+ g_assert_cmpfloat(d, ==, 10.2);
3486+ };
3487+
3488+ /* (_FLOAT)10.2 */
3489+ param = g_ptr_array_index(cmd->params, param_ndx++);
3490+ g_assert(param);
3491+ g_assert_cmpint(MYSQL_TYPE_FLOAT, ==, param->type);
3492+ g_assert_cmpint(FALSE, ==, param->is_null);
3493+ {
3494+ double d;
3495+
3496+ g_assert_cmpint(0, ==, param->get_double(param, &d));
3497+ g_assert_cmpfloat(d, ==, (float)10.2);
3498+ };
3499+
3500+ /* (_DATE)2010-10-17 */
3501+ param = g_ptr_array_index(cmd->params, param_ndx++);
3502+ g_assert(param);
3503+ g_assert_cmpint(MYSQL_TYPE_DATE, ==, param->type);
3504+ g_assert_cmpint(FALSE, ==, param->is_null);
3505+ {
3506+ network_mysqld_type_date_t date;
3507+
3508+ g_assert_cmpint(0, ==, param->get_date(param, &date));
3509+ g_assert_cmpint(date.year, ==, 2010);
3510+ g_assert_cmpint(date.month, ==, 10);
3511+ g_assert_cmpint(date.day, ==, 17);
3512+
3513+ g_assert_cmpint(date.hour, ==, 0);
3514+ g_assert_cmpint(date.min, ==, 0);
3515+ g_assert_cmpint(date.sec, ==, 0);
3516+ g_assert_cmpint(date.nsec, ==, 0);
3517+ };
3518+
3519+ /* (_DATETIME)2010-10-17 19:27:30.000 010 */
3520+ param = g_ptr_array_index(cmd->params, param_ndx++);
3521+ g_assert(param);
3522+ g_assert_cmpint(MYSQL_TYPE_DATETIME, ==, param->type);
3523+ g_assert_cmpint(FALSE, ==, param->is_null);
3524+ {
3525+ network_mysqld_type_date_t date;
3526+
3527+ g_assert_cmpint(0, ==, param->get_date(param, &date));
3528+
3529+ g_assert_cmpint(date.year, ==, 2010);
3530+ g_assert_cmpint(date.month, ==, 10);
3531+ g_assert_cmpint(date.day, ==, 17);
3532+
3533+ g_assert_cmpint(date.hour, ==, 19);
3534+ g_assert_cmpint(date.min, ==, 27);
3535+ g_assert_cmpint(date.sec, ==, 30);
3536+ g_assert_cmpint(date.nsec, ==, 1);
3537+ };
3538+
3539+ /* (_TIMESTAMP)2010-10-17 19:27:30.000 010 */
3540+ param = g_ptr_array_index(cmd->params, param_ndx++);
3541+ g_assert(param);
3542+ g_assert_cmpint(MYSQL_TYPE_TIMESTAMP, ==, param->type);
3543+ g_assert_cmpint(FALSE, ==, param->is_null);
3544+ {
3545+ network_mysqld_type_date_t date;
3546+
3547+ g_assert_cmpint(0, ==, param->get_date(param, &date));
3548+ g_assert_cmpint(date.year, ==, 2010);
3549+ g_assert_cmpint(date.month, ==, 10);
3550+ g_assert_cmpint(date.day, ==, 17);
3551+
3552+ g_assert_cmpint(date.hour, ==, 19);
3553+ g_assert_cmpint(date.min, ==, 27);
3554+ g_assert_cmpint(date.sec, ==, 30);
3555+ g_assert_cmpint(date.nsec, ==, 1);
3556+ };
3557+
3558+ /* (_TIME)-120 19:27:30.000 010 */
3559+ param = g_ptr_array_index(cmd->params, param_ndx++);
3560+ g_assert(param);
3561+ g_assert_cmpint(MYSQL_TYPE_TIME, ==, param->type);
3562+ g_assert_cmpint(FALSE, ==, param->is_null);
3563+ {
3564+ network_mysqld_type_time_t t;
3565+
3566+ g_assert_cmpint(0, ==, param->get_time(param, &t));
3567+ g_assert_cmpint(t.sign, ==, 1);
3568+ g_assert_cmpint(t.days, ==, 120);
3569+
3570+ g_assert_cmpint(t.hour, ==, 19);
3571+ g_assert_cmpint(t.min, ==, 27);
3572+ g_assert_cmpint(t.sec, ==, 30);
3573+ g_assert_cmpint(t.nsec, ==, 1);
3574+ };
3575+
3576+ network_mysqld_stmt_execute_packet_free(cmd);
3577+}
3578+
3579+/**
3580+ * test if we decode all valid types from EXECUTE stmt
3581+ */
3582+static void t_com_stmt_execute_from_packet_invalid(void) {
3583+ network_mysqld_stmt_execute_packet_t *cmd;
3584+ const char raw_packet[] =
3585+ "\x12\x00\x00\x00"
3586+ "\x17" /* COM_STMT_EXECUTE */
3587+ "\x01\x00\x00\x00" /* stmt-id */
3588+ "\x00" /* flags */
3589+ "\x01\x00\x00\x00" /* iteration count */
3590+ "\x00"
3591+ "\x01"
3592+ "\x0f\x00"
3593+ "\x03\x66\x6f\x6f";
3594+
3595+ network_packet packet;
3596+ network_mysqld_type_t *param;
3597+ int param_ndx = 0;
3598+
3599+ packet.data = g_string_new_len(C(raw_packet));
3600+ packet.offset = 0;
3601+
3602+#define EXPECTED_NUM_PARAMS 1
3603+ cmd = network_mysqld_stmt_execute_packet_new();
3604+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3605+ g_assert_cmpint(0, !=, network_mysqld_proto_get_stmt_execute_packet(&packet, cmd, EXPECTED_NUM_PARAMS));
3606+#undef EXPECTED_NUM_PARAMS
3607+
3608+ network_mysqld_stmt_execute_packet_free(cmd);
3609+}
3610+
3611+/**
3612+ * if there are no parameters, we don't have any nul-flags to send
3613+ */
3614+static void t_com_stmt_execute_from_packet_no_params(void) {
3615+ network_mysqld_stmt_execute_packet_t *cmd;
3616+ const char raw_packet[] =
3617+ "\x0a\x00\x00\x00"
3618+ "\x17" /* COM_STMT_EXECUTE */
3619+ "\x01\x00\x00\x00" /* stmt-id */
3620+ "\x00" /* flags */
3621+ "\x01\x00\x00\x00" /* iteration count */
3622+ ;
3623+
3624+ network_packet packet;
3625+
3626+ packet.data = g_string_new_len(C(raw_packet));
3627+ packet.offset = 0;
3628+
3629+ cmd = network_mysqld_stmt_execute_packet_new();
3630+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3631+ g_assert_cmpint(0, ==, network_mysqld_proto_get_stmt_execute_packet(&packet, cmd, 0));
3632+ g_assert_cmpint(1, ==, cmd->stmt_id);
3633+ g_assert_cmpint(0, ==, cmd->flags);
3634+ g_assert_cmpint(1, ==, cmd->iteration_count);
3635+
3636+ network_mysqld_stmt_execute_packet_free(cmd);
3637+}
3638+
3639+/* COM_STMT_EXECUTE result */
3640+
3641+/**
3642+ * test if we parse all the fields of a COM_STMT_EXECUTE result correctly
3643+ */
3644+static void t_com_stmt_execute_result_from_packet(void) {
3645+ network_mysqld_eof_packet_t *eof;
3646+ network_mysqld_proto_fielddefs_t *coldefs;
3647+ network_mysqld_proto_fielddef_t *coldef;
3648+ network_mysqld_resultset_row_t *row;
3649+ network_mysqld_type_t *field;
3650+ GString *data;
3651+ guint64 field_count;
3652+ int packet_id = 0;
3653+
3654+ /* response for a
3655+ * SELECT ? AS col2, CONCAT(?, ?) AS col1
3656+ * with
3657+ * 1: NULL
3658+ * 2: STRING bar
3659+ * 3: STRING foo
3660+ */
3661+ strings packets[] = {
3662+ { C("\x01\x00\x00\x01\x02") },
3663+ { C("\x1a\x00\x00\x02\x03\x64\x65\x66\x00\x00\x00\x04\x63\x6f\x6c\x32\x00\x0c\x3f\x00\x00\x00\x00\x00\xfe\x80\x00\x00\x00\x00") },
3664+ { C("\x1a\x00\x00\x03\x03\x64\x65\x66\x00\x00\x00\x04\x63\x6f\x6c\x31\x00\x0c\x08\x00\x06\x00\x00\x00\xfd\x00\x00\x1f\x00\x00") },
3665+ { C("\x05\x00\x00\x04\xfe\x00\x00\x02\x00") },
3666+ { C("\x09\x00\x00\x05\x00\x04\x06" "barfoo") },
3667+ { C("\x05\x00\x00\x06\xfe\x00\x00\x02\x00") }
3668+
3669+ };
3670+ network_packet packet;
3671+
3672+ /* the field-count */
3673+ packet_id = 0;
3674+ packet.data = g_string_new_len(packets[packet_id].s, packets[packet_id].s_len);
3675+ packet.offset = 0;
3676+
3677+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3678+ g_assert_cmpint(0, ==, network_mysqld_proto_get_lenenc_int(&packet, &field_count));
3679+ g_assert_cmpint(2, ==, field_count);
3680+
3681+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3682+ g_string_free(packet.data, TRUE);
3683+
3684+
3685+ /* the colum defs */
3686+ packet_id++;
3687+ packet.data = g_string_new_len(packets[packet_id].s, packets[packet_id].s_len);
3688+ packet.offset = 0;
3689+
3690+ coldefs = network_mysqld_proto_fielddefs_new();
3691+ coldef = network_mysqld_proto_fielddef_new();
3692+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3693+ g_assert_cmpint(0, ==, network_mysqld_proto_get_fielddef(&packet, coldef, CLIENT_PROTOCOL_41));
3694+
3695+ g_ptr_array_add(coldefs, coldef);
3696+
3697+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3698+ g_string_free(packet.data, TRUE);
3699+
3700+ /* the string column */
3701+ packet_id++;
3702+ packet.data = g_string_new_len(packets[packet_id].s, packets[packet_id].s_len);
3703+ packet.offset = 0;
3704+
3705+ coldef = network_mysqld_proto_fielddef_new();
3706+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3707+ g_assert_cmpint(0, ==, network_mysqld_proto_get_fielddef(&packet, coldef, CLIENT_PROTOCOL_41));
3708+
3709+ g_ptr_array_add(coldefs, coldef);
3710+
3711+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3712+ g_string_free(packet.data, TRUE);
3713+
3714+ /* the EOF */
3715+ packet_id++;
3716+ packet.data = g_string_new_len(packets[packet_id].s, packets[packet_id].s_len);
3717+ packet.offset = 0;
3718+
3719+ eof = network_mysqld_eof_packet_new();
3720+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3721+ g_assert_cmpint(0, ==, network_mysqld_proto_get_eof_packet(&packet, eof));
3722+
3723+ network_mysqld_eof_packet_free(eof);
3724+
3725+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3726+ g_string_free(packet.data, TRUE);
3727+
3728+ /* the row */
3729+ packet_id++;
3730+ packet.data = g_string_new_len(packets[packet_id].s, packets[packet_id].s_len);
3731+ packet.offset = 0;
3732+
3733+ row = network_mysqld_resultset_row_new();
3734+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3735+ g_assert_cmpint(0, ==, network_mysqld_proto_get_binary_row(&packet, coldefs, row));
3736+
3737+ /* check if the 1st field is NULL */
3738+ field = g_ptr_array_index(row, 0);
3739+ g_assert(field);
3740+ g_assert_cmpint(TRUE, ==, field->is_null);
3741+
3742+ /* check if the 2nd field is "barfoo" */
3743+ field = g_ptr_array_index(row, 1);
3744+ g_assert(field);
3745+ g_assert_cmpint(MYSQL_TYPE_VAR_STRING, ==, field->type);
3746+ g_assert_cmpint(FALSE, ==, field->is_null);
3747+
3748+ /* FIXME: find a way to test this without touching the internal representation */
3749+ data = field->data;
3750+ g_assert(data);
3751+ g_assert_cmpint(data->len, ==, 6);
3752+ g_assert_cmpstr(data->str, ==, "barfoo");
3753+
3754+ network_mysqld_resultset_row_free(row);
3755+
3756+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3757+ g_string_free(packet.data, TRUE);
3758+
3759+ packet_id++;
3760+ packet.data = g_string_new_len(packets[packet_id].s, packets[packet_id].s_len);
3761+ packet.offset = 0;
3762+
3763+ eof = network_mysqld_eof_packet_new();
3764+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3765+ g_assert_cmpint(0, ==, network_mysqld_proto_get_eof_packet(&packet, eof));
3766+
3767+ network_mysqld_eof_packet_free(eof);
3768+
3769+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3770+ g_string_free(packet.data, TRUE);
3771+
3772+ network_mysqld_proto_fielddefs_free(coldefs);
3773+}
3774+
3775+/* COM_STMT_CLOSE */
3776+static void t_com_stmt_close_new(void) {
3777+ network_mysqld_stmt_close_packet_t *cmd;
3778+
3779+ cmd = network_mysqld_stmt_close_packet_new();
3780+ g_assert(cmd);
3781+
3782+ network_mysqld_stmt_close_packet_free(cmd);
3783+}
3784+
3785+static void t_com_stmt_close_from_packet(void) {
3786+ network_mysqld_stmt_close_packet_t *cmd;
3787+ const char raw_packet[] = "\x05\x00\x00\x00\x19\x01\x00\x00\x00";
3788+ network_packet packet;
3789+ packet.data = g_string_new_len(C(raw_packet));
3790+ packet.offset = 0;
3791+
3792+ cmd = network_mysqld_stmt_close_packet_new();
3793+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3794+ g_assert_cmpint(0, ==, network_mysqld_proto_get_stmt_close_packet(&packet, cmd));
3795+ g_assert_cmpint(1, ==, cmd->stmt_id);
3796+
3797+ network_mysqld_stmt_close_packet_free(cmd);
3798+}
3799+
3800
3801 /**
3802 * @cond
3803@@ -727,6 +1346,23 @@
3804 g_test_add_func("/core/resultset-fields-broken-proto-field-count-low", t_resultset_fields_parse_low);
3805 g_test_add_func("/core/resultset-fields-broken-proto-field-count-high", t_resultset_fields_parse_high);
3806
3807+ /* prepared statements */
3808+ g_test_add_func("/core/com_stmt_prepare_new", t_com_stmt_prepare_new);
3809+ g_test_add_func("/core/com_stmt_prepare_from_packet", t_com_stmt_prepare_from_packet);
3810+
3811+ g_test_add_func("/core/com_stmt_prepare_ok_new", t_com_stmt_prepare_ok_new);
3812+ g_test_add_func("/core/com_stmt_prepare_ok_from_packet", t_com_stmt_prepare_ok_from_packet);
3813+
3814+ g_test_add_func("/core/com_stmt_execute_new", t_com_stmt_execute_new);
3815+ g_test_add_func("/core/com_stmt_execute_from_packet", t_com_stmt_execute_from_packet);
3816+ g_test_add_func("/core/com_stmt_execute_from_packet_no_params", t_com_stmt_execute_from_packet_no_params);
3817+ g_test_add_func("/core/com_stmt_execute_from_packet_invalid", t_com_stmt_execute_from_packet_invalid);
3818+
3819+ g_test_add_func("/core/com_stmt_execute_result_from_packet", t_com_stmt_execute_result_from_packet);
3820+
3821+ g_test_add_func("/core/com_stmt_close_new", t_com_stmt_close_new);
3822+ g_test_add_func("/core/com_stmt_close_from_packet", t_com_stmt_close_from_packet);
3823+
3824 return g_test_run();
3825 }
3826 /** @endcond */
3827
3828=== added file 'tests/unit/t_network_mysqld_type.c'
3829--- tests/unit/t_network_mysqld_type.c 1970-01-01 00:00:00 +0000
3830+++ tests/unit/t_network_mysqld_type.c 2010-09-22 15:13:16 +0000
3831@@ -0,0 +1,205 @@
3832+/* $%BEGINLICENSE%$
3833+ Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
3834+
3835+ This program is free software; you can redistribute it and/or
3836+ modify it under the terms of the GNU General Public License as
3837+ published by the Free Software Foundation; version 2 of the
3838+ License.
3839+
3840+ This program is distributed in the hope that it will be useful,
3841+ but WITHOUT ANY WARRANTY; without even the implied warranty of
3842+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3843+ GNU General Public License for more details.
3844+
3845+ You should have received a copy of the GNU General Public License
3846+ along with this program; if not, write to the Free Software
3847+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
3848+ 02110-1301 USA
3849+
3850+ $%ENDLICENSE%$ */
3851+
3852+
3853+#include <stdio.h>
3854+#include <stdlib.h>
3855+#include <string.h>
3856+
3857+#include <glib.h>
3858+
3859+#include "network_mysqld_type.h"
3860+#include "glib-ext.h"
3861+#include "string-len.h"
3862+
3863+void t_proto_type_date_to_string(void) {
3864+ network_mysqld_type_t *type;
3865+ network_mysqld_type_date_t date;
3866+ const char *const_s;
3867+ char *s;
3868+ gsize s_len;
3869+ char static_s[NETWORK_MYSQLD_TYPE_DATE_MIN_BUF_LEN];
3870+
3871+ type = network_mysqld_type_new(MYSQL_TYPE_DATE);
3872+
3873+ memset(&date, 0, sizeof(date));
3874+ date.year = 2010;
3875+ date.month = 12;
3876+ date.day = 30;
3877+
3878+ date.hour = 19;
3879+ date.min = 27;
3880+ date.sec = 30;
3881+
3882+ date.nsec = 1;
3883+
3884+ g_assert_cmpint(0, ==, network_mysqld_type_set_date(type, &date));
3885+ g_assert_cmpint(-1, ==, network_mysqld_type_get_string_const(type, &const_s, &s_len)); /* it has no string backend, so it can't have a _const for us */
3886+
3887+ /* get a copy of the date, alloced */
3888+ s = NULL;
3889+ s_len = 0;
3890+ g_assert_cmpint(0, ==, network_mysqld_type_get_string(type, &s, &s_len));
3891+ g_assert_cmpint(10, ==, s_len);
3892+ g_assert_cmpstr("2010-12-30", ==, s);
3893+ g_free(s);
3894+
3895+ s = static_s;
3896+ s_len = sizeof(static_s);
3897+ g_assert_cmpint(0, ==, network_mysqld_type_get_string(type, &s, &s_len));
3898+ g_assert_cmpint(10, ==, s_len);
3899+ g_assert_cmpstr("2010-12-30", ==, s);
3900+
3901+ network_mysqld_type_free(type);
3902+}
3903+
3904+void t_proto_type_datetime_to_string(void) {
3905+ network_mysqld_type_t *type;
3906+ network_mysqld_type_date_t date;
3907+ const char *const_s;
3908+ char *s;
3909+ gsize s_len;
3910+ char static_s[NETWORK_MYSQLD_TYPE_DATETIME_MIN_BUF_LEN];
3911+
3912+ type = network_mysqld_type_new(MYSQL_TYPE_DATETIME);
3913+
3914+ memset(&date, 0, sizeof(date));
3915+ date.year = 2010;
3916+ date.month = 12;
3917+ date.day = 30;
3918+
3919+ date.hour = 19;
3920+ date.min = 27;
3921+ date.sec = 30;
3922+
3923+ date.nsec = 1;
3924+
3925+ g_assert_cmpint(0, ==, network_mysqld_type_set_date(type, &date));
3926+ g_assert_cmpint(-1, ==, network_mysqld_type_get_string_const(type, &const_s, &s_len)); /* it has no string backend, so it can't have a _const for us */
3927+
3928+ /* get a copy of the date, alloced */
3929+ s = NULL;
3930+ s_len = 0;
3931+ g_assert_cmpint(0, ==, network_mysqld_type_get_string(type, &s, &s_len));
3932+ g_assert_cmpint(29, ==, s_len);
3933+ g_assert_cmpstr("2010-12-30 19:27:30.000000001", ==, s);
3934+ g_free(s);
3935+
3936+ s = static_s;
3937+ s_len = sizeof(static_s);
3938+ g_assert_cmpint(0, ==, network_mysqld_type_get_string(type, &s, &s_len));
3939+ g_assert_cmpint(29, ==, s_len);
3940+ g_assert_cmpstr("2010-12-30 19:27:30.000000001", ==, s);
3941+
3942+ network_mysqld_type_free(type);
3943+}
3944+
3945+void t_proto_type_timestamp_to_string(void) {
3946+ network_mysqld_type_t *type;
3947+ network_mysqld_type_date_t date;
3948+ const char *const_s;
3949+ char *s;
3950+ gsize s_len;
3951+ char static_s[NETWORK_MYSQLD_TYPE_TIMESTAMP_MIN_BUF_LEN];
3952+
3953+ type = network_mysqld_type_new(MYSQL_TYPE_TIMESTAMP);
3954+
3955+ memset(&date, 0, sizeof(date));
3956+ date.year = 2010;
3957+ date.month = 12;
3958+ date.day = 30;
3959+
3960+ date.hour = 19;
3961+ date.min = 27;
3962+ date.sec = 30;
3963+
3964+ date.nsec = 1;
3965+
3966+ g_assert_cmpint(0, ==, network_mysqld_type_set_date(type, &date));
3967+ g_assert_cmpint(-1, ==, network_mysqld_type_get_string_const(type, &const_s, &s_len)); /* it has no string backend, so it can't have a _const for us */
3968+
3969+ /* get a copy of the date, alloced */
3970+ s = NULL;
3971+ s_len = 0;
3972+ g_assert_cmpint(0, ==, network_mysqld_type_get_string(type, &s, &s_len));
3973+ g_assert_cmpint(29, ==, s_len);
3974+ g_assert_cmpstr("2010-12-30 19:27:30.000000001", ==, s);
3975+ g_free(s);
3976+
3977+ s = static_s;
3978+ s_len = sizeof(static_s);
3979+ g_assert_cmpint(0, ==, network_mysqld_type_get_string(type, &s, &s_len));
3980+ g_assert_cmpint(29, ==, s_len);
3981+ g_assert_cmpstr("2010-12-30 19:27:30.000000001", ==, s);
3982+
3983+ network_mysqld_type_free(type);
3984+}
3985+
3986+void t_proto_type_time_to_string(void) {
3987+ network_mysqld_type_t *type;
3988+ network_mysqld_type_time_t t;
3989+ const char *const_s;
3990+ char *s;
3991+ gsize s_len;
3992+ char static_s[NETWORK_MYSQLD_TYPE_TIME_MIN_BUF_LEN];
3993+
3994+ type = network_mysqld_type_new(MYSQL_TYPE_TIME);
3995+
3996+ memset(&t, 0, sizeof(t));
3997+ t.sign = -1;
3998+ t.days = 120;
3999+ t.hour = 19;
4000+ t.min = 27;
4001+ t.sec = 30;
4002+ t.nsec = 1;
4003+
4004+ g_assert_cmpint(0, ==, network_mysqld_type_set_time(type, &t));
4005+ g_assert_cmpint(-1, ==, network_mysqld_type_get_string_const(type, &const_s, &s_len)); /* it has no string backend, so it can't have a _const for us */
4006+
4007+
4008+ /* get a copy of the time, alloced */
4009+ s = NULL;
4010+ s_len = 0;
4011+ g_assert_cmpint(0, ==, network_mysqld_type_get_string(type, &s, &s_len));
4012+ g_assert_cmpint(23, ==, s_len);
4013+ g_assert_cmpstr("-120 19:27:30.000000001", ==, s);
4014+ g_free(s);
4015+
4016+ s = static_s;
4017+ s_len = sizeof(static_s);
4018+ g_assert_cmpint(0, ==, network_mysqld_type_get_string(type, &s, &s_len));
4019+ g_assert_cmpint(23, ==, s_len);
4020+ g_assert_cmpstr("-120 19:27:30.000000001", ==, s);
4021+
4022+ network_mysqld_type_free(type);
4023+}
4024+
4025+int main(int argc, char **argv) {
4026+ g_test_init(&argc, &argv, NULL);
4027+ g_test_bug_base("http://bugs.mysql.com/");
4028+
4029+ g_test_add_func("/mysql-proto/type/time", t_proto_type_time_to_string);
4030+ g_test_add_func("/mysql-proto/type/datetime", t_proto_type_datetime_to_string);
4031+ g_test_add_func("/mysql-proto/type/timestamp", t_proto_type_timestamp_to_string);
4032+ g_test_add_func("/mysql-proto/type/date", t_proto_type_date_to_string);
4033+
4034+ return g_test_run();
4035+}
4036+

Subscribers

People subscribed via source and target branches