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: 4031 lines (+3578/-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 (+436/-0)
src/network_mysqld_proto_binary.h (+12/-0)
src/network_mysqld_type.c (+656/-0)
src/network_mysqld_type.h (+147/-0)
tests/unit/CMakeLists.txt (+2/-0)
tests/unit/Makefile.am (+18/-0)
tests/unit/lua/mysql-proto.lua (+70/-1)
tests/unit/t_network_mysqld_packet.c (+636/-0)
tests/unit/t_network_mysqld_type.c (+205/-0)
To merge this branch: bzr merge lp:~jan-kneschke/mysql-proxy/prep-stmt-codecs
Reviewer Review Type Date Requested Status
Registry Administrators Pending
Review via email: mp+36316@code.launchpad.net

This proposal supersedes a proposal from 2010-09-21.

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.
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:41:40 +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:41:40 +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:41:40 +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:41:40 +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:41:40 +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:41:40 +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:41:40 +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:41:40 +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:41:40 +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:41:40 +0000
1727@@ -0,0 +1,436 @@
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+ err = err || network_mysqld_type_set_double(type, double_copy.d);
1849+
1850+ return err ? -1 : 0;
1851+}
1852+
1853+static int network_mysqld_proto_binary_append_double_type(GString *packet, network_mysqld_type_t *type) {
1854+ union {
1855+ double d;
1856+ char d_char_shadow[sizeof(double)];
1857+ } double_copy;
1858+ int err = 0;
1859+
1860+ err = err || network_mysqld_type_get_double(type, &double_copy.d);
1861+ if (0 != err) return -1;
1862+
1863+ g_string_append_len(packet, double_copy.d_char_shadow, sizeof(double));
1864+
1865+ return err ? -1 : 0;
1866+}
1867+
1868+/* float */
1869+static int network_mysqld_proto_binary_get_float_type(network_packet *packet, network_mysqld_type_t *type) {
1870+ int err = 0;
1871+ union {
1872+ float d;
1873+ char d_char_shadow[sizeof(float) + 1];
1874+ } float_copy;
1875+
1876+ GString s;
1877+ s.str = float_copy.d_char_shadow;
1878+ s.len = 0;
1879+ s.allocated_len = sizeof(float_copy.d_char_shadow);
1880+
1881+ err = err || network_mysqld_proto_get_gstring_len(packet, sizeof(float), &s);
1882+ err = err || network_mysqld_type_set_double(type, (double)float_copy.d);
1883+
1884+ return err ? -1 : 0;
1885+}
1886+
1887+static int network_mysqld_proto_binary_append_float_type(GString *packet, network_mysqld_type_t *type) {
1888+ double d;
1889+ int err = 0;
1890+
1891+ err = err || network_mysqld_type_get_double(type, &d); /* get our float as double */
1892+
1893+ if (0 == err) {
1894+ /* copy the float directly without switching byte-order */
1895+ union {
1896+ float f;
1897+ char f_char_shadow[sizeof(float)];
1898+ } float_copy; /* shadow the float with a equally sized char to be able to copy it without extra type-casting */
1899+
1900+ float_copy.f = (float)d;
1901+
1902+ g_string_append_len(packet, float_copy.f_char_shadow, sizeof(float));
1903+ }
1904+
1905+ return err ? -1 : 0;
1906+}
1907+
1908+/* all kinds of strings */
1909+static int network_mysqld_proto_binary_get_string_type(network_packet *packet, network_mysqld_type_t *type) {
1910+ GString *str;
1911+ int err = 0;
1912+
1913+ str = g_string_new(NULL);
1914+
1915+ err = err || network_mysqld_proto_get_lenenc_gstring(packet, str);
1916+
1917+ network_mysqld_type_set_string(type, S(str));
1918+
1919+ g_string_free(str, TRUE);
1920+
1921+ return err ? -1 : 0;
1922+}
1923+
1924+static int network_mysqld_proto_binary_append_string_type(GString *packet, network_mysqld_type_t *type) {
1925+ const char *s;
1926+ gsize s_len;
1927+ int err = 0;
1928+
1929+ err = err || network_mysqld_type_get_string_const(type, &s, &s_len);
1930+ err = err || network_mysqld_proto_append_lenenc_string_len(packet, s, s_len);
1931+
1932+ return err ? -1 : 0;
1933+}
1934+
1935+/* all kinds of time */
1936+
1937+/**
1938+ * extract the date from a binary resultset row
1939+ */
1940+static int network_mysqld_proto_binary_get_date_type(network_packet *packet, network_mysqld_type_t *type) {
1941+ int err = 0;
1942+ guint8 len;
1943+ network_mysqld_type_date_t date;
1944+
1945+ err = err || network_mysqld_proto_get_int8(packet, &len);
1946+
1947+ /* check the valid lengths
1948+ */
1949+ switch (len) {
1950+ case 11: /* date + time + ms */
1951+ case 7: /* date + time ( ms is .0000 ) */
1952+ case 4: /* date ( time is 00:00:00 )*/
1953+ case 0: /* date == 0000-00-00 */
1954+ break;
1955+ default:
1956+ return -1;
1957+ }
1958+
1959+ memset(&date, 0, sizeof(date));
1960+ if (len > 0) {
1961+ err = err || network_mysqld_proto_get_int16(packet, &date.year);
1962+ err = err || network_mysqld_proto_get_int8(packet, &date.month);
1963+ err = err || network_mysqld_proto_get_int8(packet, &date.day);
1964+
1965+ if (len > 4) {
1966+ err = err || network_mysqld_proto_get_int8(packet, &date.hour);
1967+ err = err || network_mysqld_proto_get_int8(packet, &date.min);
1968+ err = err || network_mysqld_proto_get_int8(packet, &date.sec);
1969+
1970+ if (len > 7) {
1971+ err = err || network_mysqld_proto_get_int32(packet, &date.nsec);
1972+ }
1973+ }
1974+ }
1975+
1976+ if (0 == err) {
1977+ err = err || network_mysqld_type_set_date(type, &date);
1978+ }
1979+
1980+ return err ? -1 : 0;
1981+}
1982+
1983+static int network_mysqld_proto_binary_append_date_type(GString G_GNUC_UNUSED *packet, network_mysqld_type_t G_GNUC_UNUSED *type) {
1984+ /* not implemented yet */
1985+ return -1;
1986+}
1987+
1988+/**
1989+ * extract the time from a binary resultset row
1990+ */
1991+static int network_mysqld_proto_binary_get_time_type(network_packet *packet, network_mysqld_type_t *type) {
1992+ int err = 0;
1993+ guint8 len;
1994+ network_mysqld_type_time_t t;
1995+
1996+ err = err || network_mysqld_proto_get_int8(packet, &len);
1997+
1998+ /* check the valid lengths
1999+ */
2000+ switch (len) {
2001+ case 12: /* day + time + ms */
2002+ case 8: /* day + time ( ms is .0000 ) */
2003+ case 0: /* time == 00:00:00 */
2004+ break;
2005+ default:
2006+ return -1;
2007+ }
2008+
2009+ memset(&t, 0, sizeof(t));
2010+ if (len > 0) {
2011+ err = err || network_mysqld_proto_get_int8(packet, &t.sign);
2012+ err = err || network_mysqld_proto_get_int32(packet, &t.days);
2013+
2014+ err = err || network_mysqld_proto_get_int8(packet, &t.hour);
2015+ err = err || network_mysqld_proto_get_int8(packet, &t.min);
2016+ err = err || network_mysqld_proto_get_int8(packet, &t.sec);
2017+
2018+ if (len > 8) {
2019+ err = err || network_mysqld_proto_get_int32(packet, &t.nsec);
2020+ }
2021+ }
2022+
2023+ if (0 == err) {
2024+ err = err || network_mysqld_type_set_time(type, &t);
2025+ }
2026+
2027+ return err ? -1 : 0;
2028+}
2029+
2030+static int network_mysqld_proto_binary_append_time_type(GString G_GNUC_UNUSED *packet, network_mysqld_type_t G_GNUC_UNUSED *type) {
2031+ /* not implemented yet */
2032+ return -1;
2033+}
2034+
2035+/**
2036+ * valid types for prepared statements parameters we receive from the client
2037+ */
2038+gboolean network_mysql_proto_binary_type_is_valid_input(enum enum_field_types field_type) {
2039+ switch (field_type) {
2040+ case MYSQL_TYPE_TINY:
2041+ case MYSQL_TYPE_SHORT:
2042+ case MYSQL_TYPE_LONG:
2043+ case MYSQL_TYPE_LONGLONG:
2044+
2045+ case MYSQL_TYPE_FLOAT:
2046+ case MYSQL_TYPE_DOUBLE:
2047+
2048+ case MYSQL_TYPE_BLOB:
2049+ case MYSQL_TYPE_STRING:
2050+
2051+ case MYSQL_TYPE_DATE:
2052+ case MYSQL_TYPE_DATETIME:
2053+ case MYSQL_TYPE_TIME:
2054+ case MYSQL_TYPE_TIMESTAMP:
2055+
2056+ case MYSQL_TYPE_NULL:
2057+ return TRUE;
2058+ default:
2059+ return FALSE;
2060+ }
2061+}
2062+
2063+/**
2064+ * types we allow the send back to the client
2065+ */
2066+gboolean network_mysql_proto_binary_is_valid_output(enum enum_field_types field_type) {
2067+ switch (field_type) {
2068+ case MYSQL_TYPE_TINY:
2069+ case MYSQL_TYPE_SHORT:
2070+ case MYSQL_TYPE_INT24:
2071+ case MYSQL_TYPE_LONG:
2072+ case MYSQL_TYPE_LONGLONG:
2073+
2074+ case MYSQL_TYPE_FLOAT:
2075+ case MYSQL_TYPE_DOUBLE:
2076+ case MYSQL_TYPE_NEWDECIMAL:
2077+
2078+ case MYSQL_TYPE_TINY_BLOB:
2079+ case MYSQL_TYPE_BLOB:
2080+ case MYSQL_TYPE_MEDIUM_BLOB:
2081+ case MYSQL_TYPE_LONG_BLOB:
2082+ case MYSQL_TYPE_STRING:
2083+ case MYSQL_TYPE_VAR_STRING:
2084+
2085+ case MYSQL_TYPE_DATE:
2086+ case MYSQL_TYPE_DATETIME:
2087+ case MYSQL_TYPE_TIME:
2088+ case MYSQL_TYPE_TIMESTAMP:
2089+
2090+ case MYSQL_TYPE_BIT:
2091+ return TRUE;
2092+ default:
2093+ return FALSE;
2094+ }
2095+}
2096+
2097+int network_mysqld_proto_binary_get_type(network_packet *packet, network_mysqld_type_t *type) {
2098+ switch (type->type) {
2099+ case MYSQL_TYPE_TINY:
2100+ case MYSQL_TYPE_SHORT:
2101+ case MYSQL_TYPE_LONG:
2102+ case MYSQL_TYPE_INT24:
2103+ case MYSQL_TYPE_LONGLONG:
2104+ return network_mysqld_proto_binary_get_int_type(packet, type);
2105+ case MYSQL_TYPE_DATE:
2106+ case MYSQL_TYPE_DATETIME:
2107+ case MYSQL_TYPE_TIMESTAMP:
2108+ return network_mysqld_proto_binary_get_date_type(packet, type);
2109+ case MYSQL_TYPE_TIME:
2110+ return network_mysqld_proto_binary_get_time_type(packet, type);
2111+ case MYSQL_TYPE_FLOAT:
2112+ return network_mysqld_proto_binary_get_float_type(packet, type);
2113+ case MYSQL_TYPE_DOUBLE:
2114+ return network_mysqld_proto_binary_get_double_type(packet, type);
2115+ case MYSQL_TYPE_BIT:
2116+ case MYSQL_TYPE_NEWDECIMAL:
2117+ case MYSQL_TYPE_BLOB:
2118+ case MYSQL_TYPE_TINY_BLOB:
2119+ case MYSQL_TYPE_MEDIUM_BLOB:
2120+ case MYSQL_TYPE_LONG_BLOB:
2121+ case MYSQL_TYPE_STRING:
2122+ case MYSQL_TYPE_VAR_STRING:
2123+ /* they are all length-encoded strings */
2124+ return network_mysqld_proto_binary_get_string_type(packet, type);
2125+ }
2126+
2127+ return -1;
2128+}
2129+
2130+int network_mysqld_proto_binary_append_type(GString *packet, network_mysqld_type_t *type) {
2131+ switch (type->type) {
2132+ case MYSQL_TYPE_TINY:
2133+ case MYSQL_TYPE_SHORT:
2134+ case MYSQL_TYPE_LONG:
2135+ case MYSQL_TYPE_INT24:
2136+ case MYSQL_TYPE_LONGLONG:
2137+ return network_mysqld_proto_binary_append_int_type(packet, type);
2138+ case MYSQL_TYPE_DATE:
2139+ case MYSQL_TYPE_DATETIME:
2140+ case MYSQL_TYPE_TIMESTAMP:
2141+ return network_mysqld_proto_binary_append_date_type(packet, type);
2142+ case MYSQL_TYPE_TIME:
2143+ return network_mysqld_proto_binary_append_time_type(packet, type);
2144+ case MYSQL_TYPE_FLOAT:
2145+ return network_mysqld_proto_binary_append_float_type(packet, type);
2146+ case MYSQL_TYPE_DOUBLE:
2147+ return network_mysqld_proto_binary_append_double_type(packet, type);
2148+ case MYSQL_TYPE_BIT:
2149+ case MYSQL_TYPE_NEWDECIMAL:
2150+ case MYSQL_TYPE_BLOB:
2151+ case MYSQL_TYPE_TINY_BLOB:
2152+ case MYSQL_TYPE_MEDIUM_BLOB:
2153+ case MYSQL_TYPE_LONG_BLOB:
2154+ case MYSQL_TYPE_STRING:
2155+ case MYSQL_TYPE_VAR_STRING:
2156+ /* they are all length-encoded strings */
2157+ return network_mysqld_proto_binary_append_string_type(packet, type);
2158+ }
2159+
2160+ return -1;
2161+}
2162+
2163+
2164
2165=== added file 'src/network_mysqld_proto_binary.h'
2166--- src/network_mysqld_proto_binary.h 1970-01-01 00:00:00 +0000
2167+++ src/network_mysqld_proto_binary.h 2010-09-22 15:41:40 +0000
2168@@ -0,0 +1,12 @@
2169+#ifndef __NETWORK_MYSQLD_PROTO_BINARY_H__
2170+#define __NETWORK_MYSQLD_PROTO_BINARY_H__
2171+
2172+#include <glib.h>
2173+
2174+#include "network-socket.h"
2175+#include "network_mysqld_type.h"
2176+
2177+int network_mysqld_proto_binary_get_type(network_packet *packet, network_mysqld_type_t *type);
2178+int network_mysqld_proto_binary_append_type(GString *packet, network_mysqld_type_t *type);
2179+
2180+#endif
2181
2182=== added file 'src/network_mysqld_type.c'
2183--- src/network_mysqld_type.c 1970-01-01 00:00:00 +0000
2184+++ src/network_mysqld_type.c 2010-09-22 15:41:40 +0000
2185@@ -0,0 +1,656 @@
2186+#include <string.h>
2187+#include <stdlib.h>
2188+#include <stdio.h>
2189+
2190+#include <glib.h>
2191+
2192+#include "network_mysqld_type.h"
2193+#include "string-len.h"
2194+
2195+#include "glib-ext.h"
2196+
2197+/* expose the types itself and their internal representation */
2198+
2199+typedef double network_mysqld_type_double_t;
2200+
2201+typedef float network_mysqld_type_float_t;
2202+
2203+typedef GString network_mysqld_type_string_t;
2204+
2205+typedef struct {
2206+ guint64 i;
2207+ gboolean is_unsigned;
2208+} network_mysqld_type_int_t;
2209+
2210+/**
2211+ * create a type that can hold a MYSQL_TYPE_LONGLONG
2212+ */
2213+static network_mysqld_type_int_t *network_mysqld_type_int_new(void) {
2214+ network_mysqld_type_int_t *ll;
2215+
2216+ ll = g_slice_new0(network_mysqld_type_int_t);
2217+
2218+ return ll;
2219+}
2220+
2221+/**
2222+ * free a network_mysqld_type_int_t
2223+ */
2224+static void network_mysqld_type_int_free(network_mysqld_type_int_t *ll) {
2225+ if (NULL == ll) return;
2226+
2227+ g_slice_free(network_mysqld_type_int_t, ll);
2228+}
2229+
2230+static int network_mysqld_type_data_int_get_int(network_mysqld_type_t *type, guint64 *i, gboolean *is_unsigned) {
2231+ network_mysqld_type_int_t *value;
2232+
2233+ if (NULL == type->data) return -1;
2234+
2235+ value = type->data;
2236+
2237+ *i = value->i;
2238+ *is_unsigned = value->is_unsigned;
2239+
2240+ return 0;
2241+}
2242+
2243+static int network_mysqld_type_data_int_set_int(network_mysqld_type_t *type, guint64 i, gboolean is_unsigned) {
2244+ network_mysqld_type_int_t *value;
2245+
2246+ if (NULL == type->data) {
2247+ type->data = network_mysqld_type_int_new();
2248+ }
2249+ value = type->data;
2250+
2251+ value->i = i;
2252+ value->is_unsigned = is_unsigned;
2253+
2254+ return 0;
2255+}
2256+
2257+
2258+/**
2259+ * typesafe wrapper for network_mysqld_type_new()
2260+ */
2261+static void network_mysqld_type_data_int_free(network_mysqld_type_t *type) {
2262+ if (NULL == type) return;
2263+ if (NULL == type->data) return;
2264+
2265+ network_mysqld_type_int_free(type->data);
2266+}
2267+
2268+static void network_mysqld_type_data_int_init(network_mysqld_type_t *type, enum enum_field_types field_type) {
2269+ type->type = field_type;
2270+ type->free_data = network_mysqld_type_data_int_free;
2271+ type->get_int = network_mysqld_type_data_int_get_int;
2272+ type->set_int = network_mysqld_type_data_int_set_int;
2273+}
2274+
2275+/* MYSQL_TYPE_DOUBLE */
2276+
2277+/**
2278+ * create a type that can hold a MYSQL_TYPE_DOUBLE
2279+ */
2280+static network_mysqld_type_double_t *network_mysqld_type_double_new(void) {
2281+ network_mysqld_type_double_t *t;
2282+
2283+ t = g_slice_new0(network_mysqld_type_double_t);
2284+
2285+ return t;
2286+}
2287+
2288+/**
2289+ * free a network_mysqld_type_double_t
2290+ */
2291+static void network_mysqld_type_double_free(network_mysqld_type_double_t *t) {
2292+ if (NULL == t) return;
2293+
2294+ g_slice_free(network_mysqld_type_double_t, t);
2295+}
2296+
2297+static void network_mysqld_type_data_double_free(network_mysqld_type_t *type) {
2298+ if (NULL == type) return;
2299+ if (NULL == type->data) return;
2300+
2301+ network_mysqld_type_double_free(type->data);
2302+}
2303+
2304+static int network_mysqld_type_data_double_get_double(network_mysqld_type_t *type, double *d) {
2305+ network_mysqld_type_double_t *value = type->data;
2306+
2307+ if (NULL == value) return -1;
2308+
2309+ *d = *value;
2310+
2311+ return 0;
2312+}
2313+
2314+static int network_mysqld_type_data_double_set_double(network_mysqld_type_t *type, double d) {
2315+ network_mysqld_type_double_t *value;
2316+
2317+ if (NULL == type->data) {
2318+ type->data = network_mysqld_type_double_new();
2319+ }
2320+
2321+ value = type->data;
2322+ *value = d;
2323+
2324+ return 0;
2325+}
2326+
2327+static void network_mysqld_type_data_double_init(network_mysqld_type_t *type, enum enum_field_types field_type) {
2328+ type->type = field_type;
2329+ type->free_data = network_mysqld_type_data_double_free;
2330+ type->get_double = network_mysqld_type_data_double_get_double;
2331+ type->set_double = network_mysqld_type_data_double_set_double;
2332+}
2333+
2334+/* MYSQL_TYPE_FLOAT */
2335+
2336+/**
2337+ * create a type that can hold a MYSQL_TYPE_FLOAT
2338+ */
2339+
2340+static network_mysqld_type_float_t *network_mysqld_type_float_new(void) {
2341+ network_mysqld_type_float_t *t;
2342+
2343+ t = g_slice_new0(network_mysqld_type_float_t);
2344+
2345+ return t;
2346+}
2347+
2348+/**
2349+ * free a network_mysqld_type_float_t
2350+ */
2351+static void network_mysqld_type_float_free(network_mysqld_type_float_t *t) {
2352+ if (NULL == t) return;
2353+
2354+ g_slice_free(network_mysqld_type_float_t, t);
2355+}
2356+
2357+static void network_mysqld_type_data_float_free(network_mysqld_type_t *type) {
2358+ if (NULL == type) return;
2359+ if (NULL == type->data) return;
2360+
2361+ network_mysqld_type_float_free(type->data);
2362+}
2363+
2364+static int network_mysqld_type_data_float_get_double(network_mysqld_type_t *type, double *dst) {
2365+ network_mysqld_type_float_t *src = type->data;
2366+
2367+ if (NULL == type->data) return -1;
2368+
2369+ *dst = (double)*src;
2370+
2371+ return 0;
2372+}
2373+
2374+static int network_mysqld_type_data_float_set_double(network_mysqld_type_t *type, double src) {
2375+ network_mysqld_type_float_t *dst = type->data;
2376+
2377+ if (NULL == type->data) {
2378+ type->data = network_mysqld_type_float_new();
2379+ }
2380+
2381+ dst = type->data;
2382+ *dst = (float)src;
2383+
2384+ return 0;
2385+}
2386+
2387+static void network_mysqld_type_data_float_init(network_mysqld_type_t *type, enum enum_field_types field_type) {
2388+ type->type = field_type;
2389+ type->free_data = network_mysqld_type_data_float_free;
2390+ type->get_double = network_mysqld_type_data_float_get_double;
2391+ type->set_double = network_mysqld_type_data_float_set_double;
2392+}
2393+
2394+/* MYSQL_TYPE_STRING */
2395+static network_mysqld_type_string_t *network_mysqld_type_string_new(void) {
2396+ network_mysqld_type_string_t *str;
2397+
2398+ str = g_string_new(NULL);
2399+
2400+ return str;
2401+}
2402+
2403+static void network_mysqld_type_string_free(network_mysqld_type_string_t *str) {
2404+ if (NULL == str) return;
2405+
2406+ g_string_free(str, TRUE);
2407+}
2408+
2409+static void network_mysqld_type_data_string_free(network_mysqld_type_t *type) {
2410+ if (NULL == type) return;
2411+
2412+ network_mysqld_type_string_free(type->data);
2413+}
2414+
2415+static int network_mysqld_type_data_string_get_string_const(network_mysqld_type_t *type, const char **dst, gsize *dst_len) {
2416+ GString *src = type->data;
2417+
2418+ if (NULL == type->data) return -1;
2419+
2420+ *dst = src->str;
2421+ *dst_len = src->len;
2422+
2423+ return 0;
2424+}
2425+
2426+static int network_mysqld_type_data_string_set_string(network_mysqld_type_t *type, const char *src, gsize src_len) {
2427+ GString *dst;
2428+
2429+ if (NULL == type->data) {
2430+ type->data = g_string_sized_new(src_len);
2431+ }
2432+
2433+ dst = type->data;
2434+
2435+ g_string_assign_len(dst, src, src_len);
2436+
2437+ return 0;
2438+}
2439+
2440+static void network_mysqld_type_data_string_init(network_mysqld_type_t *type, enum enum_field_types field_type) {
2441+ type->type = field_type;
2442+ type->free_data = network_mysqld_type_data_string_free;
2443+ type->get_string_const = network_mysqld_type_data_string_get_string_const;
2444+ type->set_string = network_mysqld_type_data_string_set_string;
2445+}
2446+
2447+/* MYSQL_TYPE_DATE */
2448+static network_mysqld_type_date_t *network_mysqld_type_date_new(void) {
2449+ network_mysqld_type_date_t *date;
2450+
2451+ date = g_slice_new0(network_mysqld_type_date_t);
2452+
2453+ return date;
2454+}
2455+
2456+static void network_mysqld_type_date_free(network_mysqld_type_date_t *date) {
2457+ if (NULL == date) return;
2458+
2459+ g_slice_free(network_mysqld_type_date_t, date);
2460+}
2461+
2462+static void network_mysqld_type_data_date_free(network_mysqld_type_t *type) {
2463+ if (NULL == type) return;
2464+
2465+ network_mysqld_type_date_free(type->data);
2466+}
2467+
2468+static int network_mysqld_type_data_date_get_date(network_mysqld_type_t *type, network_mysqld_type_date_t *dst) {
2469+ network_mysqld_type_date_t *src = type->data;
2470+
2471+ if (NULL == type->data) return -1;
2472+
2473+ memcpy(dst, src, sizeof(*src));
2474+
2475+ return 0;
2476+}
2477+
2478+static gboolean network_mysqld_type_date_time_is_valid(network_mysqld_type_date_t *date) {
2479+ return (date->nsec < 1000000000 &&
2480+ date->sec < 100 &&
2481+ date->min <= 60 &&
2482+ date->hour <= 24);
2483+}
2484+
2485+static gboolean network_mysqld_type_date_date_is_valid(network_mysqld_type_date_t *date) {
2486+ return (date->day <= 31 &&
2487+ date->month <= 12 &&
2488+ date->year <= 9999);
2489+}
2490+
2491+gboolean network_mysqld_type_date_is_valid(network_mysqld_type_date_t *date) {
2492+ return network_mysqld_type_date_time_is_valid(date) &&
2493+ network_mysqld_type_date_date_is_valid(date);
2494+}
2495+
2496+static int network_mysqld_type_data_date_get_string(network_mysqld_type_t *type, char **dst, gsize *dst_len) {
2497+ network_mysqld_type_date_t *src = type->data;
2498+
2499+ if (NULL == type->data) return -1;
2500+
2501+ switch (type->type) {
2502+ case MYSQL_TYPE_DATE:
2503+ if (!network_mysqld_type_date_date_is_valid(src)) {
2504+ return -1;
2505+ }
2506+ break;
2507+ case MYSQL_TYPE_DATETIME:
2508+ case MYSQL_TYPE_TIMESTAMP:
2509+ if (!network_mysqld_type_date_is_valid(src)) {
2510+ return -1;
2511+ }
2512+ break;
2513+ default:
2514+ /* we shouldn't be here */
2515+ return -1;
2516+ }
2517+
2518+ if (NULL != *dst) {
2519+ switch (type->type) {
2520+ case MYSQL_TYPE_DATE:
2521+ /* dst_len already contains a size and we don't have to alloc */
2522+ if (*dst_len < NETWORK_MYSQLD_TYPE_DATE_MIN_BUF_LEN) {
2523+ return -1; /* ... but it is too small .. we could return the right size here */
2524+ }
2525+ *dst_len = snprintf(*dst, *dst_len, "%04u-%02u-%02u",
2526+ src->year,
2527+ src->month,
2528+ src->day);
2529+ break;
2530+ case MYSQL_TYPE_DATETIME:
2531+ case MYSQL_TYPE_TIMESTAMP:
2532+ /* dst_len already contains a size and we don't have to alloc */
2533+ if (*dst_len < NETWORK_MYSQLD_TYPE_DATETIME_MIN_BUF_LEN) {
2534+ return -1; /* ... but it is too small .. we could return the right size here */
2535+ }
2536+ *dst_len = snprintf(*dst, *dst_len, "%04u-%02u-%02u %02u:%02u:%02u.%09u",
2537+ src->year,
2538+ src->month,
2539+ src->day,
2540+ src->hour,
2541+ src->min,
2542+ src->sec,
2543+ src->nsec);
2544+ break;
2545+ default:
2546+ g_assert_not_reached();
2547+ break;
2548+ }
2549+ } else {
2550+ switch (type->type) {
2551+ case MYSQL_TYPE_DATE:
2552+ *dst = g_strdup_printf("%04u-%02u-%02u",
2553+ src->year,
2554+ src->month,
2555+ src->day);
2556+ *dst_len = strlen(*dst);
2557+ break;
2558+ case MYSQL_TYPE_DATETIME:
2559+ case MYSQL_TYPE_TIMESTAMP:
2560+ *dst = g_strdup_printf("%04u-%02u-%02u %02u:%02u:%02u.%09u",
2561+ src->year,
2562+ src->month,
2563+ src->day,
2564+ src->hour,
2565+ src->min,
2566+ src->sec,
2567+ src->nsec);
2568+ *dst_len = strlen(*dst);
2569+ break;
2570+ default:
2571+ g_assert_not_reached();
2572+ break;
2573+ }
2574+ }
2575+
2576+ return 0;
2577+}
2578+
2579+
2580+static int network_mysqld_type_data_date_set_date(network_mysqld_type_t *type, network_mysqld_type_date_t *src) {
2581+ network_mysqld_type_date_t *dst;
2582+
2583+ if (NULL == type->data) {
2584+ type->data = network_mysqld_type_date_new();
2585+ }
2586+
2587+ dst = type->data;
2588+
2589+ memcpy(dst, src, sizeof(*src));
2590+
2591+ return 0;
2592+}
2593+
2594+static void network_mysqld_type_data_date_init(network_mysqld_type_t *type, enum enum_field_types field_type) {
2595+ type->type = field_type;
2596+ type->free_data = network_mysqld_type_data_date_free;
2597+ type->get_date = network_mysqld_type_data_date_get_date;
2598+ type->get_string = network_mysqld_type_data_date_get_string;
2599+ type->set_date = network_mysqld_type_data_date_set_date;
2600+}
2601+
2602+
2603+/* MYSQL_TYPE_TIME */
2604+static network_mysqld_type_time_t *network_mysqld_type_time_new(void) {
2605+ network_mysqld_type_time_t *t;
2606+
2607+ t = g_slice_new0(network_mysqld_type_time_t);
2608+
2609+ return t;
2610+}
2611+
2612+static void network_mysqld_type_time_free(network_mysqld_type_time_t *t) {
2613+ if (NULL == t) return;
2614+
2615+ g_slice_free(network_mysqld_type_time_t, t);
2616+}
2617+
2618+static void network_mysqld_type_data_time_free(network_mysqld_type_t *type) {
2619+ if (NULL == type) return;
2620+
2621+ network_mysqld_type_time_free(type->data);
2622+}
2623+
2624+static int network_mysqld_type_data_time_get_time(network_mysqld_type_t *type, network_mysqld_type_time_t *dst) {
2625+ network_mysqld_type_time_t *src = type->data;
2626+
2627+ if (NULL == type->data) return -1;
2628+
2629+ memcpy(dst, src, sizeof(*src));
2630+
2631+ return 0;
2632+}
2633+
2634+static int network_mysqld_type_data_time_get_string(network_mysqld_type_t *type, char **dst, gsize *dst_len) {
2635+ network_mysqld_type_time_t *src = type->data;
2636+
2637+ if (NULL == type->data) return -1;
2638+
2639+ if (NULL != *dst) {
2640+ /* dst_len already contains a size and we don't have to alloc */
2641+ if (*dst_len < NETWORK_MYSQLD_TYPE_TIME_MIN_BUF_LEN) {
2642+ return -1; /* ... but it is too small .. we could return the right size here */
2643+ }
2644+ *dst_len = snprintf(*dst, *dst_len, "%s%d %02u:%02u:%02u.%09u",
2645+ src->sign ? "-" : "",
2646+ src->days,
2647+ src->hour,
2648+ src->min,
2649+ src->sec,
2650+ src->nsec);
2651+ } else {
2652+ *dst = g_strdup_printf("%s%d %02u:%02u:%02u.%09u",
2653+ src->sign ? "-" : "",
2654+ src->days,
2655+ src->hour,
2656+ src->min,
2657+ src->sec,
2658+ src->nsec);
2659+ *dst_len = strlen(*dst);
2660+ }
2661+
2662+ return 0;
2663+}
2664+
2665+static int network_mysqld_type_data_time_set_time(network_mysqld_type_t *type, network_mysqld_type_time_t *src) {
2666+ network_mysqld_type_date_t *dst;
2667+
2668+ if (NULL == type->data) {
2669+ type->data = network_mysqld_type_time_new();
2670+ }
2671+ dst = type->data;
2672+
2673+ memcpy(dst, src, sizeof(*src));
2674+
2675+ return 0;
2676+}
2677+
2678+
2679+static void network_mysqld_type_data_time_init(network_mysqld_type_t *type, enum enum_field_types field_type) {
2680+ type->type = field_type;
2681+ type->free_data = network_mysqld_type_data_time_free;
2682+ type->get_time = network_mysqld_type_data_time_get_time;
2683+ type->get_string = network_mysqld_type_data_time_get_string;
2684+ type->set_time = network_mysqld_type_data_time_set_time;
2685+}
2686+
2687+
2688+/**
2689+ * create a type
2690+ */
2691+network_mysqld_type_t *network_mysqld_type_new(enum enum_field_types field_type) {
2692+ network_mysqld_type_t *type = NULL;
2693+
2694+ switch (field_type) {
2695+ case MYSQL_TYPE_TINY:
2696+ case MYSQL_TYPE_SHORT:
2697+ case MYSQL_TYPE_LONG:
2698+ case MYSQL_TYPE_INT24:
2699+ case MYSQL_TYPE_LONGLONG:
2700+ type = g_slice_new0(network_mysqld_type_t);
2701+
2702+ network_mysqld_type_data_int_init(type, field_type);
2703+ break;
2704+ case MYSQL_TYPE_FLOAT: /* 4 bytes */
2705+ type = g_slice_new0(network_mysqld_type_t);
2706+
2707+ network_mysqld_type_data_float_init(type, field_type);
2708+ break;
2709+ case MYSQL_TYPE_DOUBLE: /* 8 bytes */
2710+ type = g_slice_new0(network_mysqld_type_t);
2711+
2712+ network_mysqld_type_data_double_init(type, field_type);
2713+ break;
2714+ case MYSQL_TYPE_DATETIME:
2715+ case MYSQL_TYPE_DATE:
2716+ case MYSQL_TYPE_TIMESTAMP:
2717+ type = g_slice_new0(network_mysqld_type_t);
2718+
2719+ network_mysqld_type_data_date_init(type, field_type);
2720+ break;
2721+ case MYSQL_TYPE_TIME:
2722+ type = g_slice_new0(network_mysqld_type_t);
2723+
2724+ network_mysqld_type_data_time_init(type, field_type);
2725+ break;
2726+ case MYSQL_TYPE_NEWDECIMAL:
2727+ case MYSQL_TYPE_BLOB:
2728+ case MYSQL_TYPE_TINY_BLOB:
2729+ case MYSQL_TYPE_MEDIUM_BLOB:
2730+ case MYSQL_TYPE_LONG_BLOB:
2731+ case MYSQL_TYPE_STRING:
2732+ case MYSQL_TYPE_VAR_STRING:
2733+ case MYSQL_TYPE_VARCHAR:
2734+ /* they are all length-encoded strings */
2735+ type = g_slice_new0(network_mysqld_type_t);
2736+
2737+ network_mysqld_type_data_string_init(type, field_type);
2738+ break;
2739+ case MYSQL_TYPE_NULL:
2740+ type = g_slice_new0(network_mysqld_type_t);
2741+
2742+ type->type = field_type;
2743+ break;
2744+ }
2745+
2746+ return type;
2747+}
2748+/**
2749+ * free a type
2750+ */
2751+void network_mysqld_type_free(network_mysqld_type_t *type) {
2752+ if (NULL == type) return;
2753+
2754+ if (NULL != type->free_data) {
2755+ type->free_data(type);
2756+ }
2757+ g_slice_free(network_mysqld_type_t, type);
2758+}
2759+
2760+int network_mysqld_type_get_gstring(network_mysqld_type_t *type, GString *s) {
2761+ if (NULL == type->get_gstring) return -1;
2762+
2763+ return type->get_gstring(type, s);
2764+}
2765+
2766+int network_mysqld_type_get_string_const(network_mysqld_type_t *type, const char **s, gsize *s_len) {
2767+ if (NULL == type->get_string_const) return -1;
2768+
2769+ return type->get_string_const(type, s, s_len);
2770+}
2771+
2772+int network_mysqld_type_get_string(network_mysqld_type_t *type, char **s, gsize *s_len) {
2773+ if (NULL == type->get_string) return -1;
2774+
2775+ return type->get_string(type, s, s_len);
2776+}
2777+
2778+
2779+int network_mysqld_type_set_string(network_mysqld_type_t *type, const char *s, gsize s_len) {
2780+ if (NULL == type->set_string) return -1;
2781+
2782+ return type->set_string(type, s, s_len);
2783+}
2784+
2785+
2786+int network_mysqld_type_get_int(network_mysqld_type_t *type, guint64 *i, gboolean *is_unsigned) {
2787+ if (NULL == type->get_int) return -1;
2788+
2789+ return type->get_int(type, i, is_unsigned);
2790+}
2791+
2792+
2793+int network_mysqld_type_set_int(network_mysqld_type_t *type, guint64 i, gboolean is_unsigned) {
2794+ if (NULL == type->set_int) return -1;
2795+
2796+ return type->set_int(type, i, is_unsigned);
2797+}
2798+
2799+
2800+int network_mysqld_type_get_double(network_mysqld_type_t *type, double *d) {
2801+ if (NULL == type->get_double) return -1;
2802+
2803+ return type->get_double(type, d);
2804+}
2805+
2806+
2807+int network_mysqld_type_set_double(network_mysqld_type_t *type, double d) {
2808+ if (NULL == type->set_double) return -1;
2809+
2810+ return type->set_double(type, d);
2811+}
2812+
2813+
2814+int network_mysqld_type_get_date(network_mysqld_type_t *type, network_mysqld_type_date_t *date) {
2815+ if (NULL == type->get_date) return -1;
2816+
2817+ return type->get_date(type, date);
2818+}
2819+
2820+
2821+int network_mysqld_type_set_date(network_mysqld_type_t *type, network_mysqld_type_date_t *date) {
2822+ if (NULL == type->set_date) return -1;
2823+
2824+ return type->set_date(type, date);
2825+}
2826+
2827+
2828+int network_mysqld_type_get_time(network_mysqld_type_t *type, network_mysqld_type_time_t *t) {
2829+ if (NULL == type->get_time) return -1;
2830+
2831+ return type->get_time(type, t);
2832+}
2833+
2834+
2835+int network_mysqld_type_set_time(network_mysqld_type_t *type, network_mysqld_type_time_t *t) {
2836+ if (NULL == type->set_time) return -1;
2837+
2838+ return type->set_time(type, t);
2839+}
2840+
2841+
2842
2843=== added file 'src/network_mysqld_type.h'
2844--- src/network_mysqld_type.h 1970-01-01 00:00:00 +0000
2845+++ src/network_mysqld_type.h 2010-09-22 15:41:40 +0000
2846@@ -0,0 +1,147 @@
2847+#ifndef __NETWORK_MYSQLD_TYPE_H__
2848+#define __NETWORK_MYSQLD_TYPE_H__
2849+
2850+#include <mysql.h>
2851+#include <glib.h>
2852+
2853+#include "network-mysqld-proto.h"
2854+
2855+/**
2856+ * struct for the MYSQL_TYPE_DATE and friends
2857+ */
2858+typedef struct {
2859+ guint16 year;
2860+ guint8 month;
2861+ guint8 day;
2862+
2863+ guint8 hour;
2864+ guint8 min;
2865+ guint8 sec;
2866+
2867+ guint32 nsec; /* the nano-second part */
2868+} network_mysqld_type_date_t;
2869+
2870+#define NETWORK_MYSQLD_TYPE_DATE_MIN_BUF_LEN (sizeof("2010-10-27"))
2871+#define NETWORK_MYSQLD_TYPE_DATETIME_MIN_BUF_LEN (sizeof("2010-10-27 19:27:30.000000001"))
2872+#define NETWORK_MYSQLD_TYPE_TIMESTAMP_MIN_BUF_LEN NETWORK_MYSQLD_TYPE_DATETIME_MIN_BUF_LEN
2873+
2874+/**
2875+ * struct for the MYSQL_TYPE_TIME
2876+ */
2877+typedef struct {
2878+ guint8 sign;
2879+ guint32 days;
2880+
2881+ guint8 hour;
2882+ guint8 min;
2883+ guint8 sec;
2884+
2885+ guint32 nsec; /* the nano-second part */
2886+} network_mysqld_type_time_t;
2887+
2888+#define NETWORK_MYSQLD_TYPE_TIME_MIN_BUF_LEN (sizeof("-2147483647 19:27:30.000000001"))
2889+
2890+typedef struct _network_mysqld_type_t network_mysqld_type_t;
2891+
2892+struct _network_mysqld_type_t {
2893+ enum enum_field_types type;
2894+
2895+ gpointer data;
2896+ void (*free_data)(network_mysqld_type_t *type);
2897+
2898+ /**
2899+ * get a copy of ->data as GString
2900+ *
2901+ * @param type the type to get the data from
2902+ * @param s GString that the converted data will be assigned too
2903+ * @return 0 on success, -1 on error
2904+ */
2905+ int (*get_gstring)(network_mysqld_type_t *type, GString *s);
2906+ /**
2907+ * expose the ->data as constant string
2908+ *
2909+ * only available for types that have a "string" storage like _STRING, _CHAR, _BLOB
2910+ * the caller can copy the data out, but not change it
2911+ *
2912+ * @param type the type to get the data from
2913+ * @param s place to store the pointer to the const char * in
2914+ * @param s_len length of the const char *
2915+ * @return 0 on success, -1 on error
2916+ */
2917+ int (*get_string_const)(network_mysqld_type_t *type, const char **s, gsize *s_len);
2918+ /**
2919+ * get a copy of ->data as char *
2920+ *
2921+ * has 2 modes:
2922+ * - no-alloc-mode if *s is not NULL where it is expected that s and s_len point
2923+ * to a buffer of that size that we can copy into
2924+ * *s_len will contain the size of the stored string on success
2925+ * if *s_len is too small, -1 will be returned
2926+ * - alloc-mode when *s is NULL where we return a alloced buffer that is large enough
2927+ *
2928+ * @param type the type to get the data from
2929+ * @param s pointer to a buffer of *s_len size or pointer to (char *)NULL for alloc-mode
2930+ * @param s_len pointer to the length of the buffer if *s is not NULL. Points to the length of the *s on success
2931+ * @return 0 on success, -1 on error
2932+ */
2933+ int (*get_string)(network_mysqld_type_t *type, char **s, gsize *len);
2934+ /**
2935+ * set the ->data from a string
2936+ */
2937+ int (*set_string)(network_mysqld_type_t *type, const char *s, gsize s_len);
2938+ /**
2939+ * get ->data as uint64
2940+ */
2941+ int (*get_int)(network_mysqld_type_t *type, guint64 *i, gboolean *is_unsigned);
2942+ /**
2943+ * set ->data from uint64
2944+ */
2945+ int (*set_int)(network_mysqld_type_t *type, guint64 i, gboolean is_unsigned);
2946+ /**
2947+ * get ->data as double
2948+ */
2949+ int (*get_double)(network_mysqld_type_t *type, double *d);
2950+ /**
2951+ * set ->data from double
2952+ */
2953+ int (*set_double)(network_mysqld_type_t *type, double d);
2954+ int (*get_date)(network_mysqld_type_t *type, network_mysqld_type_date_t *date);
2955+ int (*set_date)(network_mysqld_type_t *type, network_mysqld_type_date_t *date);
2956+ /**
2957+ * get the ->data as _time_t
2958+ */
2959+ int (*get_time)(network_mysqld_type_t *type, network_mysqld_type_time_t *t);
2960+ /**
2961+ * set the ->data from a _time_t
2962+ */
2963+ int (*set_time)(network_mysqld_type_t *type, network_mysqld_type_time_t *t);
2964+
2965+
2966+ gboolean is_null; /**< is the value of this type NULL */
2967+ gboolean is_unsigned; /**< is the type signed or unsigned, only used by the integer types */
2968+};
2969+
2970+
2971+NETWORK_API network_mysqld_type_t *network_mysqld_type_new(enum enum_field_types _type);
2972+NETWORK_API void network_mysqld_type_free(network_mysqld_type_t *type);
2973+
2974+/**
2975+ * wrappers around the gettors and settors
2976+ *
2977+ * @return -1 if no settor or gettor defined or settor or gettor failed to convert
2978+ */
2979+NETWORK_API int network_mysqld_type_get_gstring(network_mysqld_type_t *type, GString *s);
2980+NETWORK_API int network_mysqld_type_get_gstring(network_mysqld_type_t *type, GString *s);
2981+NETWORK_API int network_mysqld_type_get_string_const(network_mysqld_type_t *type, const char **s, gsize *s_len);
2982+NETWORK_API int network_mysqld_type_get_string(network_mysqld_type_t *type, char **s, gsize *len);
2983+NETWORK_API int network_mysqld_type_set_string(network_mysqld_type_t *type, const char *s, gsize s_len);
2984+NETWORK_API int network_mysqld_type_get_int(network_mysqld_type_t *type, guint64 *i, gboolean *is_unsigned);
2985+NETWORK_API int network_mysqld_type_set_int(network_mysqld_type_t *type, guint64 i, gboolean is_unsigned);
2986+NETWORK_API int network_mysqld_type_get_double(network_mysqld_type_t *type, double *d);
2987+NETWORK_API int network_mysqld_type_set_double(network_mysqld_type_t *type, double d);
2988+NETWORK_API int network_mysqld_type_get_date(network_mysqld_type_t *type, network_mysqld_type_date_t *date);
2989+NETWORK_API int network_mysqld_type_set_date(network_mysqld_type_t *type, network_mysqld_type_date_t *date);
2990+NETWORK_API int network_mysqld_type_get_time(network_mysqld_type_t *type, network_mysqld_type_time_t *t);
2991+NETWORK_API int network_mysqld_type_set_time(network_mysqld_type_t *type, network_mysqld_type_time_t *t);
2992+
2993+#endif
2994
2995=== modified file 'tests/unit/CMakeLists.txt'
2996--- tests/unit/CMakeLists.txt 2010-02-24 11:02:26 +0000
2997+++ tests/unit/CMakeLists.txt 2010-09-22 15:41:40 +0000
2998@@ -113,6 +113,7 @@
2999 ../../src/glib-ext.c
3000 ../../src/network-mysqld-proto.c
3001 ../../src/network-mysqld-packet.c
3002+ ../../src/network_mysqld_type.c
3003 ../../src/chassis-timings.c
3004 ../../src/my_rdtsc.c
3005 )
3006@@ -132,6 +133,7 @@
3007 ../../src/glib-ext.c
3008 ../../src/network-mysqld-proto.c
3009 ../../src/network-mysqld-packet.c
3010+ ../../src/network_mysqld_type.c
3011 ../../src/network-address.c
3012 )
3013
3014
3015=== modified file 'tests/unit/Makefile.am'
3016--- tests/unit/Makefile.am 2010-04-06 14:26:51 +0000
3017+++ tests/unit/Makefile.am 2010-09-22 15:41:40 +0000
3018@@ -32,6 +32,7 @@
3019 t_network_backend \
3020 t_network_injection \
3021 t_network_mysqld_packet \
3022+ t_network_mysqld_type \
3023 t_network_mysqld_masterinfo \
3024 t_chassis_timings \
3025 t_chassis_shutdown_hooks \
3026@@ -81,10 +82,21 @@
3027 check_mysqld_proto_CPPFLAGS = -I$(top_srcdir)/src/ $(GLIB_CFLAGS) $(MYSQL_CFLAGS)
3028 check_mysqld_proto_LDADD = $(GLIB_LIBS)
3029
3030+t_network_mysqld_type_SOURCES = \
3031+ t_network_mysqld_type.c \
3032+ $(top_srcdir)/src/network_mysqld_type.c \
3033+ $(top_srcdir)/src/glib-ext.c
3034+
3035+t_network_mysqld_type_CPPFLAGS = -I$(top_srcdir)/src/ $(GLIB_CFLAGS) $(MYSQL_CFLAGS) $(LUA_CFLAGS)
3036+t_network_mysqld_type_LDADD = $(GLIB_LIBS) $(LUA_LIBS) $(EVENT_LIBS)
3037+
3038+
3039 t_network_mysqld_packet_SOURCES = \
3040 t_network_mysqld_packet.c \
3041 $(top_srcdir)/src/network-mysqld-packet.c \
3042 $(top_srcdir)/src/network-mysqld-proto.c \
3043+ $(top_srcdir)/src/network_mysqld_type.c \
3044+ $(top_srcdir)/src/network_mysqld_proto_binary.c \
3045 $(top_srcdir)/src/network-queue.c \
3046 $(top_srcdir)/src/network-socket.c \
3047 $(top_srcdir)/src/network-address.c \
3048@@ -126,6 +138,8 @@
3049 $(top_srcdir)/src/glib-ext.c \
3050 $(top_srcdir)/src/network-mysqld-proto.c \
3051 $(top_srcdir)/src/network-mysqld-packet.c \
3052+ $(top_srcdir)/src/network_mysqld_type.c \
3053+ $(top_srcdir)/src/network_mysqld_proto_binary.c \
3054 $(top_srcdir)/src/network-address.c \
3055 $(top_srcdir)/src/network-queue.c \
3056 $(top_srcdir)/src/network-socket.c
3057@@ -177,6 +191,8 @@
3058 $(top_srcdir)/src/network-backend.c \
3059 $(top_srcdir)/src/network-mysqld-proto.c \
3060 $(top_srcdir)/src/network-mysqld-packet.c \
3061+ $(top_srcdir)/src/network_mysqld_type.c \
3062+ $(top_srcdir)/src/network_mysqld_proto_binary.c \
3063 $(top_srcdir)/src/network-conn-pool.c \
3064 $(top_srcdir)/src/network-address.c \
3065 $(top_srcdir)/src/network-queue.c \
3066@@ -204,6 +220,8 @@
3067 $(top_srcdir)/src/glib-ext.c \
3068 $(top_srcdir)/src/network-mysqld-proto.c \
3069 $(top_srcdir)/src/network-mysqld-packet.c \
3070+ $(top_srcdir)/src/network_mysqld_type.c \
3071+ $(top_srcdir)/src/network_mysqld_proto_binary.c \
3072 $(top_srcdir)/src/network-injection.c \
3073 $(top_srcdir)/src/my_rdtsc.c \
3074 $(top_srcdir)/src/chassis-timings.c
3075
3076=== modified file 'tests/unit/lua/mysql-proto.lua'
3077--- tests/unit/lua/mysql-proto.lua 2010-04-06 14:26:51 +0000
3078+++ tests/unit/lua/mysql-proto.lua 2010-09-22 15:41:40 +0000
3079@@ -19,7 +19,7 @@
3080 $%ENDLICENSE%$ --]]
3081 local proto = assert(require("mysql.proto"))
3082 local password = assert(require("mysql.password"))
3083-
3084+require("proxy.test")
3085 ---
3086 -- err packet
3087
3088@@ -265,3 +265,72 @@
3089
3090 assert(false == password.check(challenge, response, dbl_hashed))
3091
3092+---
3093+-- prepared stmt decoders
3094+--
3095+
3096+-- EXECUTE packet, no params
3097+local packet = "\023\001\000\000\000\000\001\000\000\000"
3098+local execute = proto.from_stmt_execute_packet(packet, 0)
3099+assert(execute)
3100+assertEquals(execute.stmt_id, 1)
3101+assertEquals(execute.flags, 0)
3102+assertEquals(execute.iteration_count, 1)
3103+assertEquals(execute.new_params_bound, false)
3104+
3105+-- EXECUTE packet with 14 params
3106+local packet = "\023" ..
3107+ "\001\000\000\000" ..
3108+ "\000" ..
3109+ "\001\000\000\000" ..
3110+ "\003\000" ..
3111+ "\001" ..
3112+ "\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" ..
3113+ "\003\102\111\111" ..
3114+ "\001\000\000\000\000\000\000\000" ..
3115+ "\001\000\000\000\000\000\000\000" ..
3116+ "\001\000\000\000" ..
3117+ "\001\000" ..
3118+ "\001" ..
3119+ "\102\102\102\102\102\102\036\064" ..
3120+ "\000\000\036\065" ..
3121+ "\004\218\007\010\017" ..
3122+ "\011\218\007\010\017\019\027\030\001\000\000\000" ..
3123+ "\011\218\007\010\017\019\027\030\001\000\000\000" ..
3124+ "\012\001\120\000\000\000\019\027\030\001\000\000\000"
3125+
3126+local execute = proto.from_stmt_execute_packet(packet, 14)
3127+assert(execute)
3128+assertEquals(execute.stmt_id, 1)
3129+assertEquals(execute.flags, 0)
3130+assertEquals(execute.iteration_count, 1)
3131+assertEquals(execute.new_params_bound, true)
3132+
3133+local params = execute.params
3134+assert(params)
3135+assertEquals(#params, 14)
3136+
3137+local expected_params = {
3138+ { type = 254, value = nil },
3139+ { type = 6, value = nil },
3140+ { type = 254, value = "foo" },
3141+ { type = 8, value = 1 },
3142+ { type = 8, value = 1 },
3143+ { type = 3, value = 1 },
3144+ { type = 2, value = 1 },
3145+ { type = 1, value = 1 },
3146+ { type = 5, value = 10.2 }, --[[ double ]]--
3147+ { type = 4, value = 10.25 }, --[[ float ]]--
3148+ { type = 10, value = "2010-10-17" }, --[[ date ]]--
3149+ { type = 12, value = "2010-10-17 19:27:30.000000001" }, --[[ datetime ]]--
3150+ { type = 7, value = "2010-10-17 19:27:30.000000001" }, --[[ timestamp ]]--
3151+ { type = 11, value = "-120 19:27:30.000000001" }, --[[ time ]]--
3152+}
3153+
3154+for ndx, expected_param in ipairs(expected_params) do
3155+ local param = params[ndx]
3156+ assert(param)
3157+ assertEquals(param.type, expected_param.type)
3158+ assertEquals(param.value, expected_param.value)
3159+end
3160+
3161
3162=== modified file 'tests/unit/t_network_mysqld_packet.c'
3163--- tests/unit/t_network_mysqld_packet.c 2010-04-06 14:26:51 +0000
3164+++ tests/unit/t_network_mysqld_packet.c 2010-09-22 15:41:40 +0000
3165@@ -27,6 +27,7 @@
3166
3167 #include "network-mysqld-proto.h"
3168 #include "network-mysqld-packet.h"
3169+#include "network_mysqld_type.h"
3170 #include "glib-ext.h"
3171
3172 #if GLIB_CHECK_VERSION(2, 16, 0)
3173@@ -695,6 +696,624 @@
3174 network_queue_free(q);
3175 }
3176
3177+/* prepared statements */
3178+
3179+/* COM_STMT_PREPARE */
3180+static void t_com_stmt_prepare_new(void) {
3181+ network_mysqld_stmt_prepare_packet_t *cmd;
3182+
3183+ cmd = network_mysqld_stmt_prepare_packet_new();
3184+ g_assert(cmd);
3185+
3186+ network_mysqld_stmt_prepare_packet_free(cmd);
3187+}
3188+
3189+static void t_com_stmt_prepare_from_packet(void) {
3190+ network_mysqld_stmt_prepare_packet_t *cmd;
3191+ const char raw_packet[] = "\x1c\x00\x00\x00\x16SELECT CONCAT(?, ?) AS col1";
3192+ network_packet packet;
3193+
3194+ packet.data = g_string_new_len(C(raw_packet));
3195+ packet.offset = 0;
3196+
3197+ cmd = network_mysqld_stmt_prepare_packet_new();
3198+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3199+ g_assert_cmpint(0, ==, network_mysqld_proto_get_stmt_prepare_packet(&packet, cmd));
3200+ g_assert_cmpint(sizeof("SELECT CONCAT(?, ?) AS col1") - 1, ==, cmd->stmt_text->len);
3201+ g_assert_cmpstr("SELECT CONCAT(?, ?) AS col1", ==, cmd->stmt_text->str);
3202+
3203+ network_mysqld_stmt_prepare_packet_free(cmd);
3204+}
3205+
3206+/* COM_STMT_PREPARE OK-result */
3207+
3208+static void t_com_stmt_prepare_ok_new(void) {
3209+ network_mysqld_stmt_prepare_ok_packet_t *cmd;
3210+
3211+ cmd = network_mysqld_stmt_prepare_ok_packet_new();
3212+ g_assert(cmd);
3213+
3214+ network_mysqld_stmt_prepare_ok_packet_free(cmd);
3215+}
3216+
3217+/**
3218+ * test if we parse all the fields of a COM_STMT_PREPARE-ok response correctly
3219+ */
3220+static void t_com_stmt_prepare_ok_from_packet(void) {
3221+ network_mysqld_stmt_prepare_ok_packet_t *cmd;
3222+ network_mysqld_eof_packet_t *eof;
3223+ network_mysqld_proto_fielddef_t *coldef;
3224+
3225+ /* a response for the COM_STMT_PREPARE command
3226+ *
3227+ * the OK part with stmt-id and so on is in the first packet. The others are
3228+ * the field-defs, a EOF, the param-defs, and the last EOF */
3229+ strings packets[] = {
3230+ { C("\x0c\x00\x00\x01\x00\x01\x00\x00\x00\x01\x00\x02\x00\x00\x00\x00") }, /* the PREPARE OK packet */
3231+ { 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 */
3232+ { 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 */
3233+ { C("\x05\x00\x00\x04\xfe\x00\x00\x02\x00") }, /* the seperator */
3234+ { 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 */
3235+ { C("\x05\x00\x00\x06\xfe\x00\x00\x02\x00") } /* the terminator */
3236+ };
3237+ network_packet packet;
3238+
3239+ packet.data = g_string_new_len(packets[0].s, packets[0].s_len);
3240+ packet.offset = 0;
3241+
3242+ cmd = network_mysqld_stmt_prepare_ok_packet_new();
3243+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3244+ g_assert_cmpint(0, ==, network_mysqld_proto_get_stmt_prepare_ok_packet(&packet, cmd));
3245+ g_assert_cmpint(1, ==, cmd->stmt_id);
3246+ g_assert_cmpint(1, ==, cmd->num_columns);
3247+ g_assert_cmpint(2, ==, cmd->num_params);
3248+ g_assert_cmpint(0, ==, cmd->warnings);
3249+
3250+ network_mysqld_stmt_prepare_ok_packet_free(cmd);
3251+
3252+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3253+ g_string_free(packet.data, TRUE);
3254+
3255+ packet.data = g_string_new_len(packets[1].s, packets[1].s_len);
3256+ packet.offset = 0;
3257+
3258+ coldef = network_mysqld_proto_fielddef_new();
3259+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3260+ g_assert_cmpint(0, ==, network_mysqld_proto_get_fielddef(&packet, coldef, CLIENT_PROTOCOL_41));
3261+
3262+ network_mysqld_proto_fielddef_free(coldef);
3263+
3264+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3265+ g_string_free(packet.data, TRUE);
3266+
3267+
3268+ packet.data = g_string_new_len(packets[2].s, packets[2].s_len);
3269+ packet.offset = 0;
3270+
3271+ coldef = network_mysqld_proto_fielddef_new();
3272+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3273+ g_assert_cmpint(0, ==, network_mysqld_proto_get_fielddef(&packet, coldef, CLIENT_PROTOCOL_41));
3274+ network_mysqld_proto_fielddef_free(coldef);
3275+
3276+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3277+ g_string_free(packet.data, TRUE);
3278+
3279+
3280+ packet.data = g_string_new_len(packets[3].s, packets[3].s_len);
3281+ packet.offset = 0;
3282+
3283+ eof = network_mysqld_eof_packet_new();
3284+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3285+ g_assert_cmpint(0, ==, network_mysqld_proto_get_eof_packet(&packet, eof));
3286+
3287+ network_mysqld_eof_packet_free(eof);
3288+
3289+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3290+ g_string_free(packet.data, TRUE);
3291+
3292+
3293+ packet.data = g_string_new_len(packets[4].s, packets[4].s_len);
3294+ packet.offset = 0;
3295+
3296+ coldef = network_mysqld_proto_fielddef_new();
3297+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3298+ g_assert_cmpint(0, ==, network_mysqld_proto_get_fielddef(&packet, coldef, CLIENT_PROTOCOL_41));
3299+ network_mysqld_proto_fielddef_free(coldef);
3300+
3301+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3302+ g_string_free(packet.data, TRUE);
3303+
3304+
3305+ packet.data = g_string_new_len(packets[5].s, packets[5].s_len);
3306+ packet.offset = 0;
3307+
3308+ eof = network_mysqld_eof_packet_new();
3309+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3310+ g_assert_cmpint(0, ==, network_mysqld_proto_get_eof_packet(&packet, eof));
3311+
3312+ network_mysqld_eof_packet_free(eof);
3313+
3314+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3315+ g_string_free(packet.data, TRUE);
3316+}
3317+
3318+/* COM_STMT_EXECUTE */
3319+
3320+static void t_com_stmt_execute_new(void) {
3321+ network_mysqld_stmt_execute_packet_t *cmd;
3322+
3323+ cmd = network_mysqld_stmt_execute_packet_new();
3324+ g_assert(cmd);
3325+
3326+ network_mysqld_stmt_execute_packet_free(cmd);
3327+}
3328+
3329+/**
3330+ * test if we decode all valid types from EXECUTE stmt
3331+ */
3332+static void t_com_stmt_execute_from_packet(void) {
3333+ network_mysqld_stmt_execute_packet_t *cmd;
3334+ const char raw_packet[] =
3335+ "\x7a\x00\x00\x00"
3336+ "\x17" /* COM_STMT_EXECUTE */
3337+ "\x01\x00\x00\x00" /* stmt-id */
3338+ "\x00" /* flags */
3339+ "\x01\x00\x00\x00" /* iteration count */
3340+ "\x03\x00" /* nul-flags */
3341+ "\x01" /* yeah, we have parameters */
3342+ "\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 */
3343+ "\x03\x66\x6f\x6f" /* the string */
3344+ "\x01\x00\x00\x00\x00\x00\x00\x00" /* int64 */
3345+ "\x01\x00\x00\x00\x00\x00\x00\x00" /* int64 (unsigned) */
3346+ "\x01\x00\x00\x00" /* int32 */
3347+ "\x01\x00" /* int16 */
3348+ "\x01" /* int8 */
3349+ "\x66\x66\x66\x66\x66\x66\x24\x40"
3350+ "\x33\x33\x23\x41"
3351+ "\x04\xda\x07\x0a\x11"
3352+ "\x0b\xda\x07\x0a\x11\x13\x1b\x1e\x01\x00\x00\x00"
3353+ "\x0b\xda\x07\x0a\x11\x13\x1b\x1e\x01\x00\x00\x00"
3354+ "\x0c\x01\x78\x00\x00\x00\x13\x1b\x1e\x01\x00\x00\x00";
3355+
3356+ network_packet packet;
3357+ network_mysqld_type_t *param;
3358+ int param_ndx = 0;
3359+
3360+ packet.data = g_string_new_len(C(raw_packet));
3361+ packet.offset = 0;
3362+
3363+#define EXPECTED_NUM_PARAMS 14
3364+ cmd = network_mysqld_stmt_execute_packet_new();
3365+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3366+ g_assert_cmpint(0, ==, network_mysqld_proto_get_stmt_execute_packet(&packet, cmd, EXPECTED_NUM_PARAMS));
3367+ g_assert_cmpint(1, ==, cmd->stmt_id);
3368+ g_assert_cmpint(0, ==, cmd->flags);
3369+ g_assert_cmpint(1, ==, cmd->iteration_count);
3370+ g_assert_cmpint(1, ==, cmd->new_params_bound);
3371+ g_assert_cmpint(EXPECTED_NUM_PARAMS, ==, cmd->params->len);
3372+#undef EXPECTED_NUM_PARAMS
3373+
3374+ /* (_STRING)NULL */
3375+ param = g_ptr_array_index(cmd->params, param_ndx++);
3376+ g_assert(param);
3377+ g_assert_cmpint(MYSQL_TYPE_STRING, ==, param->type);
3378+ g_assert_cmpint(TRUE, ==, param->is_null);
3379+
3380+ /* (_NULL) */
3381+ param = g_ptr_array_index(cmd->params, param_ndx++);
3382+ g_assert(param);
3383+ g_assert_cmpint(MYSQL_TYPE_NULL, ==, param->type);
3384+ g_assert_cmpint(TRUE, ==, param->is_null);
3385+
3386+ /* (_STRING)"foo" */
3387+ param = g_ptr_array_index(cmd->params, param_ndx++);
3388+ g_assert(param);
3389+ g_assert_cmpint(MYSQL_TYPE_STRING, ==, param->type);
3390+ g_assert_cmpint(FALSE, ==, param->is_null);
3391+ {
3392+ const char *s;
3393+ gsize s_len;
3394+
3395+ g_assert_cmpint(0, ==, param->get_string_const(param, &s, &s_len));
3396+ g_assert_cmpint(s_len, ==, 3);
3397+ g_assert_cmpstr(s, ==, "foo");
3398+ };
3399+
3400+ /* (_INT64)1 */
3401+ param = g_ptr_array_index(cmd->params, param_ndx++);
3402+ g_assert(param);
3403+ g_assert_cmpint(MYSQL_TYPE_LONGLONG, ==, param->type);
3404+ g_assert_cmpint(FALSE, ==, param->is_null);
3405+ g_assert_cmpint(FALSE, ==, param->is_unsigned);
3406+ {
3407+ guint64 i;
3408+ gboolean is_unsigned;
3409+
3410+ g_assert_cmpint(0, ==, param->get_int(param, &i, &is_unsigned));
3411+ g_assert_cmpint(i, ==, 1);
3412+ g_assert_cmpint(is_unsigned, ==, FALSE);
3413+ };
3414+
3415+ /* (_UINT64)1 */
3416+ param = g_ptr_array_index(cmd->params, param_ndx++);
3417+ g_assert(param);
3418+ g_assert_cmpint(MYSQL_TYPE_LONGLONG, ==, param->type);
3419+ g_assert_cmpint(FALSE, ==, param->is_null);
3420+ g_assert_cmpint(TRUE, ==, param->is_unsigned);
3421+ {
3422+ guint64 i;
3423+ gboolean is_unsigned;
3424+
3425+ g_assert_cmpint(0, ==, param->get_int(param, &i, &is_unsigned));
3426+ g_assert_cmpint(i, ==, 1);
3427+ };
3428+
3429+ /* (_INT32)1 */
3430+ param = g_ptr_array_index(cmd->params, param_ndx++);
3431+ g_assert(param);
3432+ g_assert_cmpint(MYSQL_TYPE_LONG, ==, param->type);
3433+ g_assert_cmpint(FALSE, ==, param->is_null);
3434+ g_assert_cmpint(FALSE, ==, param->is_unsigned);
3435+ {
3436+ guint64 i;
3437+ gboolean is_unsigned;
3438+
3439+ g_assert_cmpint(0, ==, param->get_int(param, &i, &is_unsigned));
3440+ g_assert_cmpint(i, ==, 1);
3441+ };
3442+
3443+ /* (_INT16)1 */
3444+ param = g_ptr_array_index(cmd->params, param_ndx++);
3445+ g_assert(param);
3446+ g_assert_cmpint(MYSQL_TYPE_SHORT, ==, param->type);
3447+ g_assert_cmpint(FALSE, ==, param->is_null);
3448+ g_assert_cmpint(FALSE, ==, param->is_unsigned);
3449+ {
3450+ guint64 i;
3451+ gboolean is_unsigned;
3452+
3453+ g_assert_cmpint(0, ==, param->get_int(param, &i, &is_unsigned));
3454+ g_assert_cmpint(i, ==, 1);
3455+ };
3456+
3457+ /* (_INT8)1 */
3458+ param = g_ptr_array_index(cmd->params, param_ndx++);
3459+ g_assert(param);
3460+ g_assert_cmpint(MYSQL_TYPE_TINY, ==, param->type);
3461+ g_assert_cmpint(FALSE, ==, param->is_null);
3462+ g_assert_cmpint(FALSE, ==, param->is_unsigned);
3463+ {
3464+ guint64 i;
3465+ gboolean is_unsigned;
3466+
3467+ g_assert_cmpint(0, ==, param->get_int(param, &i, &is_unsigned));
3468+ g_assert_cmpint(i, ==, 1);
3469+ };
3470+
3471+ /* (_DOUBLE)10.2 */
3472+ param = g_ptr_array_index(cmd->params, param_ndx++);
3473+ g_assert(param);
3474+ g_assert_cmpint(MYSQL_TYPE_DOUBLE, ==, param->type);
3475+ g_assert_cmpint(FALSE, ==, param->is_null);
3476+ {
3477+ double d;
3478+
3479+ g_assert_cmpint(0, ==, param->get_double(param, &d));
3480+ g_assert_cmpfloat(d, ==, 10.2);
3481+ };
3482+
3483+ /* (_FLOAT)10.2 */
3484+ param = g_ptr_array_index(cmd->params, param_ndx++);
3485+ g_assert(param);
3486+ g_assert_cmpint(MYSQL_TYPE_FLOAT, ==, param->type);
3487+ g_assert_cmpint(FALSE, ==, param->is_null);
3488+ {
3489+ double d;
3490+
3491+ g_assert_cmpint(0, ==, param->get_double(param, &d));
3492+ g_assert_cmpfloat(d, ==, (float)10.2);
3493+ };
3494+
3495+ /* (_DATE)2010-10-17 */
3496+ param = g_ptr_array_index(cmd->params, param_ndx++);
3497+ g_assert(param);
3498+ g_assert_cmpint(MYSQL_TYPE_DATE, ==, param->type);
3499+ g_assert_cmpint(FALSE, ==, param->is_null);
3500+ {
3501+ network_mysqld_type_date_t date;
3502+
3503+ g_assert_cmpint(0, ==, param->get_date(param, &date));
3504+ g_assert_cmpint(date.year, ==, 2010);
3505+ g_assert_cmpint(date.month, ==, 10);
3506+ g_assert_cmpint(date.day, ==, 17);
3507+
3508+ g_assert_cmpint(date.hour, ==, 0);
3509+ g_assert_cmpint(date.min, ==, 0);
3510+ g_assert_cmpint(date.sec, ==, 0);
3511+ g_assert_cmpint(date.nsec, ==, 0);
3512+ };
3513+
3514+ /* (_DATETIME)2010-10-17 19:27:30.000 010 */
3515+ param = g_ptr_array_index(cmd->params, param_ndx++);
3516+ g_assert(param);
3517+ g_assert_cmpint(MYSQL_TYPE_DATETIME, ==, param->type);
3518+ g_assert_cmpint(FALSE, ==, param->is_null);
3519+ {
3520+ network_mysqld_type_date_t date;
3521+
3522+ g_assert_cmpint(0, ==, param->get_date(param, &date));
3523+
3524+ g_assert_cmpint(date.year, ==, 2010);
3525+ g_assert_cmpint(date.month, ==, 10);
3526+ g_assert_cmpint(date.day, ==, 17);
3527+
3528+ g_assert_cmpint(date.hour, ==, 19);
3529+ g_assert_cmpint(date.min, ==, 27);
3530+ g_assert_cmpint(date.sec, ==, 30);
3531+ g_assert_cmpint(date.nsec, ==, 1);
3532+ };
3533+
3534+ /* (_TIMESTAMP)2010-10-17 19:27:30.000 010 */
3535+ param = g_ptr_array_index(cmd->params, param_ndx++);
3536+ g_assert(param);
3537+ g_assert_cmpint(MYSQL_TYPE_TIMESTAMP, ==, param->type);
3538+ g_assert_cmpint(FALSE, ==, param->is_null);
3539+ {
3540+ network_mysqld_type_date_t date;
3541+
3542+ g_assert_cmpint(0, ==, param->get_date(param, &date));
3543+ g_assert_cmpint(date.year, ==, 2010);
3544+ g_assert_cmpint(date.month, ==, 10);
3545+ g_assert_cmpint(date.day, ==, 17);
3546+
3547+ g_assert_cmpint(date.hour, ==, 19);
3548+ g_assert_cmpint(date.min, ==, 27);
3549+ g_assert_cmpint(date.sec, ==, 30);
3550+ g_assert_cmpint(date.nsec, ==, 1);
3551+ };
3552+
3553+ /* (_TIME)-120 19:27:30.000 010 */
3554+ param = g_ptr_array_index(cmd->params, param_ndx++);
3555+ g_assert(param);
3556+ g_assert_cmpint(MYSQL_TYPE_TIME, ==, param->type);
3557+ g_assert_cmpint(FALSE, ==, param->is_null);
3558+ {
3559+ network_mysqld_type_time_t t;
3560+
3561+ g_assert_cmpint(0, ==, param->get_time(param, &t));
3562+ g_assert_cmpint(t.sign, ==, 1);
3563+ g_assert_cmpint(t.days, ==, 120);
3564+
3565+ g_assert_cmpint(t.hour, ==, 19);
3566+ g_assert_cmpint(t.min, ==, 27);
3567+ g_assert_cmpint(t.sec, ==, 30);
3568+ g_assert_cmpint(t.nsec, ==, 1);
3569+ };
3570+
3571+ network_mysqld_stmt_execute_packet_free(cmd);
3572+}
3573+
3574+/**
3575+ * test if we decode all valid types from EXECUTE stmt
3576+ */
3577+static void t_com_stmt_execute_from_packet_invalid(void) {
3578+ network_mysqld_stmt_execute_packet_t *cmd;
3579+ const char raw_packet[] =
3580+ "\x12\x00\x00\x00"
3581+ "\x17" /* COM_STMT_EXECUTE */
3582+ "\x01\x00\x00\x00" /* stmt-id */
3583+ "\x00" /* flags */
3584+ "\x01\x00\x00\x00" /* iteration count */
3585+ "\x00"
3586+ "\x01"
3587+ "\x0f\x00"
3588+ "\x03\x66\x6f\x6f";
3589+
3590+ network_packet packet;
3591+ network_mysqld_type_t *param;
3592+ int param_ndx = 0;
3593+
3594+ packet.data = g_string_new_len(C(raw_packet));
3595+ packet.offset = 0;
3596+
3597+#define EXPECTED_NUM_PARAMS 1
3598+ cmd = network_mysqld_stmt_execute_packet_new();
3599+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3600+ g_assert_cmpint(0, !=, network_mysqld_proto_get_stmt_execute_packet(&packet, cmd, EXPECTED_NUM_PARAMS));
3601+#undef EXPECTED_NUM_PARAMS
3602+
3603+ network_mysqld_stmt_execute_packet_free(cmd);
3604+}
3605+
3606+/**
3607+ * if there are no parameters, we don't have any nul-flags to send
3608+ */
3609+static void t_com_stmt_execute_from_packet_no_params(void) {
3610+ network_mysqld_stmt_execute_packet_t *cmd;
3611+ const char raw_packet[] =
3612+ "\x0a\x00\x00\x00"
3613+ "\x17" /* COM_STMT_EXECUTE */
3614+ "\x01\x00\x00\x00" /* stmt-id */
3615+ "\x00" /* flags */
3616+ "\x01\x00\x00\x00" /* iteration count */
3617+ ;
3618+
3619+ network_packet packet;
3620+
3621+ packet.data = g_string_new_len(C(raw_packet));
3622+ packet.offset = 0;
3623+
3624+ cmd = network_mysqld_stmt_execute_packet_new();
3625+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3626+ g_assert_cmpint(0, ==, network_mysqld_proto_get_stmt_execute_packet(&packet, cmd, 0));
3627+ g_assert_cmpint(1, ==, cmd->stmt_id);
3628+ g_assert_cmpint(0, ==, cmd->flags);
3629+ g_assert_cmpint(1, ==, cmd->iteration_count);
3630+
3631+ network_mysqld_stmt_execute_packet_free(cmd);
3632+}
3633+
3634+/* COM_STMT_EXECUTE result */
3635+
3636+/**
3637+ * test if we parse all the fields of a COM_STMT_EXECUTE result correctly
3638+ */
3639+static void t_com_stmt_execute_result_from_packet(void) {
3640+ network_mysqld_eof_packet_t *eof;
3641+ network_mysqld_proto_fielddefs_t *coldefs;
3642+ network_mysqld_proto_fielddef_t *coldef;
3643+ network_mysqld_resultset_row_t *row;
3644+ network_mysqld_type_t *field;
3645+ GString *data;
3646+ guint64 field_count;
3647+ int packet_id = 0;
3648+
3649+ /* response for a
3650+ * SELECT ? AS col2, CONCAT(?, ?) AS col1
3651+ * with
3652+ * 1: NULL
3653+ * 2: STRING bar
3654+ * 3: STRING foo
3655+ */
3656+ strings packets[] = {
3657+ { C("\x01\x00\x00\x01\x02") },
3658+ { 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") },
3659+ { 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") },
3660+ { C("\x05\x00\x00\x04\xfe\x00\x00\x02\x00") },
3661+ { C("\x09\x00\x00\x05\x00\x04\x06" "barfoo") },
3662+ { C("\x05\x00\x00\x06\xfe\x00\x00\x02\x00") }
3663+
3664+ };
3665+ network_packet packet;
3666+
3667+ /* the field-count */
3668+ packet_id = 0;
3669+ packet.data = g_string_new_len(packets[packet_id].s, packets[packet_id].s_len);
3670+ packet.offset = 0;
3671+
3672+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3673+ g_assert_cmpint(0, ==, network_mysqld_proto_get_lenenc_int(&packet, &field_count));
3674+ g_assert_cmpint(2, ==, field_count);
3675+
3676+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3677+ g_string_free(packet.data, TRUE);
3678+
3679+
3680+ /* the colum defs */
3681+ packet_id++;
3682+ packet.data = g_string_new_len(packets[packet_id].s, packets[packet_id].s_len);
3683+ packet.offset = 0;
3684+
3685+ coldefs = network_mysqld_proto_fielddefs_new();
3686+ coldef = network_mysqld_proto_fielddef_new();
3687+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3688+ g_assert_cmpint(0, ==, network_mysqld_proto_get_fielddef(&packet, coldef, CLIENT_PROTOCOL_41));
3689+
3690+ g_ptr_array_add(coldefs, coldef);
3691+
3692+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3693+ g_string_free(packet.data, TRUE);
3694+
3695+ /* the string column */
3696+ packet_id++;
3697+ packet.data = g_string_new_len(packets[packet_id].s, packets[packet_id].s_len);
3698+ packet.offset = 0;
3699+
3700+ coldef = network_mysqld_proto_fielddef_new();
3701+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3702+ g_assert_cmpint(0, ==, network_mysqld_proto_get_fielddef(&packet, coldef, CLIENT_PROTOCOL_41));
3703+
3704+ g_ptr_array_add(coldefs, coldef);
3705+
3706+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3707+ g_string_free(packet.data, TRUE);
3708+
3709+ /* the EOF */
3710+ packet_id++;
3711+ packet.data = g_string_new_len(packets[packet_id].s, packets[packet_id].s_len);
3712+ packet.offset = 0;
3713+
3714+ eof = network_mysqld_eof_packet_new();
3715+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3716+ g_assert_cmpint(0, ==, network_mysqld_proto_get_eof_packet(&packet, eof));
3717+
3718+ network_mysqld_eof_packet_free(eof);
3719+
3720+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3721+ g_string_free(packet.data, TRUE);
3722+
3723+ /* the row */
3724+ packet_id++;
3725+ packet.data = g_string_new_len(packets[packet_id].s, packets[packet_id].s_len);
3726+ packet.offset = 0;
3727+
3728+ row = network_mysqld_resultset_row_new();
3729+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3730+ g_assert_cmpint(0, ==, network_mysqld_proto_get_binary_row(&packet, coldefs, row));
3731+
3732+ /* check if the 1st field is NULL */
3733+ field = g_ptr_array_index(row, 0);
3734+ g_assert(field);
3735+ g_assert_cmpint(TRUE, ==, field->is_null);
3736+
3737+ /* check if the 2nd field is "barfoo" */
3738+ field = g_ptr_array_index(row, 1);
3739+ g_assert(field);
3740+ g_assert_cmpint(MYSQL_TYPE_VAR_STRING, ==, field->type);
3741+ g_assert_cmpint(FALSE, ==, field->is_null);
3742+
3743+ /* FIXME: find a way to test this without touching the internal representation */
3744+ data = field->data;
3745+ g_assert(data);
3746+ g_assert_cmpint(data->len, ==, 6);
3747+ g_assert_cmpstr(data->str, ==, "barfoo");
3748+
3749+ network_mysqld_resultset_row_free(row);
3750+
3751+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3752+ g_string_free(packet.data, TRUE);
3753+
3754+ packet_id++;
3755+ packet.data = g_string_new_len(packets[packet_id].s, packets[packet_id].s_len);
3756+ packet.offset = 0;
3757+
3758+ eof = network_mysqld_eof_packet_new();
3759+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3760+ g_assert_cmpint(0, ==, network_mysqld_proto_get_eof_packet(&packet, eof));
3761+
3762+ network_mysqld_eof_packet_free(eof);
3763+
3764+ g_assert_cmpint(packet.offset, ==, packet.data->len); /* is everything parsed */
3765+ g_string_free(packet.data, TRUE);
3766+
3767+ network_mysqld_proto_fielddefs_free(coldefs);
3768+}
3769+
3770+/* COM_STMT_CLOSE */
3771+static void t_com_stmt_close_new(void) {
3772+ network_mysqld_stmt_close_packet_t *cmd;
3773+
3774+ cmd = network_mysqld_stmt_close_packet_new();
3775+ g_assert(cmd);
3776+
3777+ network_mysqld_stmt_close_packet_free(cmd);
3778+}
3779+
3780+static void t_com_stmt_close_from_packet(void) {
3781+ network_mysqld_stmt_close_packet_t *cmd;
3782+ const char raw_packet[] = "\x05\x00\x00\x00\x19\x01\x00\x00\x00";
3783+ network_packet packet;
3784+ packet.data = g_string_new_len(C(raw_packet));
3785+ packet.offset = 0;
3786+
3787+ cmd = network_mysqld_stmt_close_packet_new();
3788+ g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
3789+ g_assert_cmpint(0, ==, network_mysqld_proto_get_stmt_close_packet(&packet, cmd));
3790+ g_assert_cmpint(1, ==, cmd->stmt_id);
3791+
3792+ network_mysqld_stmt_close_packet_free(cmd);
3793+}
3794+
3795
3796 /**
3797 * @cond
3798@@ -727,6 +1346,23 @@
3799 g_test_add_func("/core/resultset-fields-broken-proto-field-count-low", t_resultset_fields_parse_low);
3800 g_test_add_func("/core/resultset-fields-broken-proto-field-count-high", t_resultset_fields_parse_high);
3801
3802+ /* prepared statements */
3803+ g_test_add_func("/core/com_stmt_prepare_new", t_com_stmt_prepare_new);
3804+ g_test_add_func("/core/com_stmt_prepare_from_packet", t_com_stmt_prepare_from_packet);
3805+
3806+ g_test_add_func("/core/com_stmt_prepare_ok_new", t_com_stmt_prepare_ok_new);
3807+ g_test_add_func("/core/com_stmt_prepare_ok_from_packet", t_com_stmt_prepare_ok_from_packet);
3808+
3809+ g_test_add_func("/core/com_stmt_execute_new", t_com_stmt_execute_new);
3810+ g_test_add_func("/core/com_stmt_execute_from_packet", t_com_stmt_execute_from_packet);
3811+ g_test_add_func("/core/com_stmt_execute_from_packet_no_params", t_com_stmt_execute_from_packet_no_params);
3812+ g_test_add_func("/core/com_stmt_execute_from_packet_invalid", t_com_stmt_execute_from_packet_invalid);
3813+
3814+ g_test_add_func("/core/com_stmt_execute_result_from_packet", t_com_stmt_execute_result_from_packet);
3815+
3816+ g_test_add_func("/core/com_stmt_close_new", t_com_stmt_close_new);
3817+ g_test_add_func("/core/com_stmt_close_from_packet", t_com_stmt_close_from_packet);
3818+
3819 return g_test_run();
3820 }
3821 /** @endcond */
3822
3823=== added file 'tests/unit/t_network_mysqld_type.c'
3824--- tests/unit/t_network_mysqld_type.c 1970-01-01 00:00:00 +0000
3825+++ tests/unit/t_network_mysqld_type.c 2010-09-22 15:41:40 +0000
3826@@ -0,0 +1,205 @@
3827+/* $%BEGINLICENSE%$
3828+ Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
3829+
3830+ This program is free software; you can redistribute it and/or
3831+ modify it under the terms of the GNU General Public License as
3832+ published by the Free Software Foundation; version 2 of the
3833+ License.
3834+
3835+ This program is distributed in the hope that it will be useful,
3836+ but WITHOUT ANY WARRANTY; without even the implied warranty of
3837+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3838+ GNU General Public License for more details.
3839+
3840+ You should have received a copy of the GNU General Public License
3841+ along with this program; if not, write to the Free Software
3842+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
3843+ 02110-1301 USA
3844+
3845+ $%ENDLICENSE%$ */
3846+
3847+
3848+#include <stdio.h>
3849+#include <stdlib.h>
3850+#include <string.h>
3851+
3852+#include <glib.h>
3853+
3854+#include "network_mysqld_type.h"
3855+#include "glib-ext.h"
3856+#include "string-len.h"
3857+
3858+void t_proto_type_date_to_string(void) {
3859+ network_mysqld_type_t *type;
3860+ network_mysqld_type_date_t date;
3861+ const char *const_s;
3862+ char *s;
3863+ gsize s_len;
3864+ char static_s[NETWORK_MYSQLD_TYPE_DATE_MIN_BUF_LEN];
3865+
3866+ type = network_mysqld_type_new(MYSQL_TYPE_DATE);
3867+
3868+ memset(&date, 0, sizeof(date));
3869+ date.year = 2010;
3870+ date.month = 12;
3871+ date.day = 30;
3872+
3873+ date.hour = 19;
3874+ date.min = 27;
3875+ date.sec = 30;
3876+
3877+ date.nsec = 1;
3878+
3879+ g_assert_cmpint(0, ==, network_mysqld_type_set_date(type, &date));
3880+ 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 */
3881+
3882+ /* get a copy of the date, alloced */
3883+ s = NULL;
3884+ s_len = 0;
3885+ g_assert_cmpint(0, ==, network_mysqld_type_get_string(type, &s, &s_len));
3886+ g_assert_cmpint(10, ==, s_len);
3887+ g_assert_cmpstr("2010-12-30", ==, s);
3888+ g_free(s);
3889+
3890+ s = static_s;
3891+ s_len = sizeof(static_s);
3892+ g_assert_cmpint(0, ==, network_mysqld_type_get_string(type, &s, &s_len));
3893+ g_assert_cmpint(10, ==, s_len);
3894+ g_assert_cmpstr("2010-12-30", ==, s);
3895+
3896+ network_mysqld_type_free(type);
3897+}
3898+
3899+void t_proto_type_datetime_to_string(void) {
3900+ network_mysqld_type_t *type;
3901+ network_mysqld_type_date_t date;
3902+ const char *const_s;
3903+ char *s;
3904+ gsize s_len;
3905+ char static_s[NETWORK_MYSQLD_TYPE_DATETIME_MIN_BUF_LEN];
3906+
3907+ type = network_mysqld_type_new(MYSQL_TYPE_DATETIME);
3908+
3909+ memset(&date, 0, sizeof(date));
3910+ date.year = 2010;
3911+ date.month = 12;
3912+ date.day = 30;
3913+
3914+ date.hour = 19;
3915+ date.min = 27;
3916+ date.sec = 30;
3917+
3918+ date.nsec = 1;
3919+
3920+ g_assert_cmpint(0, ==, network_mysqld_type_set_date(type, &date));
3921+ 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 */
3922+
3923+ /* get a copy of the date, alloced */
3924+ s = NULL;
3925+ s_len = 0;
3926+ g_assert_cmpint(0, ==, network_mysqld_type_get_string(type, &s, &s_len));
3927+ g_assert_cmpint(29, ==, s_len);
3928+ g_assert_cmpstr("2010-12-30 19:27:30.000000001", ==, s);
3929+ g_free(s);
3930+
3931+ s = static_s;
3932+ s_len = sizeof(static_s);
3933+ g_assert_cmpint(0, ==, network_mysqld_type_get_string(type, &s, &s_len));
3934+ g_assert_cmpint(29, ==, s_len);
3935+ g_assert_cmpstr("2010-12-30 19:27:30.000000001", ==, s);
3936+
3937+ network_mysqld_type_free(type);
3938+}
3939+
3940+void t_proto_type_timestamp_to_string(void) {
3941+ network_mysqld_type_t *type;
3942+ network_mysqld_type_date_t date;
3943+ const char *const_s;
3944+ char *s;
3945+ gsize s_len;
3946+ char static_s[NETWORK_MYSQLD_TYPE_TIMESTAMP_MIN_BUF_LEN];
3947+
3948+ type = network_mysqld_type_new(MYSQL_TYPE_TIMESTAMP);
3949+
3950+ memset(&date, 0, sizeof(date));
3951+ date.year = 2010;
3952+ date.month = 12;
3953+ date.day = 30;
3954+
3955+ date.hour = 19;
3956+ date.min = 27;
3957+ date.sec = 30;
3958+
3959+ date.nsec = 1;
3960+
3961+ g_assert_cmpint(0, ==, network_mysqld_type_set_date(type, &date));
3962+ 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 */
3963+
3964+ /* get a copy of the date, alloced */
3965+ s = NULL;
3966+ s_len = 0;
3967+ g_assert_cmpint(0, ==, network_mysqld_type_get_string(type, &s, &s_len));
3968+ g_assert_cmpint(29, ==, s_len);
3969+ g_assert_cmpstr("2010-12-30 19:27:30.000000001", ==, s);
3970+ g_free(s);
3971+
3972+ s = static_s;
3973+ s_len = sizeof(static_s);
3974+ g_assert_cmpint(0, ==, network_mysqld_type_get_string(type, &s, &s_len));
3975+ g_assert_cmpint(29, ==, s_len);
3976+ g_assert_cmpstr("2010-12-30 19:27:30.000000001", ==, s);
3977+
3978+ network_mysqld_type_free(type);
3979+}
3980+
3981+void t_proto_type_time_to_string(void) {
3982+ network_mysqld_type_t *type;
3983+ network_mysqld_type_time_t t;
3984+ const char *const_s;
3985+ char *s;
3986+ gsize s_len;
3987+ char static_s[NETWORK_MYSQLD_TYPE_TIME_MIN_BUF_LEN];
3988+
3989+ type = network_mysqld_type_new(MYSQL_TYPE_TIME);
3990+
3991+ memset(&t, 0, sizeof(t));
3992+ t.sign = -1;
3993+ t.days = 120;
3994+ t.hour = 19;
3995+ t.min = 27;
3996+ t.sec = 30;
3997+ t.nsec = 1;
3998+
3999+ g_assert_cmpint(0, ==, network_mysqld_type_set_time(type, &t));
4000+ 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 */
4001+
4002+
4003+ /* get a copy of the time, alloced */
4004+ s = NULL;
4005+ s_len = 0;
4006+ g_assert_cmpint(0, ==, network_mysqld_type_get_string(type, &s, &s_len));
4007+ g_assert_cmpint(23, ==, s_len);
4008+ g_assert_cmpstr("-120 19:27:30.000000001", ==, s);
4009+ g_free(s);
4010+
4011+ s = static_s;
4012+ s_len = sizeof(static_s);
4013+ g_assert_cmpint(0, ==, network_mysqld_type_get_string(type, &s, &s_len));
4014+ g_assert_cmpint(23, ==, s_len);
4015+ g_assert_cmpstr("-120 19:27:30.000000001", ==, s);
4016+
4017+ network_mysqld_type_free(type);
4018+}
4019+
4020+int main(int argc, char **argv) {
4021+ g_test_init(&argc, &argv, NULL);
4022+ g_test_bug_base("http://bugs.mysql.com/");
4023+
4024+ g_test_add_func("/mysql-proto/type/time", t_proto_type_time_to_string);
4025+ g_test_add_func("/mysql-proto/type/datetime", t_proto_type_datetime_to_string);
4026+ g_test_add_func("/mysql-proto/type/timestamp", t_proto_type_timestamp_to_string);
4027+ g_test_add_func("/mysql-proto/type/date", t_proto_type_date_to_string);
4028+
4029+ return g_test_run();
4030+}
4031+

Subscribers

People subscribed via source and target branches