ruby-mysql-ext 2.9.8 → 2.9.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ext/mysql/ext.c +597 -0
- data/ext/mysql/extconf.rb +1 -1
- data/lib/mysql.rb +7 -4
- data/lib/mysql/packet.rb +77 -0
- data/lib/mysql/protocol.rb +8 -10
- data/spec/mysql_spec.rb +96 -1
- metadata +4 -3
- data/ext/mysql/packet.c +0 -246
data/ext/mysql/ext.c
ADDED
@@ -0,0 +1,597 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
|
3
|
+
typedef struct {
|
4
|
+
unsigned char *ptr;
|
5
|
+
unsigned char *endp;
|
6
|
+
} packet_data_t;
|
7
|
+
|
8
|
+
static VALUE cMysql;
|
9
|
+
static VALUE cPacket;
|
10
|
+
static VALUE cMysqlTime;
|
11
|
+
static VALUE cProtocol;
|
12
|
+
static VALUE cStmtRawRecord;
|
13
|
+
static VALUE cExecutePacket;
|
14
|
+
static VALUE cCharset;
|
15
|
+
static VALUE eProtocolError;
|
16
|
+
|
17
|
+
static VALUE packet_s_lcb(VALUE klass, VALUE val)
|
18
|
+
{
|
19
|
+
unsigned long long n;
|
20
|
+
unsigned char buf[9];
|
21
|
+
int i;
|
22
|
+
|
23
|
+
if (val == Qnil)
|
24
|
+
return rb_str_new("\xfb", 1);
|
25
|
+
n = NUM2ULL(val);
|
26
|
+
if (n < 251) {
|
27
|
+
buf[0] = n;
|
28
|
+
return rb_str_new(buf, 1);
|
29
|
+
}
|
30
|
+
if (n < 65536) {
|
31
|
+
buf[0] = '\xfc';
|
32
|
+
buf[1] = n % 256;
|
33
|
+
buf[2] = n / 256;
|
34
|
+
return rb_str_new(buf, 3);
|
35
|
+
}
|
36
|
+
if (n < 16777216) {
|
37
|
+
buf[0] = '\xfd';
|
38
|
+
buf[1] = n % 256;
|
39
|
+
n /= 256;
|
40
|
+
buf[2] = n % 256;
|
41
|
+
buf[3] = n / 256;
|
42
|
+
return rb_str_new(buf, 4);
|
43
|
+
}
|
44
|
+
buf[0] = '\xfe';
|
45
|
+
#ifdef WORDS_BIGENDIAN
|
46
|
+
for (i = 0; i < 8; i++) {
|
47
|
+
buf[i+1] = *((char *)&n + 7-i);
|
48
|
+
}
|
49
|
+
#else
|
50
|
+
memcpy(&buf[1], (char *)&n, 8);
|
51
|
+
#endif
|
52
|
+
return rb_str_new(buf, 9);
|
53
|
+
}
|
54
|
+
|
55
|
+
static VALUE packet_s_lcs(VALUE klass, VALUE val)
|
56
|
+
{
|
57
|
+
VALUE ret = packet_s_lcb(klass, ULONG2NUM(RSTRING_LEN(val)));
|
58
|
+
return rb_str_cat(ret, RSTRING_PTR(val), RSTRING_LEN(val));
|
59
|
+
}
|
60
|
+
|
61
|
+
static VALUE packet_allocate(VALUE klass)
|
62
|
+
{
|
63
|
+
packet_data_t *data;
|
64
|
+
|
65
|
+
data = xmalloc(sizeof *data);
|
66
|
+
data->ptr = NULL;
|
67
|
+
data->endp = NULL;
|
68
|
+
return Data_Wrap_Struct(klass, 0, xfree, data);
|
69
|
+
}
|
70
|
+
|
71
|
+
static VALUE packet_initialize(VALUE obj, VALUE buf)
|
72
|
+
{
|
73
|
+
packet_data_t *data;
|
74
|
+
|
75
|
+
Data_Get_Struct(obj, packet_data_t, data);
|
76
|
+
rb_ivar_set(obj, rb_intern("buf"), buf);
|
77
|
+
data->ptr = RSTRING_PTR(buf);
|
78
|
+
data->endp = data->ptr + RSTRING_LEN(buf);
|
79
|
+
}
|
80
|
+
|
81
|
+
#define NIL_VALUE 0xFFFFFFFFFFFFFFFF
|
82
|
+
|
83
|
+
static unsigned long long _packet_lcb(packet_data_t *data)
|
84
|
+
{
|
85
|
+
unsigned char v;
|
86
|
+
unsigned long long n = 0;
|
87
|
+
|
88
|
+
if (data->ptr >= data->endp)
|
89
|
+
return NIL_VALUE;
|
90
|
+
|
91
|
+
v = *data->ptr++;
|
92
|
+
switch (v) {
|
93
|
+
case 0xfb:
|
94
|
+
return NIL_VALUE;
|
95
|
+
case 0xfc:
|
96
|
+
n = *data->ptr++;
|
97
|
+
n |= ((unsigned int)*data->ptr++) << 8;
|
98
|
+
return n;
|
99
|
+
case 0xfd:
|
100
|
+
n = *data->ptr++;
|
101
|
+
n |= ((unsigned int)*data->ptr++) << 8;
|
102
|
+
n |= ((unsigned int)*data->ptr++) << 16;
|
103
|
+
return n;
|
104
|
+
case 0xfe:
|
105
|
+
n = *data->ptr++;
|
106
|
+
n |= ((unsigned long long)*data->ptr++) << 8;
|
107
|
+
n |= ((unsigned long long)*data->ptr++) << 16;
|
108
|
+
n |= ((unsigned long long)*data->ptr++) << 24;
|
109
|
+
n |= ((unsigned long long)*data->ptr++) << 32;
|
110
|
+
n |= ((unsigned long long)*data->ptr++) << 40;
|
111
|
+
n |= ((unsigned long long)*data->ptr++) << 48;
|
112
|
+
n |= ((unsigned long long)*data->ptr++) << 56;
|
113
|
+
return n;
|
114
|
+
default:
|
115
|
+
return v;
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
static VALUE packet_lcb(VALUE obj)
|
120
|
+
{
|
121
|
+
packet_data_t *data;
|
122
|
+
unsigned char v;
|
123
|
+
unsigned long long n;
|
124
|
+
|
125
|
+
Data_Get_Struct(obj, packet_data_t, data);
|
126
|
+
n = _packet_lcb(data);
|
127
|
+
if (n == NIL_VALUE)
|
128
|
+
return Qnil;
|
129
|
+
return ULL2NUM(n);
|
130
|
+
}
|
131
|
+
|
132
|
+
static VALUE _packet_lcs(packet_data_t *data)
|
133
|
+
{
|
134
|
+
unsigned long long l;
|
135
|
+
VALUE ret;
|
136
|
+
|
137
|
+
l = _packet_lcb(data);
|
138
|
+
if (l == NIL_VALUE)
|
139
|
+
return Qnil;
|
140
|
+
if (data->ptr+l > data->endp)
|
141
|
+
l = data->endp - data->ptr;
|
142
|
+
ret = rb_str_new(data->ptr, l);
|
143
|
+
data->ptr += l;
|
144
|
+
return ret;
|
145
|
+
}
|
146
|
+
|
147
|
+
static VALUE packet_lcs(VALUE obj)
|
148
|
+
{
|
149
|
+
packet_data_t *data;
|
150
|
+
unsigned long long l;
|
151
|
+
VALUE ret;
|
152
|
+
|
153
|
+
Data_Get_Struct(obj, packet_data_t, data);
|
154
|
+
return _packet_lcs(data);
|
155
|
+
}
|
156
|
+
|
157
|
+
static VALUE packet_read(VALUE obj, VALUE len)
|
158
|
+
{
|
159
|
+
packet_data_t *data;
|
160
|
+
unsigned long long l = NUM2ULL(len);
|
161
|
+
VALUE ret;
|
162
|
+
|
163
|
+
Data_Get_Struct(obj, packet_data_t, data);
|
164
|
+
if (data->ptr+l > data->endp)
|
165
|
+
l = data->endp - data->ptr;
|
166
|
+
ret = rb_str_new(data->ptr, l);
|
167
|
+
data->ptr += l;
|
168
|
+
return ret;
|
169
|
+
}
|
170
|
+
|
171
|
+
static VALUE packet_string(VALUE obj)
|
172
|
+
{
|
173
|
+
packet_data_t *data;
|
174
|
+
unsigned char *p;
|
175
|
+
VALUE ret;
|
176
|
+
|
177
|
+
Data_Get_Struct(obj, packet_data_t, data);
|
178
|
+
p = data->ptr;
|
179
|
+
while (p < data->endp && *p++ != '\0')
|
180
|
+
;
|
181
|
+
ret = rb_str_new(data->ptr, (p - data->ptr)-1);
|
182
|
+
data->ptr = p;
|
183
|
+
return ret;
|
184
|
+
}
|
185
|
+
|
186
|
+
static VALUE packet_utiny(VALUE obj)
|
187
|
+
{
|
188
|
+
packet_data_t *data;
|
189
|
+
|
190
|
+
Data_Get_Struct(obj, packet_data_t, data);
|
191
|
+
return UINT2NUM(*data->ptr++);
|
192
|
+
}
|
193
|
+
|
194
|
+
static VALUE packet_ushort(VALUE obj)
|
195
|
+
{
|
196
|
+
packet_data_t *data;
|
197
|
+
unsigned short n;
|
198
|
+
|
199
|
+
Data_Get_Struct(obj, packet_data_t, data);
|
200
|
+
n = *data->ptr++;
|
201
|
+
n |= *data->ptr++ * 0x100;
|
202
|
+
return UINT2NUM(n);
|
203
|
+
}
|
204
|
+
|
205
|
+
static VALUE packet_ulong(VALUE obj)
|
206
|
+
{
|
207
|
+
packet_data_t *data;
|
208
|
+
unsigned long n;
|
209
|
+
|
210
|
+
Data_Get_Struct(obj, packet_data_t, data);
|
211
|
+
n = *data->ptr++;
|
212
|
+
n |= *data->ptr++ * 0x100;
|
213
|
+
n |= *data->ptr++ * 0x10000;
|
214
|
+
n |= *data->ptr++ * 0x1000000;
|
215
|
+
return UINT2NUM(n);
|
216
|
+
}
|
217
|
+
|
218
|
+
static VALUE packet_eofQ(VALUE obj)
|
219
|
+
{
|
220
|
+
packet_data_t *data;
|
221
|
+
|
222
|
+
Data_Get_Struct(obj, packet_data_t, data);
|
223
|
+
if (*data->ptr == 0xfe && data->endp - data->ptr == 5)
|
224
|
+
return Qtrue;
|
225
|
+
else
|
226
|
+
return Qfalse;
|
227
|
+
}
|
228
|
+
|
229
|
+
static VALUE packet_to_s(VALUE obj)
|
230
|
+
{
|
231
|
+
packet_data_t *data;
|
232
|
+
|
233
|
+
Data_Get_Struct(obj, packet_data_t, data);
|
234
|
+
return rb_str_new(data->ptr, data->endp-data->ptr);
|
235
|
+
}
|
236
|
+
|
237
|
+
enum {
|
238
|
+
TYPE_DECIMAL = 0,
|
239
|
+
TYPE_TINY = 1,
|
240
|
+
TYPE_SHORT = 2,
|
241
|
+
TYPE_LONG = 3,
|
242
|
+
TYPE_FLOAT = 4,
|
243
|
+
TYPE_DOUBLE = 5,
|
244
|
+
TYPE_NULL = 6,
|
245
|
+
TYPE_TIMESTAMP = 7,
|
246
|
+
TYPE_LONGLONG = 8,
|
247
|
+
TYPE_INT24 = 9,
|
248
|
+
TYPE_DATE = 10,
|
249
|
+
TYPE_TIME = 11,
|
250
|
+
TYPE_DATETIME = 12,
|
251
|
+
TYPE_YEAR = 13,
|
252
|
+
TYPE_NEWDATE = 14,
|
253
|
+
TYPE_VARCHAR = 15,
|
254
|
+
TYPE_BIT = 16,
|
255
|
+
TYPE_NEWDECIMAL = 246,
|
256
|
+
TYPE_ENUM = 247,
|
257
|
+
TYPE_SET = 248,
|
258
|
+
TYPE_TINY_BLOB = 249,
|
259
|
+
TYPE_MEDIUM_BLOB = 250,
|
260
|
+
TYPE_LONG_BLOB = 251,
|
261
|
+
TYPE_BLOB = 252,
|
262
|
+
TYPE_VAR_STRING = 253,
|
263
|
+
TYPE_STRING = 254,
|
264
|
+
TYPE_GEOMETRY = 255
|
265
|
+
};
|
266
|
+
|
267
|
+
#define UNSIGNED_FLAG 32
|
268
|
+
#define BINARY_CHARSET_NUMBER 63
|
269
|
+
|
270
|
+
static VALUE _protocol_net2value(packet_data_t *data, int type, int uflag)
|
271
|
+
{
|
272
|
+
unsigned long n;
|
273
|
+
unsigned long long ll;
|
274
|
+
float f;
|
275
|
+
double fd;
|
276
|
+
int len;
|
277
|
+
int sign;
|
278
|
+
unsigned long y, m, d, h, mi, s, bs;
|
279
|
+
unsigned char buf[12];
|
280
|
+
|
281
|
+
switch (type) {
|
282
|
+
case TYPE_STRING:
|
283
|
+
case TYPE_VAR_STRING:
|
284
|
+
case TYPE_NEWDECIMAL:
|
285
|
+
case TYPE_BLOB:
|
286
|
+
case TYPE_BIT:
|
287
|
+
return _packet_lcs(data);
|
288
|
+
case TYPE_TINY:
|
289
|
+
n = *data->ptr++;
|
290
|
+
return uflag ? INT2FIX(n) : INT2FIX((char)n);
|
291
|
+
case TYPE_SHORT:
|
292
|
+
case TYPE_YEAR:
|
293
|
+
n = *data->ptr++;
|
294
|
+
n |= *data->ptr++ * 0x100;
|
295
|
+
return uflag ? INT2FIX(n) : INT2FIX((short)n);
|
296
|
+
case TYPE_INT24:
|
297
|
+
case TYPE_LONG:
|
298
|
+
n = *data->ptr++;
|
299
|
+
n |= *data->ptr++ * 0x100;
|
300
|
+
n |= *data->ptr++ * 0x10000;
|
301
|
+
n |= *data->ptr++ * 0x1000000;
|
302
|
+
return uflag ? UINT2NUM(n) : INT2NUM((long)n);
|
303
|
+
case TYPE_LONGLONG:
|
304
|
+
n = *data->ptr++;
|
305
|
+
n |= *data->ptr++ * 0x100;
|
306
|
+
n |= *data->ptr++ * 0x10000;
|
307
|
+
n |= *data->ptr++ * 0x1000000;
|
308
|
+
ll = *data->ptr++;
|
309
|
+
ll |= *data->ptr++ * 0x100;
|
310
|
+
ll |= *data->ptr++ * 0x10000;
|
311
|
+
ll |= *data->ptr++ * 0x1000000;
|
312
|
+
ll = (ll<<32) + n;
|
313
|
+
return uflag ? ULL2NUM(ll) : LL2NUM((long long)(ll));
|
314
|
+
case TYPE_FLOAT:
|
315
|
+
memcpy(&f, data->ptr, 4);
|
316
|
+
data->ptr += 4;
|
317
|
+
return rb_float_new(f);
|
318
|
+
case TYPE_DOUBLE:
|
319
|
+
memcpy(&fd, data->ptr, 8);
|
320
|
+
data->ptr += 8;
|
321
|
+
return rb_float_new(fd);
|
322
|
+
case TYPE_DATE:
|
323
|
+
len = *data->ptr++;
|
324
|
+
memset(buf, 0, sizeof(buf));
|
325
|
+
memcpy(buf, data->ptr, len);
|
326
|
+
data->ptr += len;
|
327
|
+
y = buf[0] | buf[1]<<8;
|
328
|
+
m = buf[2];
|
329
|
+
d = buf[3];
|
330
|
+
return rb_funcall(cMysqlTime, rb_intern("new"), 6, ULONG2NUM(y), ULONG2NUM(m), ULONG2NUM(d), Qnil, Qnil, Qnil);
|
331
|
+
case TYPE_DATETIME:
|
332
|
+
case TYPE_TIMESTAMP:
|
333
|
+
len = *data->ptr++;
|
334
|
+
memset(buf, 0, sizeof(buf));
|
335
|
+
memcpy(buf, data->ptr, len);
|
336
|
+
data->ptr += len;
|
337
|
+
y = buf[0] | buf[1]<<8;
|
338
|
+
m = buf[2];
|
339
|
+
d = buf[3];
|
340
|
+
h = buf[4];
|
341
|
+
mi = buf[5];
|
342
|
+
s = buf[6];
|
343
|
+
bs = buf[7] | buf[8]<<8 | buf[9]<<16 | buf[10]<<24;
|
344
|
+
return rb_funcall(cMysqlTime, rb_intern("new"), 8, ULONG2NUM(y), ULONG2NUM(m), ULONG2NUM(d), ULONG2NUM(h), ULONG2NUM(mi), ULONG2NUM(s), Qfalse, ULONG2NUM(bs));
|
345
|
+
case TYPE_TIME:
|
346
|
+
len = *data->ptr++;
|
347
|
+
memset(buf, 0, sizeof(buf));
|
348
|
+
memcpy(buf, data->ptr, len);
|
349
|
+
data->ptr += len;
|
350
|
+
sign = buf[0];
|
351
|
+
d = buf[1] | buf[2]<<8 | buf[3]<<16 | buf[4]<<24;;
|
352
|
+
h = buf[5];
|
353
|
+
mi = buf[6];
|
354
|
+
s = buf[7];
|
355
|
+
bs = buf[8] | buf[9]<<8 | buf[10]<<16 | buf[11]<<24;;
|
356
|
+
h += d * 24;
|
357
|
+
return rb_funcall(cMysqlTime, rb_intern("new"), 8, ULONG2NUM(0), ULONG2NUM(0), ULONG2NUM(0), ULONG2NUM(h), ULONG2NUM(mi), ULONG2NUM(s), (sign != 0 ? Qtrue : Qfalse), ULONG2NUM(bs));
|
358
|
+
default:
|
359
|
+
rb_raise(rb_eRuntimeError, "%s", "not implemented: type=#{%d}", type);
|
360
|
+
}
|
361
|
+
}
|
362
|
+
|
363
|
+
static VALUE _protocol_value2net(VALUE obj, VALUE netval, VALUE types)
|
364
|
+
{
|
365
|
+
int type;
|
366
|
+
char *ptr;
|
367
|
+
int len;
|
368
|
+
unsigned char buf[8];
|
369
|
+
long n;
|
370
|
+
long long ll;
|
371
|
+
unsigned long long ull;
|
372
|
+
double dbl;
|
373
|
+
|
374
|
+
if (obj == Qnil) {
|
375
|
+
type = TYPE_NULL;
|
376
|
+
ptr = NULL;
|
377
|
+
len = 0;
|
378
|
+
} else if (FIXNUM_P(obj)) {
|
379
|
+
int flag = 0;
|
380
|
+
|
381
|
+
n = FIX2LONG(obj);
|
382
|
+
if (n >= 0) {
|
383
|
+
flag = 0x8000;
|
384
|
+
}
|
385
|
+
ptr = (char *)&n;
|
386
|
+
#ifdef WORDS_BIGENDIAN
|
387
|
+
for (i=0; i<sizeof(n); i++) {
|
388
|
+
buf[i] = n % 0x100;
|
389
|
+
n /= 0x100;
|
390
|
+
}
|
391
|
+
ptr = buf;
|
392
|
+
#endif
|
393
|
+
if (-0x80 <= n && n < 0x100) {
|
394
|
+
type = TYPE_TINY | flag;
|
395
|
+
len = 1;
|
396
|
+
} else if (-0x8000 <= n && n < 0x10000) {
|
397
|
+
type = TYPE_SHORT | flag;
|
398
|
+
len = 2;
|
399
|
+
#if SIZEOF_LONG == 4
|
400
|
+
} else {
|
401
|
+
type = TYPE_LONG | flag;
|
402
|
+
len = 4;
|
403
|
+
#else
|
404
|
+
} else if (-0x80000000 <= n && n < 0x100000000) {
|
405
|
+
type = TYPE_LONG | flag;
|
406
|
+
len = 4;
|
407
|
+
} else {
|
408
|
+
type = TYPE_LONGLONG | flag;
|
409
|
+
len = 8;
|
410
|
+
#endif
|
411
|
+
}
|
412
|
+
} else if (TYPE(obj) == T_BIGNUM) {
|
413
|
+
if (RBIGNUM_SIGN(obj)) {
|
414
|
+
ull = NUM2ULL(obj);
|
415
|
+
ptr = (char *)&ull;
|
416
|
+
type = TYPE_LONGLONG | 0x8000;
|
417
|
+
len = sizeof(ull);
|
418
|
+
#ifdef WORDS_BIGENDIAN
|
419
|
+
for (i=0; i<len; i++) {
|
420
|
+
buf[i] = ull % 0x100;
|
421
|
+
ull /= 0x100;
|
422
|
+
}
|
423
|
+
ptr = buf;
|
424
|
+
#endif
|
425
|
+
} else {
|
426
|
+
ll = NUM2LL(obj);
|
427
|
+
ptr = (char *)≪
|
428
|
+
type = TYPE_LONGLONG;
|
429
|
+
len = sizeof(ll);
|
430
|
+
#ifdef WORDS_BIGENDIAN
|
431
|
+
for (i=0; i<len; i++) {
|
432
|
+
buf[i] = ll % 0x100;
|
433
|
+
ll /= 0x100;
|
434
|
+
}
|
435
|
+
ptr = buf;
|
436
|
+
#endif
|
437
|
+
}
|
438
|
+
} else if (rb_obj_is_kind_of(obj, rb_cFloat)) {
|
439
|
+
dbl = NUM2DBL(obj);
|
440
|
+
type = TYPE_DOUBLE;
|
441
|
+
ptr = (char *)&dbl;
|
442
|
+
len = sizeof(dbl);
|
443
|
+
} else if (rb_obj_is_kind_of(obj, rb_cString)) {
|
444
|
+
VALUE val;
|
445
|
+
|
446
|
+
type = TYPE_STRING;
|
447
|
+
val = packet_s_lcs(0, obj);
|
448
|
+
ptr = RSTRING_PTR(val);
|
449
|
+
len = RSTRING_LEN(val);
|
450
|
+
} else if (rb_obj_is_kind_of(obj, cMysqlTime) || rb_obj_is_kind_of(obj, rb_cTime)) {
|
451
|
+
int year, month, day, hour, min, sec;
|
452
|
+
|
453
|
+
year = FIX2INT(rb_funcall(obj, rb_intern("year"), 0));
|
454
|
+
month = FIX2INT(rb_funcall(obj, rb_intern("month"), 0));
|
455
|
+
day = FIX2INT(rb_funcall(obj, rb_intern("day"), 0));
|
456
|
+
hour = FIX2INT(rb_funcall(obj, rb_intern("hour"), 0));
|
457
|
+
min = FIX2INT(rb_funcall(obj, rb_intern("min"), 0));
|
458
|
+
sec = FIX2INT(rb_funcall(obj, rb_intern("sec"), 0));
|
459
|
+
type = TYPE_DATETIME;
|
460
|
+
buf[0] = 7;
|
461
|
+
buf[1] = year & 0xff;
|
462
|
+
buf[2] = (year >> 8) & 0xff;
|
463
|
+
buf[3] = month;
|
464
|
+
buf[4] = day;
|
465
|
+
buf[5] = hour;
|
466
|
+
buf[6] = min;
|
467
|
+
buf[7] = sec;
|
468
|
+
ptr = buf;
|
469
|
+
len = 8;
|
470
|
+
} else {
|
471
|
+
rb_raise(eProtocolError, "class %s is not supported", rb_class2name(rb_obj_class(obj)));
|
472
|
+
}
|
473
|
+
rb_str_cat(netval, ptr, len);
|
474
|
+
buf[0] = type % 256;
|
475
|
+
buf[1] = type / 256;
|
476
|
+
rb_str_cat(types, buf, 2);
|
477
|
+
return Qnil;
|
478
|
+
}
|
479
|
+
|
480
|
+
VALUE stmt_raw_record_parse_record_packet(VALUE obj)
|
481
|
+
{
|
482
|
+
VALUE packet;
|
483
|
+
VALUE fields;
|
484
|
+
packet_data_t *data;
|
485
|
+
int nfields;
|
486
|
+
int bitmap_length;
|
487
|
+
char *bitmap;
|
488
|
+
int i;
|
489
|
+
VALUE rec;
|
490
|
+
|
491
|
+
packet = rb_iv_get(obj, "@packet");
|
492
|
+
fields = rb_iv_get(obj, "@fields");
|
493
|
+
Data_Get_Struct(packet, packet_data_t, data);
|
494
|
+
data->ptr++;
|
495
|
+
nfields = RARRAY_LEN(fields);
|
496
|
+
bitmap_length = (nfields+7+2)/8;
|
497
|
+
bitmap = data->ptr;
|
498
|
+
data->ptr += bitmap_length;
|
499
|
+
rec = rb_ary_new2(nfields);
|
500
|
+
for (i = 0; i < nfields; i++) {
|
501
|
+
if ((bitmap[(i+2)/8] >> (i+2)%8) & 1) {
|
502
|
+
rb_ary_push(rec, Qnil);
|
503
|
+
} else {
|
504
|
+
VALUE field, u_flag, value;
|
505
|
+
field = RARRAY_PTR(fields)[i];
|
506
|
+
u_flag = FIX2INT(rb_iv_get(field, "@flags")) & UNSIGNED_FLAG;
|
507
|
+
value = _protocol_net2value(data, FIX2INT(rb_iv_get(field, "@type")), u_flag);
|
508
|
+
if (rb_obj_is_kind_of(value, rb_cNumeric) || rb_obj_is_kind_of(value, cMysqlTime)) {
|
509
|
+
rb_ary_push(rec, value);
|
510
|
+
} else if (FIX2INT(rb_iv_get(field, "@type")) == TYPE_BIT || FIX2INT(rb_iv_get(field, "@charsetnr")) == BINARY_CHARSET_NUMBER) {
|
511
|
+
rb_ary_push(rec, rb_funcall(cCharset, rb_intern("to_binary"), 1, value));
|
512
|
+
} else {
|
513
|
+
rb_ary_push(rec, rb_funcall(cCharset, rb_intern("convert_encoding"), 2, value, rb_iv_get(obj, "@encoding")));
|
514
|
+
}
|
515
|
+
}
|
516
|
+
}
|
517
|
+
return rec;
|
518
|
+
}
|
519
|
+
|
520
|
+
#define COM_STMT_EXECUTE 23
|
521
|
+
|
522
|
+
VALUE execute_packet_serialize(VALUE obj, VALUE stmt_id, VALUE cursor_type, VALUE values)
|
523
|
+
{
|
524
|
+
VALUE *ary = RARRAY_PTR(values);
|
525
|
+
int len = RARRAY_LEN(values);
|
526
|
+
char *null_bitmap;
|
527
|
+
int i;
|
528
|
+
int null_bitmap_len = 0;
|
529
|
+
unsigned long int_stmt_id = NUM2ULONG(stmt_id);
|
530
|
+
unsigned char buf[10];
|
531
|
+
VALUE netval;
|
532
|
+
VALUE types;
|
533
|
+
VALUE ret;
|
534
|
+
|
535
|
+
buf[0] = COM_STMT_EXECUTE;
|
536
|
+
buf[1] = int_stmt_id % 0x100;
|
537
|
+
buf[2] = (int_stmt_id / 0x100) % 0x100;
|
538
|
+
buf[3] = (int_stmt_id / 0x10000) % 0x100;
|
539
|
+
buf[4] = (int_stmt_id / 0x1000000) % 0x100;
|
540
|
+
buf[5] = FIX2INT(cursor_type);
|
541
|
+
buf[6] = 1;
|
542
|
+
buf[7] = 0;
|
543
|
+
buf[8] = 0;
|
544
|
+
buf[9] = 0;
|
545
|
+
ret = rb_str_new(buf, 10);
|
546
|
+
|
547
|
+
if (len == 0) {
|
548
|
+
return rb_str_cat(ret, "\x01", 1);
|
549
|
+
}
|
550
|
+
null_bitmap_len = (len - 1) / 8 + 1;
|
551
|
+
null_bitmap = xmalloc(null_bitmap_len);
|
552
|
+
memset(null_bitmap, 0, null_bitmap_len);
|
553
|
+
netval = rb_str_new("", 0);
|
554
|
+
types = rb_str_new("", 0);
|
555
|
+
for (i = 0; i < RARRAY_LEN(values); i++) {
|
556
|
+
if (ary[i] == Qnil) {
|
557
|
+
null_bitmap[i/8] |= 1 << (i%8);
|
558
|
+
}
|
559
|
+
_protocol_value2net(ary[i], netval, types);
|
560
|
+
}
|
561
|
+
rb_str_cat(ret, null_bitmap, null_bitmap_len);
|
562
|
+
rb_str_cat(ret, "\x01", 1);
|
563
|
+
rb_str_concat(ret, types);
|
564
|
+
rb_str_concat(ret, netval);
|
565
|
+
return ret;
|
566
|
+
}
|
567
|
+
|
568
|
+
void Init_ext(void)
|
569
|
+
{
|
570
|
+
cMysql = rb_const_get(rb_cObject, rb_intern("Mysql"));
|
571
|
+
cPacket = rb_const_get(cMysql, rb_intern("Packet"));
|
572
|
+
cMysqlTime = rb_define_class_under(cMysql, "Time", rb_cObject);
|
573
|
+
cProtocol = rb_const_get(cMysql, rb_intern("Protocol"));
|
574
|
+
cStmtRawRecord = rb_const_get(cMysql, rb_intern("StmtRawRecord"));
|
575
|
+
cExecutePacket = rb_const_get(cProtocol, rb_intern("ExecutePacket"));
|
576
|
+
cCharset = rb_const_get(cMysql, rb_intern("Charset"));
|
577
|
+
eProtocolError = rb_const_get(cMysql, rb_intern("ProtocolError"));
|
578
|
+
|
579
|
+
rb_define_alloc_func(cPacket, packet_allocate);
|
580
|
+
rb_define_singleton_method(cPacket, "lcb", packet_s_lcb, 1);
|
581
|
+
rb_define_singleton_method(cPacket, "lcs", packet_s_lcs, 1);
|
582
|
+
rb_define_method(cPacket, "initialize", packet_initialize, 1);
|
583
|
+
rb_define_method(cPacket, "lcb", packet_lcb, 0);
|
584
|
+
rb_define_method(cPacket, "lcs", packet_lcs, 0);
|
585
|
+
rb_define_method(cPacket, "read", packet_read, 1);
|
586
|
+
rb_define_method(cPacket, "string", packet_string, 0);
|
587
|
+
rb_define_method(cPacket, "utiny", packet_utiny, 0);
|
588
|
+
rb_define_method(cPacket, "ushort", packet_ushort, 0);
|
589
|
+
rb_define_method(cPacket, "ulong", packet_ulong, 0);
|
590
|
+
rb_define_method(cPacket, "eof?", packet_eofQ, 0);
|
591
|
+
rb_define_method(cPacket, "to_s", packet_to_s, 0);
|
592
|
+
|
593
|
+
rb_define_method(cStmtRawRecord, "parse_record_packet", stmt_raw_record_parse_record_packet, 0);
|
594
|
+
rb_define_alias(cStmtRawRecord, "to_a", "parse_record_packet");
|
595
|
+
|
596
|
+
rb_define_singleton_method(cExecutePacket, "serialize", execute_packet_serialize, 3);
|
597
|
+
}
|
data/ext/mysql/extconf.rb
CHANGED
data/lib/mysql.rb
CHANGED
@@ -14,13 +14,13 @@ class Mysql
|
|
14
14
|
require "mysql/error"
|
15
15
|
require "mysql/charset"
|
16
16
|
require "mysql/protocol"
|
17
|
+
require "mysql/packet.rb"
|
17
18
|
begin
|
18
|
-
require "mysql/
|
19
|
+
require "mysql/ext.so"
|
19
20
|
rescue LoadError
|
20
|
-
require "mysql/packet.rb"
|
21
21
|
end
|
22
22
|
|
23
|
-
VERSION =
|
23
|
+
VERSION = 20909 # Version number of this library
|
24
24
|
MYSQL_UNIX_PORT = "/tmp/mysql.sock" # UNIX domain socket filename
|
25
25
|
MYSQL_TCP_PORT = 3306 # TCP socket port number
|
26
26
|
|
@@ -1054,6 +1054,7 @@ class Mysql
|
|
1054
1054
|
# @param [Boolean] neg negative flag
|
1055
1055
|
# @param [Integer] second_part
|
1056
1056
|
def initialize(year=0, month=0, day=0, hour=0, minute=0, second=0, neg=false, second_part=0)
|
1057
|
+
@date_flag = !(hour && minute && second)
|
1057
1058
|
@year, @month, @day, @hour, @minute, @second, @neg, @second_part =
|
1058
1059
|
year.to_i, month.to_i, day.to_i, hour.to_i, minute.to_i, second.to_i, neg, second_part.to_i
|
1059
1060
|
end
|
@@ -1077,7 +1078,9 @@ class Mysql
|
|
1077
1078
|
|
1078
1079
|
# @return [String] "yyyy-mm-dd HH:MM:SS"
|
1079
1080
|
def to_s
|
1080
|
-
if
|
1081
|
+
if @date_flag
|
1082
|
+
sprintf "%04d-%02d-%02d", year, mon, day
|
1083
|
+
elsif year == 0 and mon == 0 and day == 0
|
1081
1084
|
h = neg ? hour * -1 : hour
|
1082
1085
|
sprintf "%02d:%02d:%02d", h, min, sec
|
1083
1086
|
else
|
data/lib/mysql/packet.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
class Mysql
|
2
|
+
class Packet
|
3
|
+
# convert Numeric to LengthCodedBinary
|
4
|
+
def self.lcb(num)
|
5
|
+
return "\xfb" if num.nil?
|
6
|
+
return [num].pack("C") if num < 251
|
7
|
+
return [252, num].pack("Cv") if num < 65536
|
8
|
+
return [253, num&0xffff, num>>16].pack("CvC") if num < 16777216
|
9
|
+
return [254, num&0xffffffff, num>>32].pack("CVV")
|
10
|
+
end
|
11
|
+
|
12
|
+
# convert String to LengthCodedString
|
13
|
+
def self.lcs(str)
|
14
|
+
str = Charset.to_binary str
|
15
|
+
lcb(str.length)+str
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(data)
|
19
|
+
@data = data
|
20
|
+
end
|
21
|
+
|
22
|
+
def lcb
|
23
|
+
return nil if @data.empty?
|
24
|
+
case v = utiny
|
25
|
+
when 0xfb
|
26
|
+
return nil
|
27
|
+
when 0xfc
|
28
|
+
return ushort
|
29
|
+
when 0xfd
|
30
|
+
c, v = utiny, ushort
|
31
|
+
return (v << 8)+c
|
32
|
+
when 0xfe
|
33
|
+
v1, v2 = ulong, ulong
|
34
|
+
return (v2 << 32)+v1
|
35
|
+
else
|
36
|
+
return v
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def lcs
|
41
|
+
len = self.lcb
|
42
|
+
return nil unless len
|
43
|
+
@data.slice!(0, len)
|
44
|
+
end
|
45
|
+
|
46
|
+
def read(len)
|
47
|
+
@data.slice!(0, len)
|
48
|
+
end
|
49
|
+
|
50
|
+
def string
|
51
|
+
str = @data.unpack('Z*').first
|
52
|
+
@data.slice!(0, str.length+1)
|
53
|
+
str
|
54
|
+
end
|
55
|
+
|
56
|
+
def utiny
|
57
|
+
@data.slice!(0, 1).unpack('C').first
|
58
|
+
end
|
59
|
+
|
60
|
+
def ushort
|
61
|
+
@data.slice!(0, 2).unpack('v').first
|
62
|
+
end
|
63
|
+
|
64
|
+
def ulong
|
65
|
+
@data.slice!(0, 4).unpack('V').first
|
66
|
+
end
|
67
|
+
|
68
|
+
def eof?
|
69
|
+
@data[0] == ?\xfe && @data.length == 5
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_s
|
73
|
+
@data
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
data/lib/mysql/protocol.rb
CHANGED
@@ -44,15 +44,12 @@ class Mysql
|
|
44
44
|
when Field::TYPE_DATE
|
45
45
|
len = pkt.utiny
|
46
46
|
y, m, d = pkt.read(len).unpack("vCC")
|
47
|
-
t = Mysql::Time.new(y, m, d)
|
48
|
-
def t.to_s
|
49
|
-
sprintf "%04d-%02d-%02d", year, mon ,day
|
50
|
-
end
|
47
|
+
t = Mysql::Time.new(y, m, d, nil, nil, nil)
|
51
48
|
return t
|
52
49
|
when Field::TYPE_DATETIME, Field::TYPE_TIMESTAMP
|
53
50
|
len = pkt.utiny
|
54
|
-
y, m, d, h, mi, s,
|
55
|
-
return Mysql::Time.new(y, m, d, h, mi, s,
|
51
|
+
y, m, d, h, mi, s, sp = pkt.read(len).unpack("vCCCCCV")
|
52
|
+
return Mysql::Time.new(y, m, d, h, mi, s, false, sp)
|
56
53
|
when Field::TYPE_TIME
|
57
54
|
len = pkt.utiny
|
58
55
|
sign, d, h, mi, s, sp = pkt.read(len).unpack("CVCCCV")
|
@@ -423,10 +420,11 @@ class Mysql
|
|
423
420
|
# [Array of Array of Object] all records
|
424
421
|
def stmt_retr_all_records(fields, charset)
|
425
422
|
check_state :RESULT
|
423
|
+
enc = charset.encoding
|
426
424
|
begin
|
427
425
|
all_recs = []
|
428
|
-
until (
|
429
|
-
all_recs.push StmtRawRecord.new(
|
426
|
+
until (pkt = read).eof?
|
427
|
+
all_recs.push StmtRawRecord.new(pkt, fields, enc)
|
430
428
|
end
|
431
429
|
all_recs
|
432
430
|
ensure
|
@@ -494,13 +492,13 @@ class Mysql
|
|
494
492
|
begin
|
495
493
|
Timeout.timeout @read_timeout do
|
496
494
|
header = @sock.read(4)
|
497
|
-
raise EOFError unless header.length == 4
|
495
|
+
raise EOFError unless header && header.length == 4
|
498
496
|
len1, len2, seq = header.unpack("CvC")
|
499
497
|
len = (len2 << 8) + len1
|
500
498
|
raise ProtocolError, "invalid packet: sequence number mismatch(#{seq} != #{@seq}(expected))" if @seq != seq
|
501
499
|
@seq = (@seq + 1) % 256
|
502
500
|
ret = @sock.read(len)
|
503
|
-
raise EOFError unless ret.length == len
|
501
|
+
raise EOFError unless ret && ret.length == len
|
504
502
|
end
|
505
503
|
rescue EOFError
|
506
504
|
raise ClientError::ServerGoneError, 'The MySQL server has gone away'
|
data/spec/mysql_spec.rb
CHANGED
@@ -13,7 +13,7 @@ MYSQL_SOCKET = ENV['MYSQL_SOCKET']
|
|
13
13
|
|
14
14
|
describe 'Mysql::VERSION' do
|
15
15
|
it 'returns client version' do
|
16
|
-
Mysql::VERSION.should ==
|
16
|
+
Mysql::VERSION.should == 20909
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
@@ -649,6 +649,7 @@ end
|
|
649
649
|
describe 'Mysql::Result' do
|
650
650
|
before do
|
651
651
|
@m = Mysql.new(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET)
|
652
|
+
@m.charset = 'latin1'
|
652
653
|
@m.query 'create temporary table t (id int, str char(10), primary key (id))'
|
653
654
|
@m.query "insert into t values (1,'abc'),(2,'defg'),(3,'hi'),(4,null)"
|
654
655
|
@res = @m.query 'select * from t'
|
@@ -808,6 +809,7 @@ end
|
|
808
809
|
describe 'Mysql::Field' do
|
809
810
|
before do
|
810
811
|
@m = Mysql.new(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET)
|
812
|
+
@m.charset = 'latin1'
|
811
813
|
@m.query 'create temporary table t (id int default 0, str char(10), primary key (id))'
|
812
814
|
@m.query "insert into t values (1,'abc'),(2,'defg'),(3,'hi'),(4,null)"
|
813
815
|
@res = @m.query 'select * from t'
|
@@ -1065,6 +1067,99 @@ describe 'Mysql::Stmt' do
|
|
1065
1067
|
end
|
1066
1068
|
end
|
1067
1069
|
|
1070
|
+
describe '#execute with various integer value:' do
|
1071
|
+
before do
|
1072
|
+
@m.query('create temporary table t (i bigint)')
|
1073
|
+
end
|
1074
|
+
[
|
1075
|
+
-9223372036854775808,
|
1076
|
+
-9223372036854775807,
|
1077
|
+
-4294967297,
|
1078
|
+
-4294967296,
|
1079
|
+
-4294967295,
|
1080
|
+
-2147483649,
|
1081
|
+
-2147483648,
|
1082
|
+
-2147483647,
|
1083
|
+
-65537,
|
1084
|
+
-65536,
|
1085
|
+
-65535,
|
1086
|
+
-32769,
|
1087
|
+
-32768,
|
1088
|
+
-32767,
|
1089
|
+
-257,
|
1090
|
+
-256,
|
1091
|
+
-255,
|
1092
|
+
-129,
|
1093
|
+
-128,
|
1094
|
+
-127,
|
1095
|
+
0,
|
1096
|
+
126,
|
1097
|
+
127,
|
1098
|
+
128,
|
1099
|
+
254,
|
1100
|
+
255,
|
1101
|
+
256,
|
1102
|
+
32766,
|
1103
|
+
32767,
|
1104
|
+
32768,
|
1105
|
+
65534,
|
1106
|
+
65535,
|
1107
|
+
65536,
|
1108
|
+
2147483646,
|
1109
|
+
2147483647,
|
1110
|
+
2147483648,
|
1111
|
+
4294967294,
|
1112
|
+
4294967295,
|
1113
|
+
4294967296,
|
1114
|
+
9223372036854775806,
|
1115
|
+
9223372036854775807,
|
1116
|
+
].each do |n|
|
1117
|
+
it "#{n} is #{n}" do
|
1118
|
+
@s.prepare 'insert into t values (?)'
|
1119
|
+
@s.execute n
|
1120
|
+
@m.query('select i from t').fetch.should == ["#{n}"]
|
1121
|
+
end
|
1122
|
+
end
|
1123
|
+
end
|
1124
|
+
|
1125
|
+
describe '#execute with various unsigned integer value:' do
|
1126
|
+
before do
|
1127
|
+
@m.query('create temporary table t (i bigint unsigned)')
|
1128
|
+
end
|
1129
|
+
[
|
1130
|
+
0,
|
1131
|
+
126,
|
1132
|
+
127,
|
1133
|
+
128,
|
1134
|
+
254,
|
1135
|
+
255,
|
1136
|
+
256,
|
1137
|
+
32766,
|
1138
|
+
32767,
|
1139
|
+
32768,
|
1140
|
+
65534,
|
1141
|
+
65535,
|
1142
|
+
65536,
|
1143
|
+
2147483646,
|
1144
|
+
2147483647,
|
1145
|
+
2147483648,
|
1146
|
+
4294967294,
|
1147
|
+
4294967295,
|
1148
|
+
4294967296,
|
1149
|
+
9223372036854775806,
|
1150
|
+
9223372036854775807,
|
1151
|
+
9223372036854775808,
|
1152
|
+
18446744073709551614,
|
1153
|
+
18446744073709551615,
|
1154
|
+
].each do |n|
|
1155
|
+
it "#{n} is #{n}" do
|
1156
|
+
@s.prepare 'insert into t values (?)'
|
1157
|
+
@s.execute n
|
1158
|
+
@m.query('select i from t').fetch.should == ["#{n}"]
|
1159
|
+
end
|
1160
|
+
end
|
1161
|
+
end
|
1162
|
+
|
1068
1163
|
it '#fetch returns result-record' do
|
1069
1164
|
@s.prepare 'select 123, "abc", null'
|
1070
1165
|
@s.execute
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-mysql-ext
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.9.
|
4
|
+
version: 2.9.9
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-06-17 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: This is MySQL connector with C extension.
|
15
15
|
email: tommy@tmtm.org
|
@@ -25,7 +25,8 @@ files:
|
|
25
25
|
- lib/mysql/protocol.rb
|
26
26
|
- lib/mysql/charset.rb
|
27
27
|
- lib/mysql/error.rb
|
28
|
-
-
|
28
|
+
- lib/mysql/packet.rb
|
29
|
+
- ext/mysql/ext.c
|
29
30
|
- spec/mysql_spec.rb
|
30
31
|
- spec/mysql/packet_spec.rb
|
31
32
|
- ext/mysql/extconf.rb
|
data/ext/mysql/packet.c
DELETED
@@ -1,246 +0,0 @@
|
|
1
|
-
#include "ruby.h"
|
2
|
-
|
3
|
-
typedef struct {
|
4
|
-
unsigned char *ptr;
|
5
|
-
unsigned char *endp;
|
6
|
-
} data_t;
|
7
|
-
|
8
|
-
static VALUE s_lcb(VALUE klass, VALUE val)
|
9
|
-
{
|
10
|
-
unsigned long long n;
|
11
|
-
unsigned char buf[9];
|
12
|
-
|
13
|
-
if (val == Qnil)
|
14
|
-
return rb_str_new("\xfb", 1);
|
15
|
-
n = NUM2ULL(val);
|
16
|
-
if (n < 251) {
|
17
|
-
buf[0] = n;
|
18
|
-
return rb_str_new(buf, 1);
|
19
|
-
}
|
20
|
-
if (n < 65536) {
|
21
|
-
buf[0] = '\xfc';
|
22
|
-
buf[1] = n % 256;
|
23
|
-
buf[2] = n / 256;
|
24
|
-
return rb_str_new(buf, 3);
|
25
|
-
}
|
26
|
-
if (n < 16777216) {
|
27
|
-
buf[0] = '\xfd';
|
28
|
-
buf[1] = n % 256;
|
29
|
-
n /= 256;
|
30
|
-
buf[2] = n % 256;
|
31
|
-
buf[3] = n / 256;
|
32
|
-
return rb_str_new(buf, 4);
|
33
|
-
}
|
34
|
-
buf[0] = '\xfe';
|
35
|
-
buf[1] = n % 256;
|
36
|
-
n /= 256;
|
37
|
-
buf[2] = n % 256;
|
38
|
-
n /= 256;
|
39
|
-
buf[3] = n % 256;
|
40
|
-
n /= 256;
|
41
|
-
buf[4] = n % 256;
|
42
|
-
n /= 256;
|
43
|
-
buf[5] = n % 256;
|
44
|
-
n /= 256;
|
45
|
-
buf[6] = n % 256;
|
46
|
-
n /= 256;
|
47
|
-
buf[7] = n % 256;
|
48
|
-
buf[8] = n / 256;
|
49
|
-
return rb_str_new(buf, 9);
|
50
|
-
}
|
51
|
-
|
52
|
-
static VALUE s_lcs(VALUE klass, VALUE val)
|
53
|
-
{
|
54
|
-
VALUE ret = s_lcb(klass, ULONG2NUM(RSTRING_LEN(val)));
|
55
|
-
return rb_str_cat(ret, RSTRING_PTR(val), RSTRING_LEN(val));
|
56
|
-
}
|
57
|
-
|
58
|
-
static VALUE allocate(VALUE klass)
|
59
|
-
{
|
60
|
-
data_t *data;
|
61
|
-
|
62
|
-
data = xmalloc(sizeof *data);
|
63
|
-
data->ptr = NULL;
|
64
|
-
data->endp = NULL;
|
65
|
-
return Data_Wrap_Struct(klass, 0, xfree, data);
|
66
|
-
}
|
67
|
-
|
68
|
-
static VALUE initialize(VALUE obj, VALUE buf)
|
69
|
-
{
|
70
|
-
data_t *data;
|
71
|
-
|
72
|
-
Data_Get_Struct(obj, data_t, data);
|
73
|
-
rb_ivar_set(obj, rb_intern("buf"), buf);
|
74
|
-
data->ptr = RSTRING_PTR(buf);
|
75
|
-
data->endp = data->ptr + RSTRING_LEN(buf);
|
76
|
-
}
|
77
|
-
|
78
|
-
#define NIL_VALUE 0xFFFFFFFFFFFFFFFF
|
79
|
-
|
80
|
-
static unsigned long long _lcb(data_t *data)
|
81
|
-
{
|
82
|
-
unsigned char v;
|
83
|
-
unsigned long long n;
|
84
|
-
|
85
|
-
if (data->ptr >= data->endp)
|
86
|
-
return NIL_VALUE;
|
87
|
-
|
88
|
-
v = *data->ptr++;
|
89
|
-
switch (v) {
|
90
|
-
case 0xfb:
|
91
|
-
return NIL_VALUE;
|
92
|
-
case 0xfc:
|
93
|
-
n = *data->ptr++;
|
94
|
-
n |= ((unsigned int)*data->ptr++) << 8;
|
95
|
-
return n;
|
96
|
-
case 0xfd:
|
97
|
-
n = *data->ptr++;
|
98
|
-
n |= ((unsigned int)*data->ptr++) << 8;
|
99
|
-
n |= ((unsigned int)*data->ptr++) << 16;
|
100
|
-
return n;
|
101
|
-
case 0xfe:
|
102
|
-
n = *data->ptr++;
|
103
|
-
n |= ((unsigned long long)*data->ptr++) << 8;
|
104
|
-
n |= ((unsigned long long)*data->ptr++) << 16;
|
105
|
-
n |= ((unsigned long long)*data->ptr++) << 24;
|
106
|
-
n |= ((unsigned long long)*data->ptr++) << 32;
|
107
|
-
n |= ((unsigned long long)*data->ptr++) << 40;
|
108
|
-
n |= ((unsigned long long)*data->ptr++) << 48;
|
109
|
-
n |= ((unsigned long long)*data->ptr++) << 56;
|
110
|
-
return n;
|
111
|
-
default:
|
112
|
-
return v;
|
113
|
-
}
|
114
|
-
}
|
115
|
-
|
116
|
-
static VALUE lcb(VALUE obj)
|
117
|
-
{
|
118
|
-
data_t *data;
|
119
|
-
unsigned char v;
|
120
|
-
unsigned long long n;
|
121
|
-
|
122
|
-
Data_Get_Struct(obj, data_t, data);
|
123
|
-
n = _lcb(data);
|
124
|
-
if (n == NIL_VALUE)
|
125
|
-
return Qnil;
|
126
|
-
return ULL2NUM(n);
|
127
|
-
}
|
128
|
-
|
129
|
-
static VALUE lcs(VALUE obj)
|
130
|
-
{
|
131
|
-
data_t *data;
|
132
|
-
unsigned long long l;
|
133
|
-
VALUE ret;
|
134
|
-
|
135
|
-
Data_Get_Struct(obj, data_t, data);
|
136
|
-
l = _lcb(data);
|
137
|
-
if (l == NIL_VALUE)
|
138
|
-
return Qnil;
|
139
|
-
if (data->ptr+l > data->endp)
|
140
|
-
l = data->endp - data->ptr;
|
141
|
-
ret = rb_str_new(data->ptr, l);
|
142
|
-
data->ptr += l;
|
143
|
-
return ret;
|
144
|
-
}
|
145
|
-
|
146
|
-
static VALUE read(VALUE obj, VALUE len)
|
147
|
-
{
|
148
|
-
data_t *data;
|
149
|
-
unsigned long long l = NUM2ULL(len);
|
150
|
-
VALUE ret;
|
151
|
-
|
152
|
-
Data_Get_Struct(obj, data_t, data);
|
153
|
-
if (data->ptr+l > data->endp)
|
154
|
-
l = data->endp - data->ptr;
|
155
|
-
ret = rb_str_new(data->ptr, l);
|
156
|
-
data->ptr += l;
|
157
|
-
return ret;
|
158
|
-
}
|
159
|
-
|
160
|
-
static VALUE string(VALUE obj)
|
161
|
-
{
|
162
|
-
data_t *data;
|
163
|
-
unsigned char *p;
|
164
|
-
VALUE ret;
|
165
|
-
|
166
|
-
Data_Get_Struct(obj, data_t, data);
|
167
|
-
p = data->ptr;
|
168
|
-
while (p < data->endp && *p++ != '\0')
|
169
|
-
;
|
170
|
-
ret = rb_str_new(data->ptr, (p - data->ptr)-1);
|
171
|
-
data->ptr = p;
|
172
|
-
return ret;
|
173
|
-
}
|
174
|
-
|
175
|
-
static VALUE utiny(VALUE obj)
|
176
|
-
{
|
177
|
-
data_t *data;
|
178
|
-
|
179
|
-
Data_Get_Struct(obj, data_t, data);
|
180
|
-
return UINT2NUM(*data->ptr++);
|
181
|
-
}
|
182
|
-
|
183
|
-
static VALUE _ushort(VALUE obj)
|
184
|
-
{
|
185
|
-
data_t *data;
|
186
|
-
unsigned short n;
|
187
|
-
|
188
|
-
Data_Get_Struct(obj, data_t, data);
|
189
|
-
n = *data->ptr++;
|
190
|
-
n |= *data->ptr++ * 0x100;
|
191
|
-
return UINT2NUM(n);
|
192
|
-
}
|
193
|
-
|
194
|
-
static VALUE _ulong(VALUE obj)
|
195
|
-
{
|
196
|
-
data_t *data;
|
197
|
-
unsigned long n;
|
198
|
-
|
199
|
-
Data_Get_Struct(obj, data_t, data);
|
200
|
-
n = *data->ptr++;
|
201
|
-
n |= *data->ptr++ * 0x100;
|
202
|
-
n |= *data->ptr++ * 0x10000;
|
203
|
-
n |= *data->ptr++ * 0x1000000;
|
204
|
-
return UINT2NUM(n);
|
205
|
-
}
|
206
|
-
|
207
|
-
static VALUE eofQ(VALUE obj)
|
208
|
-
{
|
209
|
-
data_t *data;
|
210
|
-
|
211
|
-
Data_Get_Struct(obj, data_t, data);
|
212
|
-
if (*data->ptr == 0xfe && data->endp - data->ptr == 5)
|
213
|
-
return Qtrue;
|
214
|
-
else
|
215
|
-
return Qfalse;
|
216
|
-
}
|
217
|
-
|
218
|
-
static VALUE to_s(VALUE obj)
|
219
|
-
{
|
220
|
-
data_t *data;
|
221
|
-
|
222
|
-
Data_Get_Struct(obj, data_t, data);
|
223
|
-
return rb_str_new(data->ptr, data->endp-data->ptr);
|
224
|
-
}
|
225
|
-
|
226
|
-
void Init_packet(void)
|
227
|
-
{
|
228
|
-
VALUE cMysql;
|
229
|
-
VALUE cPacket;
|
230
|
-
|
231
|
-
cMysql = rb_define_class("Mysql", rb_cObject);
|
232
|
-
cPacket = rb_define_class_under(cMysql, "Packet", rb_cObject);
|
233
|
-
rb_define_alloc_func(cPacket, allocate);
|
234
|
-
rb_define_singleton_method(cPacket, "lcb", s_lcb, 1);
|
235
|
-
rb_define_singleton_method(cPacket, "lcs", s_lcs, 1);
|
236
|
-
rb_define_method(cPacket, "initialize", initialize, 1);
|
237
|
-
rb_define_method(cPacket, "lcb", lcb, 0);
|
238
|
-
rb_define_method(cPacket, "lcs", lcs, 0);
|
239
|
-
rb_define_method(cPacket, "read", read, 1);
|
240
|
-
rb_define_method(cPacket, "string", string, 0);
|
241
|
-
rb_define_method(cPacket, "utiny", utiny, 0);
|
242
|
-
rb_define_method(cPacket, "ushort", _ushort, 0);
|
243
|
-
rb_define_method(cPacket, "ulong", _ulong, 0);
|
244
|
-
rb_define_method(cPacket, "eof?", eofQ, 0);
|
245
|
-
rb_define_method(cPacket, "to_s", to_s, 0);
|
246
|
-
}
|