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