1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2017, 2018, MariaDB Corporation. |
5 | |
6 | This program is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free Software |
8 | Foundation; version 2 of the License. |
9 | |
10 | This program is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License along with |
15 | this program; if not, write to the Free Software Foundation, Inc., |
16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
17 | |
18 | *****************************************************************************/ |
19 | |
20 | /**************************************************//** |
21 | @file include/data0type.ic |
22 | Data types |
23 | |
24 | Created 1/16/1996 Heikki Tuuri |
25 | *******************************************************/ |
26 | |
27 | #include "mach0data.h" |
28 | #include "ha_prototypes.h" |
29 | |
30 | /*********************************************************************//** |
31 | Gets the MySQL charset-collation code for MySQL string types. |
32 | @return MySQL charset-collation code */ |
33 | UNIV_INLINE |
34 | ulint |
35 | dtype_get_charset_coll( |
36 | /*===================*/ |
37 | ulint prtype) /*!< in: precise data type */ |
38 | { |
39 | return((prtype >> 16) & CHAR_COLL_MASK); |
40 | } |
41 | |
42 | /*********************************************************************//** |
43 | Determines if a MySQL string type is a subset of UTF-8. This function |
44 | may return false negatives, in case further character-set collation |
45 | codes are introduced in MySQL later. |
46 | @return whether a subset of UTF-8 */ |
47 | UNIV_INLINE |
48 | bool |
49 | dtype_is_utf8( |
50 | /*==========*/ |
51 | ulint prtype) /*!< in: precise data type */ |
52 | { |
53 | /* These codes have been copied from strings/ctype-extra.c |
54 | and strings/ctype-utf8.c. */ |
55 | switch (dtype_get_charset_coll(prtype)) { |
56 | case 11: /* ascii_general_ci */ |
57 | case 65: /* ascii_bin */ |
58 | case 33: /* utf8_general_ci */ |
59 | case 83: /* utf8_bin */ |
60 | case 254: /* utf8_general_cs */ |
61 | return true; |
62 | } |
63 | |
64 | return false; |
65 | } |
66 | |
67 | /*********************************************************************//** |
68 | Gets the MySQL type code from a dtype. |
69 | @return MySQL type code; this is NOT an InnoDB type code! */ |
70 | UNIV_INLINE |
71 | ulint |
72 | dtype_get_mysql_type( |
73 | /*=================*/ |
74 | const dtype_t* type) /*!< in: type struct */ |
75 | { |
76 | return(type->prtype & 0xFFUL); |
77 | } |
78 | |
79 | /*********************************************************************//** |
80 | Compute the mbminlen and mbmaxlen members of a data type structure. */ |
81 | UNIV_INLINE |
82 | void |
83 | dtype_get_mblen( |
84 | /*============*/ |
85 | ulint mtype, /*!< in: main type */ |
86 | ulint prtype, /*!< in: precise type (and collation) */ |
87 | ulint* mbminlen, /*!< out: minimum length of a |
88 | multi-byte character */ |
89 | ulint* mbmaxlen) /*!< out: maximum length of a |
90 | multi-byte character */ |
91 | { |
92 | if (dtype_is_string_type(mtype)) { |
93 | innobase_get_cset_width(dtype_get_charset_coll(prtype), |
94 | mbminlen, mbmaxlen); |
95 | ut_ad(*mbminlen <= *mbmaxlen); |
96 | ut_ad(*mbminlen < DATA_MBMAX); |
97 | ut_ad(*mbmaxlen < DATA_MBMAX); |
98 | } else { |
99 | *mbminlen = *mbmaxlen = 0; |
100 | } |
101 | } |
102 | |
103 | /*********************************************************************//** |
104 | Compute the mbminlen and mbmaxlen members of a data type structure. */ |
105 | UNIV_INLINE |
106 | void |
107 | dtype_set_mblen( |
108 | /*============*/ |
109 | dtype_t* type) /*!< in/out: type */ |
110 | { |
111 | ulint mbminlen; |
112 | ulint mbmaxlen; |
113 | |
114 | dtype_get_mblen(type->mtype, type->prtype, &mbminlen, &mbmaxlen); |
115 | type->mbminlen = mbminlen; |
116 | type->mbmaxlen = mbmaxlen; |
117 | |
118 | ut_ad(dtype_validate(type)); |
119 | } |
120 | |
121 | /*********************************************************************//** |
122 | Sets a data type structure. */ |
123 | UNIV_INLINE |
124 | void |
125 | dtype_set( |
126 | /*======*/ |
127 | dtype_t* type, /*!< in: type struct to init */ |
128 | ulint mtype, /*!< in: main data type */ |
129 | ulint prtype, /*!< in: precise type */ |
130 | ulint len) /*!< in: precision of type */ |
131 | { |
132 | ut_ad(type); |
133 | ut_ad(mtype <= DATA_MTYPE_MAX); |
134 | |
135 | type->mtype = unsigned(mtype); |
136 | type->prtype = unsigned(prtype); |
137 | type->len = unsigned(len); |
138 | |
139 | dtype_set_mblen(type); |
140 | } |
141 | |
142 | /*********************************************************************//** |
143 | Copies a data type structure. */ |
144 | UNIV_INLINE |
145 | void |
146 | dtype_copy( |
147 | /*=======*/ |
148 | dtype_t* type1, /*!< in: type struct to copy to */ |
149 | const dtype_t* type2) /*!< in: type struct to copy from */ |
150 | { |
151 | *type1 = *type2; |
152 | |
153 | ut_ad(dtype_validate(type1)); |
154 | } |
155 | |
156 | /*********************************************************************//** |
157 | Gets the SQL main data type. |
158 | @return SQL main data type */ |
159 | UNIV_INLINE |
160 | ulint |
161 | dtype_get_mtype( |
162 | /*============*/ |
163 | const dtype_t* type) /*!< in: data type */ |
164 | { |
165 | ut_ad(type); |
166 | |
167 | return(type->mtype); |
168 | } |
169 | |
170 | /*********************************************************************//** |
171 | Gets the precise data type. |
172 | @return precise data type */ |
173 | UNIV_INLINE |
174 | ulint |
175 | dtype_get_prtype( |
176 | /*=============*/ |
177 | const dtype_t* type) /*!< in: data type */ |
178 | { |
179 | ut_ad(type); |
180 | |
181 | return(type->prtype); |
182 | } |
183 | |
184 | /*********************************************************************//** |
185 | Gets the type length. |
186 | @return fixed length of the type, in bytes, or 0 if variable-length */ |
187 | UNIV_INLINE |
188 | ulint |
189 | dtype_get_len( |
190 | /*==========*/ |
191 | const dtype_t* type) /*!< in: data type */ |
192 | { |
193 | ut_ad(type); |
194 | |
195 | return(type->len); |
196 | } |
197 | |
198 | /*********************************************************************//** |
199 | Gets the minimum length of a character, in bytes. |
200 | @return minimum length of a char, in bytes, or 0 if this is not a |
201 | character type */ |
202 | UNIV_INLINE |
203 | ulint |
204 | dtype_get_mbminlen( |
205 | /*===============*/ |
206 | const dtype_t* type) /*!< in: type */ |
207 | { |
208 | return type->mbminlen; |
209 | } |
210 | /*********************************************************************//** |
211 | Gets the maximum length of a character, in bytes. |
212 | @return maximum length of a char, in bytes, or 0 if this is not a |
213 | character type */ |
214 | UNIV_INLINE |
215 | ulint |
216 | dtype_get_mbmaxlen( |
217 | /*===============*/ |
218 | const dtype_t* type) /*!< in: type */ |
219 | { |
220 | return type->mbmaxlen; |
221 | } |
222 | |
223 | /**********************************************************************//** |
224 | Stores for a type the information which determines its alphabetical ordering |
225 | and the storage size of an SQL NULL value. This is the >= 4.1.x storage |
226 | format. */ |
227 | UNIV_INLINE |
228 | void |
229 | dtype_new_store_for_order_and_null_size( |
230 | /*====================================*/ |
231 | byte* buf, /*!< in: buffer for |
232 | DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE |
233 | bytes where we store the info */ |
234 | const dtype_t* type, /*!< in: type struct */ |
235 | ulint prefix_len)/*!< in: prefix length to |
236 | replace type->len, or 0 */ |
237 | { |
238 | compile_time_assert(6 == DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); |
239 | |
240 | ulint len; |
241 | |
242 | ut_ad(type); |
243 | ut_ad(type->mtype >= DATA_VARCHAR); |
244 | ut_ad(type->mtype <= DATA_MTYPE_MAX); |
245 | |
246 | buf[0] = (byte)(type->mtype & 0xFFUL); |
247 | |
248 | if (type->prtype & DATA_BINARY_TYPE) { |
249 | buf[0] |= 128; |
250 | } |
251 | |
252 | /* In versions < 4.1.2 we had: if (type->prtype & DATA_NONLATIN1) { |
253 | buf[0] |= 64; |
254 | } |
255 | */ |
256 | |
257 | buf[1] = (byte)(type->prtype & 0xFFUL); |
258 | |
259 | len = prefix_len ? prefix_len : type->len; |
260 | |
261 | mach_write_to_2(buf + 2, len & 0xFFFFUL); |
262 | |
263 | ut_ad(dtype_get_charset_coll(type->prtype) <= MAX_CHAR_COLL_NUM); |
264 | mach_write_to_2(buf + 4, dtype_get_charset_coll(type->prtype)); |
265 | |
266 | if (type->prtype & DATA_NOT_NULL) { |
267 | buf[4] |= 128; |
268 | } |
269 | } |
270 | |
271 | /**********************************************************************//** |
272 | Reads to a type the stored information which determines its alphabetical |
273 | ordering and the storage size of an SQL NULL value. This is the < 4.1.x |
274 | storage format. */ |
275 | UNIV_INLINE |
276 | void |
277 | dtype_read_for_order_and_null_size( |
278 | /*===============================*/ |
279 | dtype_t* type, /*!< in: type struct */ |
280 | const byte* buf) /*!< in: buffer for stored type order info */ |
281 | { |
282 | compile_time_assert(4 == DATA_ORDER_NULL_TYPE_BUF_SIZE); |
283 | type->mtype = buf[0] & 63; |
284 | type->prtype = buf[1]; |
285 | |
286 | if (buf[0] & 128) { |
287 | type->prtype |= DATA_BINARY_TYPE; |
288 | } |
289 | |
290 | type->len = mach_read_from_2(buf + 2); |
291 | |
292 | type->prtype = dtype_form_prtype(type->prtype, |
293 | data_mysql_default_charset_coll); |
294 | dtype_set_mblen(type); |
295 | } |
296 | |
297 | /**********************************************************************//** |
298 | Reads to a type the stored information which determines its alphabetical |
299 | ordering and the storage size of an SQL NULL value. This is the >= 4.1.x |
300 | storage format. */ |
301 | UNIV_INLINE |
302 | void |
303 | dtype_new_read_for_order_and_null_size( |
304 | /*===================================*/ |
305 | dtype_t* type, /*!< in: type struct */ |
306 | const byte* buf) /*!< in: buffer for stored type order info */ |
307 | { |
308 | compile_time_assert(6 == DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); |
309 | |
310 | type->mtype = buf[0] & 63; |
311 | type->prtype = buf[1]; |
312 | |
313 | if (buf[0] & 128) { |
314 | type->prtype |= DATA_BINARY_TYPE; |
315 | } |
316 | |
317 | if (buf[4] & 128) { |
318 | type->prtype |= DATA_NOT_NULL; |
319 | } |
320 | |
321 | type->len = mach_read_from_2(buf + 2); |
322 | |
323 | ulint charset_coll = mach_read_from_2(buf + 4) & CHAR_COLL_MASK; |
324 | |
325 | if (dtype_is_string_type(type->mtype)) { |
326 | ut_a(charset_coll <= MAX_CHAR_COLL_NUM); |
327 | |
328 | if (charset_coll == 0) { |
329 | /* This insert buffer record was inserted with MySQL |
330 | version < 4.1.2, and the charset-collation code was not |
331 | explicitly stored to dtype->prtype at that time. It |
332 | must be the default charset-collation of this MySQL |
333 | installation. */ |
334 | |
335 | charset_coll = data_mysql_default_charset_coll; |
336 | } |
337 | |
338 | type->prtype = dtype_form_prtype(type->prtype, charset_coll); |
339 | } |
340 | dtype_set_mblen(type); |
341 | } |
342 | |
343 | /*********************************************************************//** |
344 | Returns the type's SQL name (e.g. BIGINT UNSIGNED) from mtype,prtype,len |
345 | @return the SQL type name */ |
346 | UNIV_INLINE |
347 | char* |
348 | dtype_sql_name( |
349 | /*===========*/ |
350 | unsigned mtype, /*!< in: mtype */ |
351 | unsigned prtype, /*!< in: prtype */ |
352 | unsigned len, /*!< in: len */ |
353 | char* name, /*!< out: SQL name */ |
354 | unsigned name_sz)/*!< in: size of the name buffer */ |
355 | { |
356 | |
357 | #define APPEND_UNSIGNED() \ |
358 | do { \ |
359 | if (prtype & DATA_UNSIGNED) { \ |
360 | snprintf(name + strlen(name), \ |
361 | name_sz - strlen(name), \ |
362 | " UNSIGNED"); \ |
363 | } \ |
364 | } while (0) |
365 | |
366 | snprintf(name, name_sz, "UNKNOWN" ); |
367 | |
368 | switch (mtype) { |
369 | case DATA_INT: |
370 | switch (len) { |
371 | case 1: |
372 | snprintf(name, name_sz, "TINYINT" ); |
373 | break; |
374 | case 2: |
375 | snprintf(name, name_sz, "SMALLINT" ); |
376 | break; |
377 | case 3: |
378 | snprintf(name, name_sz, "MEDIUMINT" ); |
379 | break; |
380 | case 4: |
381 | snprintf(name, name_sz, "INT" ); |
382 | break; |
383 | case 8: |
384 | snprintf(name, name_sz, "BIGINT" ); |
385 | break; |
386 | } |
387 | APPEND_UNSIGNED(); |
388 | break; |
389 | case DATA_FLOAT: |
390 | snprintf(name, name_sz, "FLOAT" ); |
391 | APPEND_UNSIGNED(); |
392 | break; |
393 | case DATA_DOUBLE: |
394 | snprintf(name, name_sz, "DOUBLE" ); |
395 | APPEND_UNSIGNED(); |
396 | break; |
397 | case DATA_FIXBINARY: |
398 | snprintf(name, name_sz, "BINARY(%u)" , len); |
399 | break; |
400 | case DATA_CHAR: |
401 | case DATA_MYSQL: |
402 | snprintf(name, name_sz, "CHAR(%u)" , len); |
403 | break; |
404 | case DATA_VARCHAR: |
405 | case DATA_VARMYSQL: |
406 | snprintf(name, name_sz, "VARCHAR(%u)" , len); |
407 | break; |
408 | case DATA_BINARY: |
409 | snprintf(name, name_sz, "VARBINARY(%u)" , len); |
410 | break; |
411 | case DATA_GEOMETRY: |
412 | snprintf(name, name_sz, "GEOMETRY" ); |
413 | break; |
414 | case DATA_BLOB: |
415 | switch (len) { |
416 | case 9: |
417 | snprintf(name, name_sz, "TINYBLOB" ); |
418 | break; |
419 | case 10: |
420 | snprintf(name, name_sz, "BLOB" ); |
421 | break; |
422 | case 11: |
423 | snprintf(name, name_sz, "MEDIUMBLOB" ); |
424 | break; |
425 | case 12: |
426 | snprintf(name, name_sz, "LONGBLOB" ); |
427 | break; |
428 | } |
429 | } |
430 | |
431 | if (prtype & DATA_NOT_NULL) { |
432 | snprintf(name + strlen(name), |
433 | name_sz - strlen(name), |
434 | " NOT NULL" ); |
435 | } |
436 | |
437 | return(name); |
438 | } |
439 | |
440 | /***********************************************************************//** |
441 | Returns the size of a fixed size data type, 0 if not a fixed size type. |
442 | @return fixed size, or 0 */ |
443 | UNIV_INLINE |
444 | ulint |
445 | dtype_get_fixed_size_low( |
446 | /*=====================*/ |
447 | ulint mtype, /*!< in: main type */ |
448 | ulint prtype, /*!< in: precise type */ |
449 | ulint len, /*!< in: length */ |
450 | ulint mbminlen, /*!< in: minimum length of a |
451 | multibyte character, in bytes */ |
452 | ulint mbmaxlen, /*!< in: maximum length of a |
453 | multibyte character, in bytes */ |
454 | ulint comp) /*!< in: nonzero=ROW_FORMAT=COMPACT */ |
455 | { |
456 | switch (mtype) { |
457 | case DATA_SYS: |
458 | #ifdef UNIV_DEBUG |
459 | switch (prtype & DATA_MYSQL_TYPE_MASK) { |
460 | case DATA_ROW_ID: |
461 | ut_ad(len == DATA_ROW_ID_LEN); |
462 | break; |
463 | case DATA_TRX_ID: |
464 | ut_ad(len == DATA_TRX_ID_LEN); |
465 | break; |
466 | case DATA_ROLL_PTR: |
467 | ut_ad(len == DATA_ROLL_PTR_LEN); |
468 | break; |
469 | default: |
470 | ut_ad(0); |
471 | return(0); |
472 | } |
473 | #endif /* UNIV_DEBUG */ |
474 | /* fall through */ |
475 | case DATA_CHAR: |
476 | case DATA_FIXBINARY: |
477 | case DATA_INT: |
478 | case DATA_FLOAT: |
479 | case DATA_DOUBLE: |
480 | return(len); |
481 | case DATA_MYSQL: |
482 | if (prtype & DATA_BINARY_TYPE) { |
483 | return(len); |
484 | } else if (!comp) { |
485 | return(len); |
486 | } else { |
487 | #ifdef UNIV_DEBUG |
488 | ulint i_mbminlen, i_mbmaxlen; |
489 | |
490 | innobase_get_cset_width( |
491 | dtype_get_charset_coll(prtype), |
492 | &i_mbminlen, &i_mbmaxlen); |
493 | |
494 | ut_ad(i_mbminlen == mbminlen); |
495 | ut_ad(i_mbmaxlen == mbmaxlen); |
496 | #endif /* UNIV_DEBUG */ |
497 | if (mbminlen == mbmaxlen) { |
498 | return(len); |
499 | } |
500 | } |
501 | /* Treat as variable-length. */ |
502 | /* fall through */ |
503 | case DATA_VARCHAR: |
504 | case DATA_BINARY: |
505 | case DATA_DECIMAL: |
506 | case DATA_VARMYSQL: |
507 | case DATA_GEOMETRY: |
508 | case DATA_BLOB: |
509 | return(0); |
510 | default: |
511 | ut_error; |
512 | } |
513 | |
514 | return(0); |
515 | } |
516 | |
517 | /***********************************************************************//** |
518 | Returns the minimum size of a data type. |
519 | @return minimum size */ |
520 | UNIV_INLINE |
521 | ulint |
522 | dtype_get_min_size_low( |
523 | /*===================*/ |
524 | ulint mtype, /*!< in: main type */ |
525 | ulint prtype, /*!< in: precise type */ |
526 | ulint len, /*!< in: length */ |
527 | ulint mbminlen, /*!< in: minimum length of a character */ |
528 | ulint mbmaxlen) /*!< in: maximum length of a character */ |
529 | { |
530 | switch (mtype) { |
531 | case DATA_SYS: |
532 | #ifdef UNIV_DEBUG |
533 | switch (prtype & DATA_MYSQL_TYPE_MASK) { |
534 | case DATA_ROW_ID: |
535 | ut_ad(len == DATA_ROW_ID_LEN); |
536 | break; |
537 | case DATA_TRX_ID: |
538 | ut_ad(len == DATA_TRX_ID_LEN); |
539 | break; |
540 | case DATA_ROLL_PTR: |
541 | ut_ad(len == DATA_ROLL_PTR_LEN); |
542 | break; |
543 | default: |
544 | ut_ad(0); |
545 | return(0); |
546 | } |
547 | #endif /* UNIV_DEBUG */ |
548 | /* fall through */ |
549 | case DATA_CHAR: |
550 | case DATA_FIXBINARY: |
551 | case DATA_INT: |
552 | case DATA_FLOAT: |
553 | case DATA_DOUBLE: |
554 | return(len); |
555 | case DATA_MYSQL: |
556 | if (prtype & DATA_BINARY_TYPE) { |
557 | return(len); |
558 | } else { |
559 | if (mbminlen == mbmaxlen) { |
560 | return(len); |
561 | } |
562 | |
563 | /* this is a variable-length character set */ |
564 | ut_a(mbminlen > 0); |
565 | ut_a(mbmaxlen > mbminlen); |
566 | ut_a(len % mbmaxlen == 0); |
567 | return(len * mbminlen / mbmaxlen); |
568 | } |
569 | case DATA_VARCHAR: |
570 | case DATA_BINARY: |
571 | case DATA_DECIMAL: |
572 | case DATA_VARMYSQL: |
573 | case DATA_GEOMETRY: |
574 | case DATA_BLOB: |
575 | return(0); |
576 | default: |
577 | ut_error; |
578 | } |
579 | |
580 | return(0); |
581 | } |
582 | |
583 | /***********************************************************************//** |
584 | Returns the maximum size of a data type. Note: types in system tables may be |
585 | incomplete and return incorrect information. |
586 | @return maximum size */ |
587 | UNIV_INLINE |
588 | ulint |
589 | dtype_get_max_size_low( |
590 | /*===================*/ |
591 | ulint mtype, /*!< in: main type */ |
592 | ulint len) /*!< in: length */ |
593 | { |
594 | switch (mtype) { |
595 | case DATA_SYS: |
596 | case DATA_CHAR: |
597 | case DATA_FIXBINARY: |
598 | case DATA_INT: |
599 | case DATA_FLOAT: |
600 | case DATA_DOUBLE: |
601 | case DATA_MYSQL: |
602 | case DATA_VARCHAR: |
603 | case DATA_BINARY: |
604 | case DATA_DECIMAL: |
605 | case DATA_VARMYSQL: |
606 | return(len); |
607 | case DATA_GEOMETRY: |
608 | case DATA_BLOB: |
609 | break; |
610 | default: |
611 | ut_error; |
612 | } |
613 | |
614 | return(ULINT_MAX); |
615 | } |
616 | |
617 | /***********************************************************************//** |
618 | Returns the ROW_FORMAT=REDUNDANT stored SQL NULL size of a type. |
619 | For fixed length types it is the fixed length of the type, otherwise 0. |
620 | @return SQL null storage size in ROW_FORMAT=REDUNDANT */ |
621 | UNIV_INLINE |
622 | ulint |
623 | dtype_get_sql_null_size( |
624 | /*====================*/ |
625 | const dtype_t* type, /*!< in: type */ |
626 | ulint comp) /*!< in: nonzero=ROW_FORMAT=COMPACT */ |
627 | { |
628 | return(dtype_get_fixed_size_low(type->mtype, type->prtype, type->len, |
629 | type->mbminlen, type->mbmaxlen, comp)); |
630 | } |
631 | |