Merge lp:~wiml-omni/libdrizzle/date-time into lp:libdrizzle
- date-time
- Merge into libdrizzle-redux
Status: | Merged |
---|---|
Approved by: | Andrew Hutchings |
Approved revision: | 115 |
Merged at revision: | 111 |
Proposed branch: | lp:~wiml-omni/libdrizzle/date-time |
Merge into: | lp:libdrizzle |
Diff against target: |
279 lines (+95/-66) 5 files modified
libdrizzle-5.1/constants.h (+2/-0) libdrizzle/pack.cc (+50/-44) libdrizzle/pack.h (+2/-2) libdrizzle/statement.cc (+2/-2) libdrizzle/statement_param.cc (+39/-18) |
To merge this branch: | bzr merge lp:~wiml-omni/libdrizzle/date-time |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Wim Lewis (community) | Needs Fixing | ||
Andrew Hutchings | Approve | ||
Review via email: mp+156381@code.launchpad.net |
Commit message
This fixes a handful of bugs related to dates and times in prepared statements, mostly found by the datetypes unit test.
Description of the change
This fixes a handful of bugs related to dates and times in prepared statements, mostly found by the datetypes unit test.
Andrew Hutchings (linuxjedi) wrote : | # |
So, there are two problems that flagged up when trying to merge this. I don't quite see how they are related to this branch yet, but:
Ubuntu 12.04:
../tests/
Row 1
Column 2: 1 "1" 1.000000
Column 3: 1 "1" 1.000000
Column 4: 1 "1" 1.000000
Column 5: 1 "1" 1.000000
Column 6: 1 "1" 1.000000
Column 7: 1 "1.000000" 1.000000
Column 8: 1 "1.000000" 1.000000
Row 2
Column 2: 127 "127" 127.000000
Column 3: 32687 "32687" 32687.000000
Column 4: 8388351 "8388351" 8388351.000000
Column 5: 2147352575 "2147352575" 2147352575.000000
Column 6: 9222246136947920895 "92222461369479
Column 7: 443664 "443664.000000" 443664.000000
FAIL: tests/unit/numbers
Fedora 17:
/usr/bin/ld: tests/unit/
/usr/bin/ld: note: 'truncf@
/lib64/libm.so.6: could not read symbols: Invalid operation
collect2: error: ld returned 1 exit status
make[1]: *** [tests/
I'll look into these later this evening.
Wim Lewis (wiml-omni) wrote : | # |
On 2 Apr 2013, at 11:36 AM, Andrew Hutchings wrote:
> So, there are two problems that flagged up when trying to merge this. I don't quite see how they are related to this branch yet, but:
>
> Ubuntu 12.04:
>
> ../tests/
Oho. I've fixed that, but haven't cleaned it up to commit yet, and had forgotten that numbers.c would hit it. (The problem, IIRC, is that drizzle_
> Fedora 17:
> /usr/bin/ld: tests/unit/
> /usr/bin/ld: note: 'truncf@
> /lib64/libm.so.6: could not read symbols: Invalid operation
> collect2: error: ld returned 1 exit status
> make[1]: *** [tests/
I guess the unit tests need to be linked against -lm if they're using trunc(). I missed that one since libc and libm are the same library on OSX.
Wim Lewis (wiml-omni) wrote : | # |
I'm working on some cleaning up my fixes for the first of those problems and I'll commit them to this branch when I have a chance.
Andrew Hutchings (linuxjedi) wrote : | # |
awesome, thanks.
When that is ready I'll fix the Fedora builder problem.
Preview Diff
1 | === modified file 'libdrizzle-5.1/constants.h' | |||
2 | --- libdrizzle-5.1/constants.h 2013-03-05 03:27:07 +0000 | |||
3 | +++ libdrizzle-5.1/constants.h 2013-04-01 17:45:26 +0000 | |||
4 | @@ -621,6 +621,8 @@ | |||
5 | 621 | ((uint64_t)drizzle_get_byte4(((uint8_t *)__buffer)+4) << 32)) | 621 | ((uint64_t)drizzle_get_byte4(((uint8_t *)__buffer)+4) << 32)) |
6 | 622 | 622 | ||
7 | 623 | /* Protocol packing macros. */ | 623 | /* Protocol packing macros. */ |
8 | 624 | #define drizzle_set_byte1(__buffer, __int) do { \ | ||
9 | 625 | (__buffer)[0] = (uint8_t)(__int); } while (0) | ||
10 | 624 | #define drizzle_set_byte2(__buffer, __int) do { \ | 626 | #define drizzle_set_byte2(__buffer, __int) do { \ |
11 | 625 | (__buffer)[0]= (uint8_t)((__int) & 0xFF); \ | 627 | (__buffer)[0]= (uint8_t)((__int) & 0xFF); \ |
12 | 626 | (__buffer)[1]= (uint8_t)(((__int) >> 8) & 0xFF); } while (0) | 628 | (__buffer)[1]= (uint8_t)(((__int) >> 8) & 0xFF); } while (0) |
13 | 627 | 629 | ||
14 | === modified file 'libdrizzle/pack.cc' | |||
15 | --- libdrizzle/pack.cc 2013-03-12 16:33:14 +0000 | |||
16 | +++ libdrizzle/pack.cc 2013-04-01 17:45:26 +0000 | |||
17 | @@ -193,71 +193,78 @@ | |||
18 | 193 | { | 193 | { |
19 | 194 | uint8_t length= 0; | 194 | uint8_t length= 0; |
20 | 195 | 195 | ||
21 | 196 | /* If nothing is set then we are sending a 0 length time */ | ||
22 | 197 | if (time->day || time->hour || time->minute || time->second) | ||
23 | 198 | { | ||
24 | 199 | ptr[0]= (time->negative) ? 1 : 0; | ||
25 | 200 | drizzle_set_byte4(&ptr[1], time->day); | ||
26 | 201 | ptr[5]= (uint8_t) time->hour; | ||
27 | 202 | ptr[6]= time->minute; | ||
28 | 203 | ptr[7]= time->second; | ||
29 | 204 | length= 8; | ||
30 | 205 | } | ||
31 | 206 | /* NOTE: MySQL has a bug here and doesn't follow this part of the protocol | 196 | /* NOTE: MySQL has a bug here and doesn't follow this part of the protocol |
32 | 207 | * when packing, we will for now, no idea if it works | 197 | * when packing, we will for now, no idea if it works |
33 | 208 | * */ | 198 | * */ |
34 | 209 | if (time->microsecond) | 199 | if (time->microsecond) |
35 | 210 | { | 200 | { |
37 | 211 | drizzle_set_byte4(&ptr[8], time->microsecond); | 201 | drizzle_set_byte4(ptr+9, time->microsecond); |
38 | 212 | length= 12; | 202 | length= 12; |
39 | 213 | } | 203 | } |
41 | 214 | return ptr+length; | 204 | |
42 | 205 | if (length || time->day || time->hour || time->minute || time->second) | ||
43 | 206 | { | ||
44 | 207 | ptr[1]= (time->negative) ? 1 : 0; | ||
45 | 208 | drizzle_set_byte4(ptr+2, time->day); | ||
46 | 209 | drizzle_set_byte1(ptr+6, time->hour); | ||
47 | 210 | drizzle_set_byte1(ptr+7, time->minute); | ||
48 | 211 | drizzle_set_byte1(ptr+8, time->second); | ||
49 | 212 | /* If no microseconds, then we are packing 8 bytes */ | ||
50 | 213 | if (!length) | ||
51 | 214 | length= 8; | ||
52 | 215 | } | ||
53 | 216 | |||
54 | 217 | /* If nothing is set then we are sending a 0 length time */ | ||
55 | 218 | |||
56 | 219 | drizzle_set_byte1(ptr, length); | ||
57 | 220 | return ptr + 1 + length; | ||
58 | 215 | } | 221 | } |
59 | 216 | 222 | ||
60 | 217 | unsigned char *drizzle_pack_datetime(drizzle_datetime_st *datetime, unsigned char *ptr) | 223 | unsigned char *drizzle_pack_datetime(drizzle_datetime_st *datetime, unsigned char *ptr) |
61 | 218 | { | 224 | { |
62 | 219 | uint8_t length= 0; | 225 | uint8_t length= 0; |
63 | 220 | 226 | ||
64 | 227 | if (datetime->microsecond) | ||
65 | 228 | { | ||
66 | 229 | drizzle_set_byte4(ptr+8, datetime->microsecond); | ||
67 | 230 | length = 11; | ||
68 | 231 | } | ||
69 | 232 | |||
70 | 233 | if (length || datetime->hour || datetime->minute || datetime->second) | ||
71 | 234 | { | ||
72 | 235 | drizzle_set_byte1(ptr+5, datetime->hour); | ||
73 | 236 | drizzle_set_byte1(ptr+6, datetime->minute); | ||
74 | 237 | drizzle_set_byte1(ptr+7, datetime->second); | ||
75 | 238 | /* If only date+time is provided then we are packing 7 bytes */ | ||
76 | 239 | if (!length) | ||
77 | 240 | length = 7; | ||
78 | 241 | } | ||
79 | 242 | |||
80 | 243 | if (length || datetime->year || datetime->month || datetime->day) | ||
81 | 244 | { | ||
82 | 245 | drizzle_set_byte2(ptr+1, datetime->year); | ||
83 | 246 | drizzle_set_byte1(ptr+3, datetime->month); | ||
84 | 247 | drizzle_set_byte1(ptr+4, datetime->day); | ||
85 | 248 | /* If only date is provided then we are packing 4 bytes */ | ||
86 | 249 | if (!length) | ||
87 | 250 | length = 4; | ||
88 | 251 | } | ||
89 | 252 | |||
90 | 221 | /* If nothing is set then we are sending a 0 length datetime */ | 253 | /* If nothing is set then we are sending a 0 length datetime */ |
91 | 222 | 254 | ||
116 | 223 | /* If only date is provided then we are packing 4 bytes */ | 255 | drizzle_set_byte1(ptr, length); |
117 | 224 | if (datetime->year || datetime->month || datetime->day) | 256 | return ptr + 1 + length; |
94 | 225 | { | ||
95 | 226 | drizzle_set_byte2(ptr, datetime->year); | ||
96 | 227 | ptr[2]= datetime->month; | ||
97 | 228 | ptr[3]= datetime->day; | ||
98 | 229 | length= 4; | ||
99 | 230 | } | ||
100 | 231 | |||
101 | 232 | if (datetime->hour || datetime->minute || datetime->second) | ||
102 | 233 | { | ||
103 | 234 | ptr[4]= (uint8_t) datetime->hour; | ||
104 | 235 | ptr[5]= datetime->minute; | ||
105 | 236 | ptr[6]= datetime->second; | ||
106 | 237 | length= 7; | ||
107 | 238 | } | ||
108 | 239 | |||
109 | 240 | if (datetime->microsecond) | ||
110 | 241 | { | ||
111 | 242 | drizzle_set_byte4(&ptr[7], datetime->microsecond); | ||
112 | 243 | length= 11; | ||
113 | 244 | } | ||
114 | 245 | |||
115 | 246 | return ptr + length; | ||
118 | 247 | } | 257 | } |
119 | 248 | 258 | ||
121 | 249 | void drizzle_unpack_time(drizzle_field_t field, size_t length, unsigned char *data) | 259 | void drizzle_unpack_time(drizzle_field_t field, size_t length, drizzle_datetime_st *datetime) |
122 | 250 | { | 260 | { |
125 | 251 | drizzle_datetime_st *datetime= (drizzle_datetime_st*) data; | 261 | memset(datetime, 0, sizeof(*datetime)); |
124 | 252 | memset(datetime, 0, length); | ||
126 | 253 | 262 | ||
127 | 254 | if (length) | 263 | if (length) |
128 | 255 | { | 264 | { |
129 | 256 | datetime->negative= field[0]; | 265 | datetime->negative= field[0]; |
130 | 257 | datetime->day= drizzle_get_byte4(&field[1]); | 266 | datetime->day= drizzle_get_byte4(&field[1]); |
131 | 258 | datetime->hour= field[5]; | 267 | datetime->hour= field[5]; |
132 | 259 | datetime->hour= datetime->day * 24; | ||
133 | 260 | datetime->day= 0; | ||
134 | 261 | datetime->minute= field[6]; | 268 | datetime->minute= field[6]; |
135 | 262 | datetime->second= field[7]; | 269 | datetime->second= field[7]; |
136 | 263 | if (length > 8) | 270 | if (length > 8) |
137 | @@ -267,10 +274,9 @@ | |||
138 | 267 | } | 274 | } |
139 | 268 | } | 275 | } |
140 | 269 | 276 | ||
142 | 270 | void drizzle_unpack_datetime(drizzle_field_t field, size_t length, unsigned char *data) | 277 | void drizzle_unpack_datetime(drizzle_field_t field, size_t length, drizzle_datetime_st *datetime) |
143 | 271 | { | 278 | { |
146 | 272 | drizzle_datetime_st *datetime= (drizzle_datetime_st*) data; | 279 | memset(datetime, 0, sizeof(*datetime)); |
145 | 273 | memset(datetime, 0, length); | ||
147 | 274 | 280 | ||
148 | 275 | if (length) | 281 | if (length) |
149 | 276 | { | 282 | { |
150 | 277 | 283 | ||
151 | === modified file 'libdrizzle/pack.h' | |||
152 | --- libdrizzle/pack.h 2013-03-06 18:05:42 +0000 | |||
153 | +++ libdrizzle/pack.h 2013-04-01 17:45:26 +0000 | |||
154 | @@ -79,9 +79,9 @@ | |||
155 | 79 | 79 | ||
156 | 80 | unsigned char *drizzle_pack_datetime(drizzle_datetime_st *datetime, unsigned char *ptr); | 80 | unsigned char *drizzle_pack_datetime(drizzle_datetime_st *datetime, unsigned char *ptr); |
157 | 81 | 81 | ||
159 | 82 | void drizzle_unpack_time(drizzle_field_t field, size_t length, unsigned char *data); | 82 | void drizzle_unpack_time(drizzle_field_t field, size_t length, drizzle_datetime_st *datetime); |
160 | 83 | 83 | ||
162 | 84 | void drizzle_unpack_datetime(drizzle_field_t field, size_t length, unsigned char *data); | 84 | void drizzle_unpack_datetime(drizzle_field_t field, size_t length, drizzle_datetime_st *datetime); |
163 | 85 | 85 | ||
164 | 86 | /** | 86 | /** |
165 | 87 | * Unpack length-encoded string. | 87 | * Unpack length-encoded string. |
166 | 88 | 88 | ||
167 | === modified file 'libdrizzle/statement.cc' | |||
168 | --- libdrizzle/statement.cc 2013-03-21 10:44:02 +0000 | |||
169 | +++ libdrizzle/statement.cc 2013-04-01 17:45:26 +0000 | |||
170 | @@ -471,13 +471,13 @@ | |||
171 | 471 | break; | 471 | break; |
172 | 472 | case DRIZZLE_COLUMN_TYPE_TIME: | 472 | case DRIZZLE_COLUMN_TYPE_TIME: |
173 | 473 | param->data= param->data_buffer; | 473 | param->data= param->data_buffer; |
175 | 474 | drizzle_unpack_time(row[column_counter], param->length, (unsigned char*)param->data); | 474 | drizzle_unpack_time(row[column_counter], param->length, (drizzle_datetime_st *)param->data); |
176 | 475 | break; | 475 | break; |
177 | 476 | case DRIZZLE_COLUMN_TYPE_DATE: | 476 | case DRIZZLE_COLUMN_TYPE_DATE: |
178 | 477 | case DRIZZLE_COLUMN_TYPE_DATETIME: | 477 | case DRIZZLE_COLUMN_TYPE_DATETIME: |
179 | 478 | case DRIZZLE_COLUMN_TYPE_TIMESTAMP: | 478 | case DRIZZLE_COLUMN_TYPE_TIMESTAMP: |
180 | 479 | param->data= param->data_buffer; | 479 | param->data= param->data_buffer; |
182 | 480 | drizzle_unpack_datetime(row[column_counter], param->length, (unsigned char*)param->data); | 480 | drizzle_unpack_datetime(row[column_counter], param->length, (drizzle_datetime_st *)param->data); |
183 | 481 | break; | 481 | break; |
184 | 482 | case DRIZZLE_COLUMN_TYPE_TINY_BLOB: | 482 | case DRIZZLE_COLUMN_TYPE_TINY_BLOB: |
185 | 483 | case DRIZZLE_COLUMN_TYPE_MEDIUM_BLOB: | 483 | case DRIZZLE_COLUMN_TYPE_MEDIUM_BLOB: |
186 | 484 | 484 | ||
187 | === modified file 'libdrizzle/statement_param.cc' | |||
188 | --- libdrizzle/statement_param.cc 2013-03-11 17:33:00 +0000 | |||
189 | +++ libdrizzle/statement_param.cc 2013-04-01 17:45:26 +0000 | |||
190 | @@ -129,6 +129,8 @@ | |||
191 | 129 | drizzle_datetime_st *time; | 129 | drizzle_datetime_st *time; |
192 | 130 | time= (drizzle_datetime_st*) stmt->query_params[param_num].data_buffer; | 130 | time= (drizzle_datetime_st*) stmt->query_params[param_num].data_buffer; |
193 | 131 | 131 | ||
194 | 132 | bzero(time, sizeof(*time)); | ||
195 | 133 | |||
196 | 132 | time->negative= is_negative; | 134 | time->negative= is_negative; |
197 | 133 | time->day= days; | 135 | time->day= days; |
198 | 134 | time->hour= hours; | 136 | time->hour= hours; |
199 | @@ -145,6 +147,8 @@ | |||
200 | 145 | drizzle_datetime_st *timestamp; | 147 | drizzle_datetime_st *timestamp; |
201 | 146 | timestamp= (drizzle_datetime_st*) stmt->query_params[param_num].data_buffer; | 148 | timestamp= (drizzle_datetime_st*) stmt->query_params[param_num].data_buffer; |
202 | 147 | 149 | ||
203 | 150 | bzero(timestamp, sizeof(*timestamp)); | ||
204 | 151 | |||
205 | 148 | timestamp->negative= false; | 152 | timestamp->negative= false; |
206 | 149 | timestamp->year= year; | 153 | timestamp->year= year; |
207 | 150 | timestamp->day= day; | 154 | timestamp->day= day; |
208 | @@ -156,7 +160,7 @@ | |||
209 | 156 | timestamp->microsecond= microseconds; | 160 | timestamp->microsecond= microseconds; |
210 | 157 | 161 | ||
211 | 158 | /* Length not important because we will figure that out when packing */ | 162 | /* Length not important because we will figure that out when packing */ |
213 | 159 | return drizzle_stmt_set_param(stmt, param_num, DRIZZLE_COLUMN_TYPE_TIME, timestamp, 0, false); | 163 | return drizzle_stmt_set_param(stmt, param_num, DRIZZLE_COLUMN_TYPE_TIMESTAMP, timestamp, 0, false); |
214 | 160 | } | 164 | } |
215 | 161 | 165 | ||
216 | 162 | bool drizzle_stmt_get_is_null_from_name(drizzle_stmt_st *stmt, const char *column_name, drizzle_return_t *ret_ptr) | 166 | bool drizzle_stmt_get_is_null_from_name(drizzle_stmt_st *stmt, const char *column_name, drizzle_return_t *ret_ptr) |
217 | @@ -619,29 +623,46 @@ | |||
218 | 619 | { | 623 | { |
219 | 620 | /* Max time is -HHH:MM:SS.ssssss + NUL = 17 */ | 624 | /* Max time is -HHH:MM:SS.ssssss + NUL = 17 */ |
220 | 621 | char* buffer= param->data_buffer + 50; | 625 | char* buffer= param->data_buffer + 50; |
229 | 622 | if (time->microsecond == 0) | 626 | int buffersize = 17; |
230 | 623 | { | 627 | int used = 0; |
231 | 624 | snprintf(buffer, 17, "%s%"PRIu16":%"PRIu8":%"PRIu8, (time->negative) ? "-" : "", time->hour, time->minute, time->second); | 628 | |
232 | 625 | } | 629 | /* Values are transferred with days separated from hours, but presented with days folded into hours. */ |
233 | 626 | else | 630 | used = snprintf(buffer, buffersize-used, "%s%02u:%02"PRIu8":%02"PRIu8, (time->negative) ? "-" : "", time->hour + 24 * time->day, time->minute, time->second); |
234 | 627 | { | 631 | |
235 | 628 | snprintf(buffer, 17, "%s%"PRIu16":%"PRIu8":%"PRIu8".%"PRIu32, (time->negative) ? "-" : "", time->hour, time->minute, time->second, time->microsecond); | 632 | /* TODO: the existence (and length) of the decimals should be decided based on the number of fields sent by the server or possibly the column's "decimals" value, not by whether the microseconds are 0 */ |
236 | 629 | } | 633 | if (time->microsecond) |
237 | 634 | used += snprintf(buffer+used, buffersize-used, ".%06" PRIu32, time->microsecond); | ||
238 | 635 | |||
239 | 636 | assert(used < buffersize); | ||
240 | 637 | |||
241 | 630 | return buffer; | 638 | return buffer; |
242 | 631 | } | 639 | } |
243 | 632 | 640 | ||
244 | 633 | char *timestamp_to_string(drizzle_bind_st *param, drizzle_datetime_st *timestamp) | 641 | char *timestamp_to_string(drizzle_bind_st *param, drizzle_datetime_st *timestamp) |
245 | 634 | { | 642 | { |
247 | 635 | /* Max timestamp is YYYY-MM-DD HH:MM:SS.ssssss + NUL = 26 */ | 643 | /* Max timestamp is YYYY-MM-DD HH:MM:SS.ssssss + NUL = 27 */ |
248 | 636 | char* buffer= param->data_buffer + 50; | 644 | char* buffer= param->data_buffer + 50; |
257 | 637 | if (timestamp->microsecond == 0) | 645 | int buffersize = 27; |
258 | 638 | { | 646 | int used = 0; |
259 | 639 | snprintf(buffer, 26, "%"PRIu16"-%"PRIu8"-%"PRIu32" %"PRIu16":%"PRIu8":%"PRIu8, timestamp->year, timestamp->month, timestamp->day, timestamp->hour, timestamp->minute, timestamp->second); | 647 | |
260 | 640 | } | 648 | used += snprintf(buffer, buffersize-used, "%"PRIu16"-%02"PRIu8"-%02"PRIu32, |
261 | 641 | else | 649 | timestamp->year, timestamp->month, timestamp->day); |
262 | 642 | { | 650 | assert(used < buffersize); |
263 | 643 | snprintf(buffer, 26, "%"PRIu16"-%"PRIu8"-%"PRIu32" %"PRIu16":%"PRIu8":%"PRIu8".%"PRIu32, timestamp->year, timestamp->month, timestamp->day, timestamp->hour, timestamp->minute, timestamp->second, timestamp->microsecond); | 651 | |
264 | 644 | } | 652 | if (param->type == DRIZZLE_COLUMN_TYPE_DATE) |
265 | 653 | return buffer; | ||
266 | 654 | |||
267 | 655 | used += snprintf(buffer+used, buffersize-used, " %02"PRIu16":%02"PRIu8":%02"PRIu8, | ||
268 | 656 | timestamp->hour, timestamp->minute, timestamp->second); | ||
269 | 657 | |||
270 | 658 | /* TODO: the existence (and length) of the decimals should be decided based on the number of fields sent by the server or possibly the column's "decimals" value, not by whether the microseconds are 0 */ | ||
271 | 659 | if (timestamp->microsecond) | ||
272 | 660 | { | ||
273 | 661 | used += snprintf(buffer+used, buffersize-used, ".%06"PRIu32, timestamp->microsecond); | ||
274 | 662 | } | ||
275 | 663 | |||
276 | 664 | assert(used < buffersize); | ||
277 | 665 | |||
278 | 645 | return buffer; | 666 | return buffer; |
279 | 646 | } | 667 | } |
280 | 647 | 668 |
Many great fixes :)