1 /* Copyright (c) 2014, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #include "binary_log_funcs.h"
24
25 #include "byteorder.h"
26 #include "wrapper_functions.h"
27
28 #include <string.h>
29 #include <climits>
30 #include <stdint.h>
31 #include <cstring>
32
33 /**
34 Max value for an unsigned integer of 'bits' bits.
35
36 The somewhat contorted expression is to avoid overflow.
37 */
uint_max(int bits)38 static unsigned int uint_max(int bits) {
39 BAPI_ASSERT(static_cast<unsigned int>(bits) <= sizeof(unsigned int) * CHAR_BIT);
40 return (((1U << (bits - 1)) - 1) << 1) | 1;
41 }
42
43
44 /**
45 Calculate binary size of packed numeric time representation.
46
47 @param dec Precision.
48 The same formula is used to find the binary size of the packed numeric time
49 in libbinlogevents/src/value.cpp calc_field_size().
50 If any modification is done here the same needs to be done in the
51 aforementioned method in libbinlogevents also.
52 */
my_time_binary_length(unsigned int dec)53 unsigned int my_time_binary_length(unsigned int dec)
54 {
55 BAPI_ASSERT(dec <= DATETIME_MAX_DECIMALS);
56 return 3 + (dec + 1) / 2;
57 }
58
59 /**
60 Calculate binary size of packed datetime representation.
61 @param dec Precision.
62
63 The same formula is used to find the binary size of the packed numeric time
64 in libbinlogevents/src/value.cpp calc_field_size().
65 If any modification is done here the same needs to be done in the
66 aforementioned method in libbinlogevents also.
67 */
my_datetime_binary_length(unsigned int dec)68 unsigned int my_datetime_binary_length(unsigned int dec)
69 {
70 BAPI_ASSERT(dec <= DATETIME_MAX_DECIMALS);
71 return 5 + (dec + 1) / 2;
72 }
73
74 /**
75 Calculate on-disk size of a timestamp value.
76
77 @param dec Precision.
78
79 The same formula is used to find the binary size of the packed numeric time
80 in libbinlogevents/src/value.cpp calc_field_size().
81 If any modification is done here the same needs to be done in the
82 aforementioned method in libbinlogevents also.
83 */
my_timestamp_binary_length(unsigned int dec)84 unsigned int my_timestamp_binary_length(unsigned int dec)
85 {
86 BAPI_ASSERT(dec <= DATETIME_MAX_DECIMALS);
87 return 4 + (dec + 1) / 2;
88 }
89
90 /**
91 Compute the maximum display length of a field.
92
93 @param sql_type Type of the field
94 @param metadata The metadata from the master for the field.
95 @return Maximum length of the field in bytes.
96 */
97 unsigned int
max_display_length_for_field(enum_field_types sql_type,unsigned int metadata)98 max_display_length_for_field(enum_field_types sql_type, unsigned int metadata)
99 {
100 BAPI_ASSERT(metadata >> 16 == 0);
101
102 switch (sql_type) {
103 case MYSQL_TYPE_NEWDECIMAL:
104 return metadata >> 8;
105
106 case MYSQL_TYPE_FLOAT:
107 return 12;
108
109 case MYSQL_TYPE_DOUBLE:
110 return 22;
111
112 case MYSQL_TYPE_SET:
113 case MYSQL_TYPE_ENUM:
114 return metadata & 0x00ff;
115
116 case MYSQL_TYPE_STRING:
117 {
118 unsigned char type= metadata >> 8;
119 if (type == MYSQL_TYPE_SET || type == MYSQL_TYPE_ENUM)
120 return metadata & 0xff;
121 else
122 return (((metadata >> 4) & 0x300) ^ 0x300) + (metadata & 0x00ff);
123 }
124
125 case MYSQL_TYPE_YEAR:
126 case MYSQL_TYPE_TINY:
127 return 4;
128
129 case MYSQL_TYPE_SHORT:
130 return 6;
131
132 case MYSQL_TYPE_INT24:
133 return 9;
134
135 case MYSQL_TYPE_LONG:
136 return 11;
137
138 case MYSQL_TYPE_LONGLONG:
139 return 20;
140
141 case MYSQL_TYPE_NULL:
142 return 0;
143
144 case MYSQL_TYPE_NEWDATE:
145 return 3;
146
147 case MYSQL_TYPE_DATE:
148 case MYSQL_TYPE_TIME:
149 case MYSQL_TYPE_TIME2:
150 return 3;
151
152 case MYSQL_TYPE_TIMESTAMP:
153 case MYSQL_TYPE_TIMESTAMP2:
154 return 4;
155
156 case MYSQL_TYPE_DATETIME:
157 case MYSQL_TYPE_DATETIME2:
158 return 8;
159
160 case MYSQL_TYPE_BIT:
161 /*
162 Decode the size of the bit field from the master.
163 */
164 BAPI_ASSERT((metadata & 0xff) <= 7);
165 return 8 * (metadata >> 8U) + (metadata & 0x00ff);
166
167 case MYSQL_TYPE_VAR_STRING:
168 case MYSQL_TYPE_VARCHAR:
169 return metadata;
170
171 /*
172 The actual length for these types does not really matter since
173 they are used to calc_pack_length, which ignores the given
174 length for these types.
175
176 Since we want this to be accurate for other uses, we return the
177 maximum size in bytes of these BLOBs.
178 */
179
180 case MYSQL_TYPE_TINY_BLOB:
181 return uint_max(1 * 8);
182
183 case MYSQL_TYPE_MEDIUM_BLOB:
184 return uint_max(3 * 8);
185
186 case MYSQL_TYPE_BLOB:
187 /*
188 For the blob type, Field::real_type() lies and say that all
189 blobs are of type MYSQL_TYPE_BLOB. In that case, we have to look
190 at the length instead to decide what the max display size is.
191 */
192 return uint_max(metadata * 8);
193
194 case MYSQL_TYPE_LONG_BLOB:
195 case MYSQL_TYPE_GEOMETRY:
196 case MYSQL_TYPE_JSON:
197 return uint_max(4 * 8);
198
199 default:
200 return UINT_MAX;
201 }
202 }
203
decimal_binary_size(int precision,int scale)204 int decimal_binary_size(int precision, int scale)
205 {
206 static const int dig2bytes[10]= {0, 1, 1, 2, 2, 3, 3, 4, 4, 4};
207 int intg= precision-scale,
208 intg0= intg/9, frac0= scale/9,
209 intg0x= intg-intg0*9, frac0x= scale-frac0*9;
210
211 BAPI_ASSERT(scale >= 0 && precision > 0 && scale <= precision);
212 return intg0 * sizeof(uint32_t) + dig2bytes[intg0x]+
213 frac0 * sizeof(uint32_t) + dig2bytes[frac0x];
214 }
215
216
217 /**
218 This helper function calculates the size in bytes of a particular field in a
219 row type event as defined by the field_ptr and metadata_ptr arguments.
220 @param col Field type code
221 @param master_data The field data
222 @param metadata The field metadata
223
224 @return The size in bytes of a particular field
225 */
calc_field_size(unsigned char col,const unsigned char * master_data,unsigned int metadata)226 uint32_t calc_field_size(unsigned char col, const unsigned char *master_data,
227 unsigned int metadata)
228 {
229 uint32_t length= 0;
230
231 switch ((col)) {
232 case MYSQL_TYPE_NEWDECIMAL:
233 length= decimal_binary_size(metadata >> 8,
234 metadata & 0xff);
235 break;
236 case MYSQL_TYPE_DECIMAL:
237 case MYSQL_TYPE_FLOAT:
238 case MYSQL_TYPE_DOUBLE:
239 length= metadata;
240 break;
241 /*
242 The cases for SET and ENUM are include for completeness, however
243 both are mapped to type MYSQL_TYPE_STRING and their real types
244 are encoded in the field metadata.
245 */
246 case MYSQL_TYPE_SET:
247 case MYSQL_TYPE_ENUM:
248 case MYSQL_TYPE_STRING:
249 {
250 unsigned char type= metadata >> 8U;
251 if ((type == MYSQL_TYPE_SET) || (type == MYSQL_TYPE_ENUM))
252 length= metadata & 0x00ff;
253 else
254 {
255 /*
256 We are reading the actual size from the master_data record
257 because this field has the actual lengh stored in the first
258 one or two bytes.
259 */
260 length= max_display_length_for_field(MYSQL_TYPE_STRING, metadata) > 255 ? 2 : 1;
261
262 if (length == 1)
263 length+= *master_data;
264 else
265 {
266 uint32_t temp= 0;
267 memcpy(&temp, master_data, 2);
268 length= length + le32toh(temp);
269 }
270 }
271 break;
272 }
273 case MYSQL_TYPE_YEAR:
274 case MYSQL_TYPE_TINY:
275 length= 1;
276 break;
277 case MYSQL_TYPE_SHORT:
278 length= 2;
279 break;
280 case MYSQL_TYPE_INT24:
281 length= 3;
282 break;
283 case MYSQL_TYPE_LONG:
284 length= 4;
285 break;
286 case MYSQL_TYPE_LONGLONG:
287 length= 8;
288 break;
289 case MYSQL_TYPE_NULL:
290 length= 0;
291 break;
292 case MYSQL_TYPE_NEWDATE:
293 length= 3;
294 break;
295 case MYSQL_TYPE_DATE:
296 case MYSQL_TYPE_TIME:
297 length= 3;
298 break;
299 case MYSQL_TYPE_TIME2:
300 /*
301 The original methods in the server to calculate the binary size of the
302 packed numeric time representation is defined in my_time.c, the signature
303 being unsigned int my_time_binary_length(uint)
304
305 The length below needs to be updated if the above method is updated in
306 the server
307 */
308 length= my_time_binary_length(metadata);
309 break;
310 case MYSQL_TYPE_TIMESTAMP:
311 length= 4;
312 break;
313 case MYSQL_TYPE_TIMESTAMP2:
314 /*
315 The original methods in the server to calculate the binary size of the
316 packed numeric time representation is defined in time.c, the signature
317 being unsigned int my_timestamp_binary_length(uint)
318
319 The length below needs to be updated if the above method is updated in
320 the server
321 */
322 length= my_timestamp_binary_length(metadata);
323 break;
324 case MYSQL_TYPE_DATETIME:
325 length= 8;
326 break;
327 case MYSQL_TYPE_DATETIME2:
328 /*
329 The original methods in the server to calculate the binary size of the
330 packed numeric time representation is defined in time.c, the signature
331 being unsigned int my_datetime_binary_length(uint)
332
333 The length below needs to be updated if the above method is updated in
334 the server
335 */
336 length= my_datetime_binary_length(metadata);
337 break;
338 case MYSQL_TYPE_BIT:
339 {
340 /*
341 Decode the size of the bit field from the master.
342 from_len is the length in bytes from the master
343 from_bit_len is the number of extra bits stored in the master record
344 If from_bit_len is not 0, add 1 to the length to account for accurate
345 number of bytes needed.
346 */
347 unsigned int from_len= (metadata >> 8U) & 0x00ff;
348 unsigned int from_bit_len= metadata & 0x00ff;
349 BAPI_ASSERT(from_bit_len <= 7);
350 length= from_len + ((from_bit_len > 0) ? 1 : 0);
351 break;
352 }
353 case MYSQL_TYPE_VARCHAR:
354 {
355 length= metadata > 255 ? 2 : 1;
356 if (length == 1)
357 length+= (uint32_t) *master_data;
358 else
359 {
360 uint32_t temp= 0;
361 memcpy(&temp, master_data, 2);
362 length= length + le32toh(temp);
363 }
364 break;
365 }
366 case MYSQL_TYPE_TINY_BLOB:
367 case MYSQL_TYPE_MEDIUM_BLOB:
368 case MYSQL_TYPE_LONG_BLOB:
369 case MYSQL_TYPE_BLOB:
370 case MYSQL_TYPE_GEOMETRY:
371 case MYSQL_TYPE_JSON:
372 {
373 /*
374 Compute the length of the data. We cannot use get_length() here
375 since it is dependent on the specific table (and also checks the
376 packlength using the internal 'table' pointer) and replication
377 is using a fixed format for storing data in the binlog.
378 */
379 switch (metadata) {
380 case 1:
381 length= *master_data;
382 break;
383 case 2:
384 memcpy(&length, master_data, 2);
385 length= le32toh(length);
386 break;
387 case 3:
388 memcpy(&length, master_data, 3);
389 length= le32toh(length);
390 break;
391 case 4:
392 memcpy(&length, master_data, 4);
393 length= le32toh(length);
394 break;
395 default:
396 BAPI_ASSERT(0); // Should not come here
397 break;
398 }
399
400 length+= metadata;
401 break;
402 }
403 default:
404 length= UINT_MAX;
405 }
406 return length;
407 }
408