1 From 95b210810301f0a5c87adc0d682bc8424dfb41d0 Mon Sep 17 00:00:00 2001 |
|
2 From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <[email protected]> |
|
3 Date: Fri, 26 Feb 2016 13:32:31 +0100 |
|
4 Subject: [PATCH] Fix transferring MYSQL_TYPE_LONG values on 64-bit big endian |
|
5 systems |
|
6 MIME-Version: 1.0 |
|
7 Content-Type: text/plain; charset=UTF-8 |
|
8 Content-Transfer-Encoding: 8bit |
|
9 |
|
10 t/40server_prepare.t test failed on s390x platform. Server-prepared |
|
11 values of types int, smallint, and tinyint are passed to application |
|
12 as 32-bit integer. The same buffer was interpreted as long integer |
|
13 by DBD::MySQL. This caused missaligned read/write and bogus |
|
14 interpretation of the values. |
|
15 |
|
16 https://rt.cpan.org/Public/Bug/Display.html?id=57266 |
|
17 https://bugzilla.redhat.com/show_bug.cgi?id=1311646 |
|
18 http://dev.mysql.com/doc/refman/5.7/en/mysql-stmt-fetch.html |
|
19 Signed-off-by: Petr Písař <[email protected]> |
|
20 --- |
|
21 dbdimp.c | 20 +++++++++++++------- |
|
22 dbdimp.h | 5 +++-- |
|
23 2 files changed, 16 insertions(+), 9 deletions(-) |
|
24 |
|
25 diff --git a/dbdimp.c b/dbdimp.c |
|
26 index d507588..9a1be20 100644 |
|
27 --- a/dbdimp.c |
|
28 +++ b/dbdimp.c |
|
29 @@ -18,6 +18,7 @@ |
|
30 #endif |
|
31 |
|
32 #include "dbdimp.h" |
|
33 +#include <inttypes.h> /* for PRId32 */ |
|
34 |
|
35 #if defined(WIN32) && defined(WORD) |
|
36 #undef WORD |
|
37 @@ -3753,8 +3754,8 @@ int dbd_describe(SV* sth, imp_sth_t* imp_sth) |
|
38 |
|
39 if (DBIc_TRACE_LEVEL(imp_xxh) >= 2) |
|
40 { |
|
41 - PerlIO_printf(DBIc_LOGPIO(imp_xxh),"\t\ti %d col_type %d fbh->length %d\n", |
|
42 - i, col_type, (int) fbh->length); |
|
43 + PerlIO_printf(DBIc_LOGPIO(imp_xxh),"\t\ti %d col_type %d fbh->length %lu\n", |
|
44 + i, col_type, fbh->length); |
|
45 PerlIO_printf(DBIc_LOGPIO(imp_xxh), |
|
46 "\t\tfields[i].length %lu fields[i].max_length %lu fields[i].type %d fields[i].charsetnr %d\n", |
|
47 (long unsigned int) fields[i].length, (long unsigned int) fields[i].max_length, fields[i].type, |
|
48 @@ -4015,8 +4016,8 @@ process: |
|
49 |
|
50 case MYSQL_TYPE_LONG: |
|
51 if (DBIc_TRACE_LEVEL(imp_xxh) >= 2) |
|
52 - PerlIO_printf(DBIc_LOGPIO(imp_xxh), "\t\tst_fetch int data %d, unsigned? %d\n", |
|
53 - (int) fbh->ldata, buffer->is_unsigned); |
|
54 + PerlIO_printf(DBIc_LOGPIO(imp_xxh), "\t\tst_fetch int data %"PRId32", unsigned? %d\n", |
|
55 + fbh->ldata, buffer->is_unsigned); |
|
56 if (buffer->is_unsigned) |
|
57 sv_setuv(sv, fbh->ldata); |
|
58 else |
|
59 @@ -4787,6 +4788,7 @@ int dbd_bind_ph(SV *sth, imp_sth_t *imp_sth, SV *param, SV *value, |
|
60 int buffer_is_null= 0; |
|
61 int buffer_length= slen; |
|
62 unsigned int buffer_type= 0; |
|
63 + IV tmp; |
|
64 #endif |
|
65 |
|
66 D_imp_dbh_from_sth; |
|
67 @@ -4874,12 +4876,16 @@ int dbd_bind_ph(SV *sth, imp_sth_t *imp_sth, SV *param, SV *value, |
|
68 if (!SvIOK(imp_sth->params[idx].value) && DBIc_TRACE_LEVEL(imp_xxh) >= 2) |
|
69 PerlIO_printf(DBIc_LOGPIO(imp_xxh), "\t\tTRY TO BIND AN INT NUMBER\n"); |
|
70 buffer_length = sizeof imp_sth->fbind[idx].numeric_val.lval; |
|
71 - imp_sth->fbind[idx].numeric_val.lval= SvIV(imp_sth->params[idx].value); |
|
72 + |
|
73 + tmp = SvIV(imp_sth->params[idx].value); |
|
74 + if (tmp > INT32_MAX) |
|
75 + croak("Could not bind %ld: Integer too large for MYSQL_TYPE_LONG", tmp); |
|
76 + imp_sth->fbind[idx].numeric_val.lval= tmp; |
|
77 buffer=(void*)&(imp_sth->fbind[idx].numeric_val.lval); |
|
78 if (DBIc_TRACE_LEVEL(imp_xxh) >= 2) |
|
79 PerlIO_printf(DBIc_LOGPIO(imp_xxh), |
|
80 - " SCALAR type %d ->%ld<- IS A INT NUMBER\n", |
|
81 - (int) sql_type, (long) (*buffer)); |
|
82 + " SCALAR type %d ->%"PRId32"<- IS A INT NUMBER\n", |
|
83 + (int) sql_type, *(int32_t *)buffer); |
|
84 break; |
|
85 |
|
86 case MYSQL_TYPE_DOUBLE: |
|
87 diff --git a/dbdimp.h b/dbdimp.h |
|
88 index 8723bcc..1ef5d72 100644 |
|
89 --- a/dbdimp.h |
|
90 +++ b/dbdimp.h |
|
91 @@ -22,6 +22,7 @@ |
|
92 #include <mysqld_error.h> /* Comes MySQL */ |
|
93 |
|
94 #include <errmsg.h> /* Comes with MySQL-devel */ |
|
95 +#include <stdint.h> /* For int32_t */ |
|
96 |
|
97 /* For now, we hardcode this, but in the future, |
|
98 * we can detect capabilities of the MySQL libraries |
|
99 @@ -212,7 +213,7 @@ typedef struct imp_sth_ph_st { |
|
100 typedef struct imp_sth_phb_st { |
|
101 union |
|
102 { |
|
103 - long lval; |
|
104 + int32_t lval; |
|
105 double dval; |
|
106 } numeric_val; |
|
107 unsigned long length; |
|
108 @@ -233,7 +234,7 @@ typedef struct imp_sth_fbh_st { |
|
109 char *data; |
|
110 int charsetnr; |
|
111 double ddata; |
|
112 - long ldata; |
|
113 + int32_t ldata; |
|
114 #if MYSQL_VERSION_ID < FIELD_CHARSETNR_VERSION |
|
115 unsigned int flags; |
|
116 #endif |
|
117 -- |
|
118 2.5.0 |
|
119 |
|