Merge lp:~jan-kneschke/mysql-proxy/prep-stmt-codecs into lp:mysql-proxy/0.8
- prep-stmt-codecs
- Merge into 0.8
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 |
Related bugs: |
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.
Commit message
Description of the change
* added a network_
* added encoders and decoders for the binary row format (network_
* added encoders and decoders for COM_STMT_PREPARE, COM_STMT_EXECUTE, COM_STMT_CLOSE and its special response packets
* added a example on how to use them examples/
- 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_*
- 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
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, ¶m_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 | + |