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