Cleanup#2 for MDEV-34319: DECLARE TYPE .. TABLE OF .. INDEX BY - packed_col_length

Additional small cleanup (forgoten in the previous commit):
- Item_splocal_assoc_array_element_field::fix_fields()
  Fixing the error message for:
    SELECT marks('a').name; -- marks is a TABLE OF VARCHAR(10)
  From: ERROR 42S22: Unknown column '1' in 'SELECT'
  To:   ERROR 42S22: Unknown column 'name' in 'marks'

Fixing wrong results of packed_col_length(): it returned a wrong result for:
- CHAR(N)
- BINARY(N)
- MEDIUMBLOB
- LONGBLOB

Note, this method was not used. Now it's used by the assoc array data type.

Details:

- Cleanup: adding "const" qualifier to:

  * Field::pack()
  * Field::max_packed_col_length()
  * Field::packed_col_length()

- Removing the "max_length" argument from Field::pack().
  The caller passed either UINT_MAX or Field::max_data_length() to it.
  So it was never used to limit the destination size and only
  made the code more complicated and confusing.

- Removing arguments from packed_col_length().
  Now it calculates the value for the Field, using its "ptr",
  and assuming the entire value will be packed,
  without limiting the destination size.

- Fixing Field_blob::packed_col_length(). It worked fine only for
  TINYBLOB and BLOB, and did not work for MEDIUMBLOB and LONGBLOB.

- Overriding Field_char::packed_col_length().
  Using the inherited method was wrong - it implemented
  variable length data behavior.

- Overriding Field_string::max_data_length(). It was also incorrect.
  Implementing fixed size behavior.
  Moving the old implementation of Field_longstring::max_data_length()
  to Field_varstring::max_data_length().

- Fixing class StringPack:
  * Removing the "length" argument from StringPack::packed_col_length().
    It now assumes that the packed length for the entire data buffer
    is needed, without limiting the destination size.

  * Fixing StringPack::packed_col_length() to implement fixed dat size behavior.
    It erroneously implemented VARCHAR style behavor
    (assumed that the length was stored in the leading 1 or 2 bytes).

  * Adding a helper method length_bytes(). Reusing it in packed_col_length()
    and max_packed_col_length().

  * Moving a part the method pack() into a new method trimmed_length().
    Reusing it in pack() and packed_col_length().

  * Rewriting the code in trimmed_length() in a more straightforward way.
    It was hard to understand what it was doing.
    Adding a comment.

- Adding a test sp-assoc-array-pack-debug.test covering packed_col_length()
  and pack() for various data types.
This commit is contained in:
Alexander Barkov 2025-05-17 09:33:16 +04:00 committed by Sergei Golubchik
parent 3acda17aa9
commit f9b330e0b4
14 changed files with 798 additions and 143 deletions

View File

@ -0,0 +1 @@
--max-allowed-packet=33554432

View File

@ -0,0 +1,486 @@
set sql_mode=oracle;
SET NAMES utf8mb4;
SELECT @@SESSION.max_allowed_packet;
@@SESSION.max_allowed_packet
33554432
#
# MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
#
SET debug_dbug='d,assoc_array_pack';
CREATE TABLE dtypes
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
dtype VARCHAR(128),
val LONGTEXT
);
INSERT INTO dtypes (dtype, val) VALUES
('bit(1)', 'bit:1'),
('bit(8)', 'bit:255'),
('bit(16)', 'bit:65535'),
('bit(64)', 'bit:18446744073709551615'),
('tinyint', '123'),
('tinyint unsigned', '123'),
('smallint', '123'),
('smallint unsigned', '123'),
('int', '123'),
('int unsigned', '123'),
('mediumint', '123'),
('mediumint unsigned', '123'),
('bigint', '123'),
('bigint unsigned', '123'),
('decimal(10,2)', '123.45'),
('float', '123e5'),
('double', '123e5'),
('mariadb_schema.date', '2001-01-01'),
('time', '800:59:59'),
('time(6)', '800:59:59.123456'),
('datetime', '2001-01-01 23:59:59'),
('datetime(6)', '2001-01-01 23:59:59.123456'),
('timestamp', '2001-01-01 23:59:59'),
('timestamp(6)', '2001-01-01 23:59:59.123456'),
('binary(10)', 'test'),
('binary(20)', 'test'),
('binary(10)', 'test test'),
('binary(20)', 'test test'),
('char(10) character set latin1', 'test'),
('char(10) character set utf8mb4', 'test'),
('varchar(10) character set latin1', 'test'),
('varchar(10) character set utf8mb4', 'test'),
('tinytext character set latin1', 'test'),
('tinytext character set utf8mb4', 'test'),
('text character set latin1', 'test'),
('text character set utf8mb4', 'test'),
('mediumtext character set latin1', 'test'),
('mediumtext character set utf8mb4', 'test'),
('longtext character set latin1', 'test'),
('longtext character set utf8mb4', 'test'),
('char(255) character set latin1', REPEAT('test ',50)),
('char(255) character set utf8mb4', REPEAT('test ',50)),
('varchar(255) character set latin1', REPEAT('test ',50)),
('varchar(255) character set utf8mb4', REPEAT('test ',50)),
('tinytext character set latin1', REPEAT('test ',50)),
('tinytext character set utf8mb4', REPEAT('test ',50)),
('text character set latin1', REPEAT('test ',50)),
('text character set utf8mb4', REPEAT('test ',50)),
('mediumtext character set latin1', REPEAT('test ',50)),
('mediumtext character set utf8mb4', REPEAT('test ',50)),
('longtext character set latin1', REPEAT('test ',50)),
('longtext character set utf8mb4', REPEAT('test ',50)),
('text character set latin1', REPEAT('test ',(256*256-1)/5)),
('text character set utf8mb4', REPEAT('test ',(256*256-1)/5)),
('mediumtext character set latin1', REPEAT('test ',(256*256-1)/5)),
('mediumtext character set utf8mb4', REPEAT('test ',(256*256-1)/5)),
('longtext character set latin1', REPEAT('test ',(256*256-1)/5)),
('longtext character set utf8mb4', REPEAT('test ',(256*256-1)/5)),
('mediumtext character set utf8mb4', REPEAT('test ',(256*256*256-1)/5)),
('longtext character set utf8mb4', REPEAT('test ',(256*256*256-1)/5 + 1));
CREATE PROCEDURE test_type(rec dtypes%ROWTYPE) AS
TYPE assoc_t IS TABLE OF t1.val%TYPE INDEX BY INTEGER;
assoc assoc_t;
val LONGTEXT;
BEGIN
IF rec.val LIKE 'bit:%'
THEN
assoc(0) := CAST(REPLACE(rec.val,'bit:','') AS UNSIGNED);
SHOW WARNINGS;
SELECT assoc(0)+0 AS `assoc(0)`;
ELSIF rec.dtype LIKE 'binary%'
THEN
assoc(0):= rec.val;
SHOW WARNINGS;
SELECT HEX(assoc(0)), LENGTH(assoc(0));
ELSE
assoc(0) := rec.val;
SHOW WARNINGS;
IF LENGTH(rec.val) > 64
THEN
SELECT LEFT(assoc(0),30) ||
'..' || LENGTH(assoc(0)) || '.. ' ||
RIGHT(assoc(0),30) AS `assoc(0)`;
ELSE
SELECT assoc(0);
END IF;
END IF;
END;
$$
CREATE PROCEDURE test_types AS
BEGIN
FOR rec IN (SELECT * FROM dtypes)
LOOP
EXECUTE IMMEDIATE REPLACE('CREATE TABLE t1 (val DTYPE)','DTYPE',rec.dtype);
SELECT
COLUMN_TYPE AS ``, COALESCE(CHARACTER_SET_NAME,'') AS ``
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_SCHEMA='test' AND TABLE_NAME='t1' AND COLUMN_NAME='val';
INSERT INTO t1 VALUES (rec.val);
CALL test_type(rec);
DROP TABLE t1;
END LOOP;
END;
$$
CALL test_types;
bit(1)
Level Code Message
Note 1003 pack=1 plen=1 ; mdlen=1 flen=1 ; `assoc` bit(1)
assoc(0)
1
bit(8)
Level Code Message
Note 1003 pack=1 plen=1 ; mdlen=1 flen=8 ; `assoc` bit(8)
assoc(0)
255
bit(16)
Level Code Message
Note 1003 pack=2 plen=2 ; mdlen=2 flen=16 ; `assoc` bit(16)
assoc(0)
65535
bit(64)
Level Code Message
Note 1003 pack=8 plen=8 ; mdlen=8 flen=64 ; `assoc` bit(64)
assoc(0)
18446744073709551615
tinyint(4)
Level Code Message
Note 1003 pack=1 plen=1 ; mdlen=1 flen=4 ; `assoc` tinyint(4)
assoc(0)
123
tinyint(3) unsigned
Level Code Message
Note 1003 pack=1 plen=1 ; mdlen=1 flen=3 ; `assoc` tinyint(3) unsigned
assoc(0)
123
smallint(6)
Level Code Message
Note 1003 pack=2 plen=2 ; mdlen=2 flen=6 ; `assoc` smallint(6)
assoc(0)
123
smallint(5) unsigned
Level Code Message
Note 1003 pack=2 plen=2 ; mdlen=2 flen=5 ; `assoc` smallint(5) unsigned
assoc(0)
123
int(11)
Level Code Message
Note 1003 pack=4 plen=4 ; mdlen=4 flen=11 ; `assoc` int(11)
assoc(0)
123
int(10) unsigned
Level Code Message
Note 1003 pack=4 plen=4 ; mdlen=4 flen=10 ; `assoc` int(10) unsigned
assoc(0)
123
mediumint(9)
Level Code Message
Note 1003 pack=3 plen=3 ; mdlen=3 flen=9 ; `assoc` mediumint(9)
assoc(0)
123
mediumint(8) unsigned
Level Code Message
Note 1003 pack=3 plen=3 ; mdlen=3 flen=8 ; `assoc` mediumint(8) unsigned
assoc(0)
123
bigint(20)
Level Code Message
Note 1003 pack=8 plen=8 ; mdlen=8 flen=20 ; `assoc` bigint(20)
assoc(0)
123
bigint(20) unsigned
Level Code Message
Note 1003 pack=8 plen=8 ; mdlen=8 flen=20 ; `assoc` bigint(20) unsigned
assoc(0)
123
decimal(10,2)
Level Code Message
Note 1003 pack=5 plen=5 ; mdlen=5 flen=12 ; `assoc` decimal(10,2)
assoc(0)
123.45
float
Level Code Message
Note 1003 pack=4 plen=4 ; mdlen=4 flen=12 ; `assoc` float
assoc(0)
12300000
double
Level Code Message
Note 1003 pack=8 plen=8 ; mdlen=8 flen=22 ; `assoc` double
assoc(0)
12300000
date
Level Code Message
Note 1003 pack=3 plen=3 ; mdlen=3 flen=10 ; `assoc` date
assoc(0)
2001-01-01
time
Level Code Message
Note 1003 pack=3 plen=3 ; mdlen=3 flen=10 ; `assoc` time
assoc(0)
800:59:59
time(6)
Level Code Message
Note 1003 pack=6 plen=6 ; mdlen=6 flen=17 ; `assoc` time(6)
assoc(0)
800:59:59.123456
datetime
Level Code Message
Note 1003 pack=5 plen=5 ; mdlen=5 flen=19 ; `assoc` datetime
assoc(0)
2001-01-01 23:59:59
datetime(6)
Level Code Message
Note 1003 pack=8 plen=8 ; mdlen=8 flen=26 ; `assoc` datetime(6)
assoc(0)
2001-01-01 23:59:59.123456
timestamp
Level Code Message
Note 1003 pack=4 plen=4 ; mdlen=4 flen=19 ; `assoc` timestamp
assoc(0)
2001-01-01 23:59:59
timestamp(6)
Level Code Message
Note 1003 pack=7 plen=7 ; mdlen=7 flen=26 ; `assoc` timestamp(6)
assoc(0)
2001-01-01 23:59:59.123456
binary(10)
Level Code Message
Note 1003 pack=5 plen=5 ; mdlen=10 flen=10 ; `assoc` binary(10)
HEX(assoc(0)) LENGTH(assoc(0))
74657374000000000000 10
binary(20)
Level Code Message
Note 1003 pack=5 plen=5 ; mdlen=20 flen=20 ; `assoc` binary(20)
HEX(assoc(0)) LENGTH(assoc(0))
7465737400000000000000000000000000000000 20
binary(10)
Level Code Message
Note 1003 pack=10 plen=10 ; mdlen=10 flen=10 ; `assoc` binary(10)
HEX(assoc(0)) LENGTH(assoc(0))
74657374207465737400 10
binary(20)
Level Code Message
Note 1003 pack=10 plen=10 ; mdlen=20 flen=20 ; `assoc` binary(20)
HEX(assoc(0)) LENGTH(assoc(0))
7465737420746573740000000000000000000000 20
char(10) latin1
Level Code Message
Note 1003 pack=5 plen=5 ; mdlen=10 flen=10 ; `assoc` char(10)
assoc(0)
test
char(10) utf8mb4
Level Code Message
Note 1003 pack=5 plen=5 ; mdlen=40 flen=40 ; `assoc` char(10)
assoc(0)
test
varchar(10) latin1
Level Code Message
Note 1003 pack=5 plen=5 ; mdlen=11 flen=10 ; `assoc` varchar(10)
assoc(0)
test
varchar(10) utf8mb4
Level Code Message
Note 1003 pack=5 plen=5 ; mdlen=41 flen=40 ; `assoc` varchar(10)
assoc(0)
test
tinytext latin1
Level Code Message
Note 1003 pack=5 plen=5 ; mdlen=255 flen=255 ; `assoc` tinytext
assoc(0)
test
tinytext utf8mb4
Level Code Message
Note 1003 pack=5 plen=5 ; mdlen=255 flen=255 ; `assoc` tinytext
assoc(0)
test
text latin1
Level Code Message
Note 1003 pack=6 plen=6 ; mdlen=65535 flen=65535 ; `assoc` text
assoc(0)
test
text utf8mb4
Level Code Message
Note 1003 pack=6 plen=6 ; mdlen=65535 flen=65535 ; `assoc` text
assoc(0)
test
mediumtext latin1
Level Code Message
Note 1003 pack=7 plen=7 ; mdlen=16777215 flen=16777215 ; `assoc` mediumtext
assoc(0)
test
mediumtext utf8mb4
Level Code Message
Note 1003 pack=7 plen=7 ; mdlen=16777215 flen=16777215 ; `assoc` mediumtext
assoc(0)
test
longtext latin1
Level Code Message
Note 1003 pack=8 plen=8 ; mdlen=4294967295 flen=4294967295 ; `assoc` longtext
assoc(0)
test
longtext utf8mb4
Level Code Message
Note 1003 pack=8 plen=8 ; mdlen=4294967295 flen=4294967295 ; `assoc` longtext
assoc(0)
test
char(255) latin1
Level Code Message
Note 1003 pack=250 plen=250 ; mdlen=255 flen=255 ; `assoc` char(255)
assoc(0)
test test test test test test ..249.. test test test test test test
char(255) utf8mb4
Level Code Message
Note 1003 pack=251 plen=251 ; mdlen=1020 flen=1020 ; `assoc` char(255)
assoc(0)
test test test test test test ..249.. test test test test test test
varchar(255) latin1
Level Code Message
Note 1003 pack=251 plen=251 ; mdlen=256 flen=255 ; `assoc` varchar(255)
assoc(0)
test test test test test test ..250.. test test test test test test
varchar(255) utf8mb4
Level Code Message
Note 1003 pack=252 plen=252 ; mdlen=1022 flen=1020 ; `assoc` varchar(255)
assoc(0)
test test test test test test ..250.. test test test test test test
tinytext latin1
Level Code Message
Note 1003 pack=251 plen=251 ; mdlen=255 flen=255 ; `assoc` tinytext
assoc(0)
test test test test test test ..250.. test test test test test test
tinytext utf8mb4
Level Code Message
Note 1003 pack=251 plen=251 ; mdlen=255 flen=255 ; `assoc` tinytext
assoc(0)
test test test test test test ..250.. test test test test test test
text latin1
Level Code Message
Note 1003 pack=252 plen=252 ; mdlen=65535 flen=65535 ; `assoc` text
assoc(0)
test test test test test test ..250.. test test test test test test
text utf8mb4
Level Code Message
Note 1003 pack=252 plen=252 ; mdlen=65535 flen=65535 ; `assoc` text
assoc(0)
test test test test test test ..250.. test test test test test test
mediumtext latin1
Level Code Message
Note 1003 pack=253 plen=253 ; mdlen=16777215 flen=16777215 ; `assoc` mediumtext
assoc(0)
test test test test test test ..250.. test test test test test test
mediumtext utf8mb4
Level Code Message
Note 1003 pack=253 plen=253 ; mdlen=16777215 flen=16777215 ; `assoc` mediumtext
assoc(0)
test test test test test test ..250.. test test test test test test
longtext latin1
Level Code Message
Note 1003 pack=254 plen=254 ; mdlen=4294967295 flen=4294967295 ; `assoc` longtext
assoc(0)
test test test test test test ..250.. test test test test test test
longtext utf8mb4
Level Code Message
Note 1003 pack=254 plen=254 ; mdlen=4294967295 flen=4294967295 ; `assoc` longtext
assoc(0)
test test test test test test ..250.. test test test test test test
text latin1
Level Code Message
Note 1003 pack=65537 plen=65537 ; mdlen=65535 flen=65535 ; `assoc` text
assoc(0)
test test test test test test ..65535.. test test test test test test
text utf8mb4
Level Code Message
Note 1003 pack=65537 plen=65537 ; mdlen=65535 flen=65535 ; `assoc` text
assoc(0)
test test test test test test ..65535.. test test test test test test
mediumtext latin1
Level Code Message
Note 1003 pack=65538 plen=65538 ; mdlen=16777215 flen=16777215 ; `assoc` mediumtext
assoc(0)
test test test test test test ..65535.. test test test test test test
mediumtext utf8mb4
Level Code Message
Note 1003 pack=65538 plen=65538 ; mdlen=16777215 flen=16777215 ; `assoc` mediumtext
assoc(0)
test test test test test test ..65535.. test test test test test test
longtext latin1
Level Code Message
Note 1003 pack=65539 plen=65539 ; mdlen=4294967295 flen=4294967295 ; `assoc` longtext
assoc(0)
test test test test test test ..65535.. test test test test test test
longtext utf8mb4
Level Code Message
Note 1003 pack=65539 plen=65539 ; mdlen=4294967295 flen=4294967295 ; `assoc` longtext
assoc(0)
test test test test test test ..65535.. test test test test test test
mediumtext utf8mb4
Level Code Message
Note 1003 pack=16777218 plen=16777218 ; mdlen=16777215 flen=16777215 ; `assoc` mediumtext
assoc(0)
test test test test test test ..16777215.. test test test test test test
longtext utf8mb4
Level Code Message
Note 1003 pack=16777224 plen=16777224 ; mdlen=4294967295 flen=4294967295 ; `assoc` longtext
assoc(0)
test test test test test test ..16777220.. test test test test test test
DROP PROCEDURE test_type;
DROP PROCEDURE test_types;
DROP TABLE dtypes;

View File

@ -0,0 +1,144 @@
-- source include/have_debug.inc
set sql_mode=oracle;
SET NAMES utf8mb4;
SELECT @@SESSION.max_allowed_packet;
--echo #
--echo # MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
--echo #
SET debug_dbug='d,assoc_array_pack';
CREATE TABLE dtypes
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
dtype VARCHAR(128),
val LONGTEXT
);
INSERT INTO dtypes (dtype, val) VALUES
('bit(1)', 'bit:1'),
('bit(8)', 'bit:255'),
('bit(16)', 'bit:65535'),
('bit(64)', 'bit:18446744073709551615'),
('tinyint', '123'),
('tinyint unsigned', '123'),
('smallint', '123'),
('smallint unsigned', '123'),
('int', '123'),
('int unsigned', '123'),
('mediumint', '123'),
('mediumint unsigned', '123'),
('bigint', '123'),
('bigint unsigned', '123'),
('decimal(10,2)', '123.45'),
('float', '123e5'),
('double', '123e5'),
('mariadb_schema.date', '2001-01-01'),
('time', '800:59:59'),
('time(6)', '800:59:59.123456'),
('datetime', '2001-01-01 23:59:59'),
('datetime(6)', '2001-01-01 23:59:59.123456'),
('timestamp', '2001-01-01 23:59:59'),
('timestamp(6)', '2001-01-01 23:59:59.123456'),
('binary(10)', 'test'),
('binary(20)', 'test'),
('binary(10)', 'test test'),
('binary(20)', 'test test'),
('char(10) character set latin1', 'test'),
('char(10) character set utf8mb4', 'test'),
('varchar(10) character set latin1', 'test'),
('varchar(10) character set utf8mb4', 'test'),
('tinytext character set latin1', 'test'),
('tinytext character set utf8mb4', 'test'),
('text character set latin1', 'test'),
('text character set utf8mb4', 'test'),
('mediumtext character set latin1', 'test'),
('mediumtext character set utf8mb4', 'test'),
('longtext character set latin1', 'test'),
('longtext character set utf8mb4', 'test'),
('char(255) character set latin1', REPEAT('test ',50)),
('char(255) character set utf8mb4', REPEAT('test ',50)),
('varchar(255) character set latin1', REPEAT('test ',50)),
('varchar(255) character set utf8mb4', REPEAT('test ',50)),
('tinytext character set latin1', REPEAT('test ',50)),
('tinytext character set utf8mb4', REPEAT('test ',50)),
('text character set latin1', REPEAT('test ',50)),
('text character set utf8mb4', REPEAT('test ',50)),
('mediumtext character set latin1', REPEAT('test ',50)),
('mediumtext character set utf8mb4', REPEAT('test ',50)),
('longtext character set latin1', REPEAT('test ',50)),
('longtext character set utf8mb4', REPEAT('test ',50)),
('text character set latin1', REPEAT('test ',(256*256-1)/5)),
('text character set utf8mb4', REPEAT('test ',(256*256-1)/5)),
('mediumtext character set latin1', REPEAT('test ',(256*256-1)/5)),
('mediumtext character set utf8mb4', REPEAT('test ',(256*256-1)/5)),
('longtext character set latin1', REPEAT('test ',(256*256-1)/5)),
('longtext character set utf8mb4', REPEAT('test ',(256*256-1)/5)),
('mediumtext character set utf8mb4', REPEAT('test ',(256*256*256-1)/5)),
('longtext character set utf8mb4', REPEAT('test ',(256*256*256-1)/5 + 1));
DELIMITER $$;
CREATE PROCEDURE test_type(rec dtypes%ROWTYPE) AS
TYPE assoc_t IS TABLE OF t1.val%TYPE INDEX BY INTEGER;
assoc assoc_t;
val LONGTEXT;
BEGIN
IF rec.val LIKE 'bit:%'
THEN
assoc(0) := CAST(REPLACE(rec.val,'bit:','') AS UNSIGNED);
SHOW WARNINGS;
SELECT assoc(0)+0 AS `assoc(0)`;
ELSIF rec.dtype LIKE 'binary%'
THEN
assoc(0):= rec.val;
SHOW WARNINGS;
SELECT HEX(assoc(0)), LENGTH(assoc(0));
ELSE
assoc(0) := rec.val;
SHOW WARNINGS;
IF LENGTH(rec.val) > 64
THEN
SELECT LEFT(assoc(0),30) ||
'..' || LENGTH(assoc(0)) || '.. ' ||
RIGHT(assoc(0),30) AS `assoc(0)`;
ELSE
SELECT assoc(0);
END IF;
END IF;
END;
$$
DELIMITER ;$$
DELIMITER $$;
CREATE PROCEDURE test_types AS
BEGIN
FOR rec IN (SELECT * FROM dtypes)
LOOP
EXECUTE IMMEDIATE REPLACE('CREATE TABLE t1 (val DTYPE)','DTYPE',rec.dtype);
SELECT
COLUMN_TYPE AS ``, COALESCE(CHARACTER_SET_NAME,'') AS ``
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_SCHEMA='test' AND TABLE_NAME='t1' AND COLUMN_NAME='val';
INSERT INTO t1 VALUES (rec.val);
CALL test_type(rec);
DROP TABLE t1;
END LOOP;
END;
$$
DELIMITER ;$$
CALL test_types;
DROP PROCEDURE test_type;
DROP PROCEDURE test_types;
DROP TABLE dtypes;

View File

@ -1,6 +1,9 @@
SET sql_mode=ORACLE;
SET NAMES utf8mb4;
# Needed for mtr --cursor
--enable_prepare_warnings
--echo #
--echo # MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
--echo #

View File

@ -1522,7 +1522,7 @@ marks(1) := 1;
SELECT marks(1).name;
END;
$$
ERROR 42S22: Unknown column '1' in 'SELECT'
ERROR 42S22: Unknown column 'name' in 'marks'
#
# Field assignment
#

View File

@ -128,12 +128,26 @@ public:
DBUG_ASSERT(field);
DBUG_ASSERT(m_buffer);
auto length= field->packed_col_length(field->ptr,
field->value_length()) + 1;
if (unlikely(m_buffer->realloc(length)))
uint length= field->packed_col_length();
if (unlikely(m_buffer->realloc(length + 1/*QQ: is +1 needed?*/)))
return true;
#ifndef DBUG_OFF
StringBuffer<64> type;
field->sql_type(type);
const uchar *pend=
#endif
field->pack(ptr(), field->ptr);
DBUG_ASSERT((uint) (pend - ptr()) == length);
DBUG_EXECUTE_IF("assoc_array_pack",
push_warning_printf(current_thd,
Sql_condition::WARN_LEVEL_NOTE,
ER_YES, "pack=%u plen=%u ; mdlen=%u flen=%u ; `%s` %s",
(uint) (pend - ptr()), length,
field->max_data_length(),
field->field_length,
field->field_name.str,
type.c_ptr()););
return false;
}
@ -271,8 +285,7 @@ public:
for (uint i= 0; i < vtable.s->fields; i++)
{
auto field= vtable.field[i];
length+= field->packed_col_length(field->ptr,
field->value_length()) + 1;
length+= field->packed_col_length() + 1;
}
return length;
@ -1532,8 +1545,7 @@ bool Field_assoc_array::create_element_buffer(THD *thd, Binary_string *buffer)
return buffer->alloc(length);
}
uint length= m_element_field->packed_col_length(m_element_field->ptr,
m_element_field->value_length()) + 1;
uint length= m_element_field->packed_col_length() + 1;
return buffer->alloc(length);
}
@ -2005,7 +2017,7 @@ bool Item_splocal_assoc_array_element_field::fix_fields(THD *thd, Item **ref)
m_field_name,
m_field_idx))
{
my_error(ER_BAD_FIELD_ERROR, MYF(0), str->c_ptr(), thd_where(thd));
my_error(ER_BAD_FIELD_ERROR, MYF(0), m_field_name.str, m_name.str);
return true;
}

View File

@ -294,12 +294,11 @@ public:
extending the binary log format to put the extact data type name into
the column metadata.
*/
static uchar *pack(uchar *to, const uchar *from, uint max_length)
static uchar *pack(uchar *to, const uchar *from)
{
uchar buf[binary_length()];
record_to_memory((char *) buf, (const char *) from);
return StringPack(&my_charset_bin, binary_length()).
pack(to, buf, max_length);
return StringPack(&my_charset_bin, binary_length()).pack(to, buf);
}
// Convert binlog representation to in-record representation

View File

@ -2126,19 +2126,11 @@ int Field_blob::store_from_statistical_minmax_field(Field *stat_field,
@param from
Pointer to memory area where record representation of field is
stored.
@param max_length
Maximum length of the field, as given in the column definition. For
example, for <code>CHAR(1000)</code>, the <code>max_length</code>
is 1000. This information is sometimes needed to decide how to pack
the data.
*/
uchar *
Field::pack(uchar *to, const uchar *from, uint max_length)
Field::pack(uchar *to, const uchar *from) const
{
uint32 length= pack_length();
set_if_smaller(length, max_length);
memcpy(to, from, length);
return to+length;
}
@ -7608,12 +7600,6 @@ int Field_longstr::store_decimal(const my_decimal *d)
return store(str.ptr(), str.length(), str.charset());
}
uint32 Field_longstr::max_data_length() const
{
return field_length + (field_length > 255 ? 2 : 1);
}
Data_type_compatibility
Field_longstr::cmp_to_string_with_same_collation(const Item_bool_func *cond,
const Item *item) const
@ -7917,10 +7903,10 @@ void Field_string::sql_rpl_type(String *res) const
Field_string::sql_type(*res);
}
uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length)
uchar *Field_string::pack(uchar *to, const uchar *from) const
{
DBUG_PRINT("debug", ("Packing field '%s'", field_name.str));
return StringPack(field_charset(), field_length).pack(to, from, max_length);
return StringPack(field_charset(), field_length).pack(to, from);
}
@ -8004,13 +7990,14 @@ Binlog_type_info Field_string::binlog_type_info() const
}
uint Field_string::packed_col_length(const uchar *data_ptr, uint length)
uint Field_string::packed_col_length() const
{
return StringPack::packed_col_length(data_ptr, length);
return StringPack(field_charset(), field_length).
packed_col_length(ptr);
}
uint Field_string::max_packed_col_length(uint max_length)
uint Field_string::max_packed_col_length(uint max_length) const
{
return StringPack::max_packed_col_length(max_length);
}
@ -8395,19 +8382,16 @@ uint32 Field_varstring::data_length()
/*
Functions to create a packed row.
Here the number of length bytes are depending on the given max_length
*/
uchar *Field_varstring::pack(uchar *to, const uchar *from, uint max_length)
uchar *Field_varstring::pack(uchar *to, const uchar *from) const
{
uint length= length_bytes == 1 ? (uint) *from : uint2korr(from);
set_if_smaller(max_length, field_length);
if (length > max_length)
length=max_length;
DBUG_ASSERT(length <= field_length);
/* Length always stored little-endian */
*to++= length & 0xFF;
if (max_length > 255)
if (field_length > 255)
*to++= (length >> 8) & 0xFF;
/* Store bytes of string */
@ -8466,15 +8450,15 @@ Field_varstring::unpack(uchar *to, const uchar *from, const uchar *from_end,
}
uint Field_varstring::packed_col_length(const uchar *data_ptr, uint length)
uint Field_varstring::packed_col_length() const
{
if (length > 255)
return uint2korr(data_ptr)+2;
return (uint) *data_ptr + 1;
if (field_length > 255)
return uint2korr(ptr) + 2;
return (uint) *ptr + 1;
}
uint Field_varstring::max_packed_col_length(uint max_length)
uint Field_varstring::max_packed_col_length(uint max_length) const
{
return (max_length > 255 ? 2 : 1)+max_length;
}
@ -8823,6 +8807,7 @@ Field_blob::Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
void Field_blob::store_length(uchar *i_ptr, uint i_packlength, uint32 i_number)
const
{
store_lowendian(i_number, i_ptr, i_packlength);
}
@ -9287,7 +9272,7 @@ void Field_blob::sql_type(String &res) const
}
}
uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length)
uchar *Field_blob::pack(uchar *to, const uchar *from) const
{
uint32 length=get_length(from, packlength); // Length of from string
@ -9296,7 +9281,7 @@ uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length)
length given is smaller than the actual length of the blob, we
just store the initial bytes of the blob.
*/
store_length(to, packlength, MY_MIN(length, max_length));
store_length(to, packlength, length);
/*
Store the actual blob data, which will occupy 'length' bytes.
@ -9347,15 +9332,13 @@ const uchar *Field_blob::unpack(uchar *to, const uchar *from,
}
uint Field_blob::packed_col_length(const uchar *data_ptr, uint length)
uint Field_blob::packed_col_length() const
{
if (length > 255)
return uint2korr(data_ptr)+2;
return (uint) *data_ptr + 1;
return (uint) read_lowendian(ptr, packlength) + packlength;
}
uint Field_blob::max_packed_col_length(uint max_length)
uint Field_blob::max_packed_col_length(uint max_length) const
{
return (max_length > 255 ? 2 : 1)+max_length;
}
@ -9891,7 +9874,7 @@ bool Field_enum::is_equal(const Column_definition &new_field) const
}
uchar *Field_enum::pack(uchar *to, const uchar *from, uint max_length)
uchar *Field_enum::pack(uchar *to, const uchar *from) const
{
DBUG_ENTER("Field_enum::pack");
DBUG_PRINT("debug", ("packlength: %d", packlength));
@ -10389,10 +10372,8 @@ void Field_bit::sql_type(String &res) const
uchar *
Field_bit::pack(uchar *to, const uchar *from, uint max_length)
Field_bit::pack(uchar *to, const uchar *from) const
{
DBUG_ASSERT(max_length > 0);
uint length;
if (bit_len > 0)
{
/*
@ -10417,9 +10398,8 @@ Field_bit::pack(uchar *to, const uchar *from, uint max_length)
uchar bits= get_rec_bits(bit_ptr + (from - ptr), bit_ofs, bit_len);
*to++= bits;
}
length= MY_MIN(bytes_in_rec, max_length - (bit_len > 0));
memcpy(to, from, length);
return to + length;
memcpy(to, from, bytes_in_rec);
return to + bytes_in_rec;
}

View File

@ -1717,23 +1717,14 @@ public:
}
virtual bool send(Protocol *protocol);
virtual uchar *pack(uchar *to, const uchar *from, uint max_length);
/**
@overload Field::pack(uchar*, const uchar*, uint, bool)
*/
uchar *pack(uchar *to, const uchar *from)
{
DBUG_ENTER("Field::pack");
uchar *result= this->pack(to, from, UINT_MAX);
DBUG_RETURN(result);
}
virtual uchar *pack(uchar *to, const uchar *from) const;
virtual const uchar *unpack(uchar* to, const uchar *from,
const uchar *from_end, uint param_data=0);
virtual uint packed_col_length(const uchar *to, uint length)
{ return length;}
virtual uint max_packed_col_length(uint max_length)
virtual uint packed_col_length() const
{ return pack_length(); }
virtual uint max_packed_col_length(uint max_length) const
{ return max_length;}
virtual bool is_packable() const { return false; }
@ -2118,14 +2109,14 @@ private:
virtual size_t do_last_null_byte() const;
protected:
uchar *pack_int(uchar *to, const uchar *from, size_t size)
static uchar *pack_int(uchar *to, const uchar *from, size_t size)
{
memcpy(to, from, size);
return to + size;
}
const uchar *unpack_int(uchar* to, const uchar *from,
const uchar *from_end, size_t size)
static const uchar *unpack_int(uchar* to, const uchar *from,
const uchar *from_end, size_t size)
{
if (from + size > from_end)
return 0;
@ -2133,21 +2124,25 @@ protected:
return from + size;
}
uchar *pack_int16(uchar *to, const uchar *from)
static uchar *pack_int16(uchar *to, const uchar *from)
{ return pack_int(to, from, 2); }
const uchar *unpack_int16(uchar* to, const uchar *from, const uchar *from_end)
static const uchar *unpack_int16(uchar* to,
const uchar *from, const uchar *from_end)
{ return unpack_int(to, from, from_end, 2); }
uchar *pack_int24(uchar *to, const uchar *from)
static uchar *pack_int24(uchar *to, const uchar *from)
{ return pack_int(to, from, 3); }
const uchar *unpack_int24(uchar* to, const uchar *from, const uchar *from_end)
static const uchar *unpack_int24(uchar* to,
const uchar *from, const uchar *from_end)
{ return unpack_int(to, from, from_end, 3); }
uchar *pack_int32(uchar *to, const uchar *from)
static uchar *pack_int32(uchar *to, const uchar *from)
{ return pack_int(to, from, 4); }
const uchar *unpack_int32(uchar* to, const uchar *from, const uchar *from_end)
static const uchar *unpack_int32(uchar* to,
const uchar *from, const uchar *from_end)
{ return unpack_int(to, from, from_end, 4); }
uchar *pack_int64(uchar* to, const uchar *from)
static uchar *pack_int64(uchar* to, const uchar *from)
{ return pack_int(to, from, 8); }
const uchar *unpack_int64(uchar* to, const uchar *from, const uchar *from_end)
static const uchar *unpack_int64(uchar* to,
const uchar *from, const uchar *from_end)
{ return unpack_int(to, from, from_end, 8); }
double pos_in_interval_val_real(Field *min, Field *max);
@ -2379,7 +2374,8 @@ public:
const Relay_log_info *rli,
const Conv_param &param) const override;
int store_decimal(const my_decimal *d) override;
uint32 max_data_length() const override;
uint32 max_data_length() const override= 0;
uint packed_col_length() const override= 0;
void make_send_field(Send_field *) override;
bool send(Protocol *protocol) override;
bool val_bool() override;
@ -2503,9 +2499,9 @@ public:
void overflow(bool negative);
bool zero_pack() const override { return false; }
void sql_type(String &str) const override;
uchar *pack(uchar* to, const uchar *from, uint max_length) override
uchar *pack(uchar* to, const uchar *from) const override
{
return Field::pack(to, from, max_length);
return Field::pack(to, from);
}
};
@ -2720,7 +2716,7 @@ public:
return type_handler_priv()->type_limits_int();
}
uchar *pack(uchar* to, const uchar *from, uint max_length) override
uchar *pack(uchar* to, const uchar *from) const override
{
*to= *from;
return to + 1;
@ -2782,7 +2778,7 @@ public:
{
return type_handler_priv()->type_limits_int();
}
uchar *pack(uchar* to, const uchar *from, uint) override
uchar *pack(uchar* to, const uchar *from) const override
{ return pack_int16(to, from); }
const uchar *unpack(uchar* to, const uchar *from,
@ -2829,9 +2825,9 @@ public:
{
return type_handler_priv()->type_limits_int();
}
uchar *pack(uchar* to, const uchar *from, uint max_length) override
uchar *pack(uchar* to, const uchar *from) const override
{
return Field::pack(to, from, max_length);
return Field::pack(to, from);
}
ulonglong get_max_int_value() const override
{
@ -2881,7 +2877,7 @@ public:
{
return type_handler_priv()->type_limits_int();
}
uchar *pack(uchar* to, const uchar *from, uint) override
uchar *pack(uchar* to, const uchar *from) const override
{
return pack_int32(to, from);
}
@ -2942,7 +2938,7 @@ public:
{
return type_handler_priv()->type_limits_int();
}
uchar *pack(uchar* to, const uchar *from, uint) override
uchar *pack(uchar* to, const uchar *from) const override
{
return pack_int64(to, from);
}
@ -3404,7 +3400,7 @@ public:
/* Get TIMESTAMP field value as seconds since begging of Unix Epoch */
my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const override;
bool val_native(Native *to) override;
uchar *pack(uchar *to, const uchar *from, uint) override
uchar *pack(uchar *to, const uchar *from) const override
{
return pack_int32(to, from);
}
@ -3441,8 +3437,8 @@ public:
}
decimal_digits_t decimals() const override { return dec; }
enum ha_base_keytype key_type() const override { return HA_KEYTYPE_BINARY; }
uchar *pack(uchar *to, const uchar *from, uint max_length) override
{ return Field::pack(to, from, max_length); }
uchar *pack(uchar *to, const uchar *from) const override
{ return Field::pack(to, from); }
const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
uint param_data) override
{ return Field::unpack(to, from, from_end, param_data); }
@ -3654,7 +3650,7 @@ public:
void sort_string(uchar *buff,uint length) override;
uint32 pack_length() const override { return 4; }
void sql_type(String &str) const override;
uchar *pack(uchar* to, const uchar *from, uint) override
uchar *pack(uchar* to, const uchar *from) const override
{
return pack_int32(to, from);
}
@ -3975,7 +3971,7 @@ public:
uint32 pack_length() const override { return 8; }
bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override
{ return Field_datetime0::get_TIME(ltime, ptr, fuzzydate); }
uchar *pack(uchar* to, const uchar *from, uint) override
uchar *pack(uchar* to, const uchar *from) const override
{
return pack_int64(to, from);
}
@ -4010,8 +4006,8 @@ public:
enum ha_base_keytype key_type() const override final { return HA_KEYTYPE_BINARY; }
void make_send_field(Send_field *field) override final;
bool send(Protocol *protocol) override final;
uchar *pack(uchar *to, const uchar *from, uint max_length) override final
{ return Field::pack(to, from, max_length); }
uchar *pack(uchar *to, const uchar *from) const override final
{ return Field::pack(to, from); }
const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
uint param_data) override final
{ return Field::unpack(to, from, from_end, param_data); }
@ -4216,7 +4212,7 @@ public:
void sql_type(String &str) const override;
void sql_rpl_type(String*) const override;
bool is_equal(const Column_definition &new_field) const override;
uchar *pack(uchar *to, const uchar *from, uint max_length) override;
uchar *pack(uchar *to, const uchar *from) const override;
const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
uint param_data) override;
uint pack_length_from_metadata(uint field_metadata) const override
@ -4229,8 +4225,12 @@ public:
bool compatible_field_size(uint field_metadata, const Relay_log_info *rli,
uint16 mflags, int *order_var) const override;
uint row_pack_length() const override { return field_length; }
uint packed_col_length(const uchar *to, uint length) override;
uint max_packed_col_length(uint max_length) override;
uint32 max_data_length() const override
{
return field_length;
}
uint packed_col_length() const override;
uint max_packed_col_length(uint max_length) const override;
uint size_of() const override { return sizeof *this; }
bool has_charset() const override { return charset() != &my_charset_bin; }
Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type)
@ -4263,7 +4263,7 @@ public:
return length_bytes == 1 ? (uint) *ptr_arg : uint2korr(ptr_arg);
}
protected:
void store_length(uint32 number)
void store_length(uint32 number) const
{
if (length_bytes == 1)
*ptr= (uchar) number;
@ -4311,6 +4311,10 @@ public:
uint row_pack_length() const override { return field_length; }
bool zero_pack() const override { return false; }
int reset() override { bzero(ptr,field_length+length_bytes); return 0; }
uint32 max_data_length() const override
{
return field_length + (field_length > 255 ? 2 : 1);
}
uint32 pack_length() const override
{ return (uint32) field_length+length_bytes; }
uint32 key_length() const override { return (uint32) field_length; }
@ -4348,15 +4352,15 @@ public:
void set_key_image(const uchar *buff,uint length) override;
void sql_type(String &str) const override;
void sql_rpl_type(String*) const override;
uchar *pack(uchar *to, const uchar *from, uint max_length) override;
uchar *pack(uchar *to, const uchar *from) const override;
const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
uint param_data) override;
int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U) const
override;
int key_cmp(const uchar *,const uchar*) const override;
int key_cmp(const uchar *str, uint length) const override;
uint packed_col_length(const uchar *to, uint length) override;
uint max_packed_col_length(uint max_length) override;
uint packed_col_length() const override;
uint max_packed_col_length(uint max_length) const override;
uint32 data_length() override;
uint size_of() const override { return sizeof *this; }
bool has_charset() const override
@ -4677,8 +4681,8 @@ public:
bzero((uchar*) &read_value, sizeof read_value);
}
uint32 get_field_buffer_size() { return value.alloced_length(); }
void store_length(uchar *i_ptr, uint i_packlength, uint32 i_number);
void store_length(size_t number)
void store_length(uchar *i_ptr, uint i_packlength, uint32 i_number) const;
void store_length(size_t number) const
{
DBUG_ASSERT(number < UINT_MAX32);
store_length(ptr, packlength, (uint32)number);
@ -4778,11 +4782,11 @@ public:
/* Set value pointer. Lengths are not important */
value.reset((char*) data, 1, 1, &my_charset_bin);
}
uchar *pack(uchar *to, const uchar *from, uint max_length) override;
uchar *pack(uchar *to, const uchar *from) const override;
const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end,
uint param_data) override;
uint packed_col_length(const uchar *col_ptr, uint length) override;
uint max_packed_col_length(uint max_length) override;
uint packed_col_length() const override;
uint max_packed_col_length(uint max_length) const override;
void free() override
{
value.free();
@ -4972,7 +4976,7 @@ public:
{
return Type_extra_attributes(m_typelib);
}
uchar *pack(uchar *to, const uchar *from, uint max_length) override;
uchar *pack(uchar *to, const uchar *from) const override;
const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end,
uint param_data) override;
@ -5177,7 +5181,7 @@ public:
bool compatible_field_size(uint metadata, const Relay_log_info *rli,
uint16 mflags, int *order_var) const override;
void sql_type(String &str) const override;
uchar *pack(uchar *to, const uchar *from, uint max_length) override;
uchar *pack(uchar *to, const uchar *from) const override;
const uchar *unpack(uchar *to, const uchar *from,
const uchar *from_end, uint param_data) override;
int set_default() override;

View File

@ -103,8 +103,7 @@ pack_row(TABLE *table, MY_BITMAP const* cols,
#ifndef DBUG_OFF
const uchar *old_pack_ptr= pack_ptr;
#endif
pack_ptr= field->pack(pack_ptr, field->ptr + offset,
field->max_data_length());
pack_ptr= field->pack(pack_ptr, field->ptr + offset);
DBUG_PRINT("debug", ("field: %s; real_type: %d, pack_ptr: %p;"
" pack_ptr':%p; bytes: %d",
field->field_name.str, field->real_type(),

View File

@ -719,10 +719,10 @@ public:
FbtImpl::binary_length(), &my_charset_bin);
}
uchar *pack(uchar *to, const uchar *from, uint max_length) override
uchar *pack(uchar *to, const uchar *from) const override
{
DBUG_PRINT("debug", ("Packing field '%s'", field_name.str));
return FbtImpl::pack(to, from, max_length);
return FbtImpl::pack(to, from);
}
const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end,
@ -731,14 +731,15 @@ public:
return FbtImpl::unpack(to, from, from_end, param_data);
}
uint max_packed_col_length(uint max_length) override
uint max_packed_col_length(uint max_length) const override
{
return StringPack::max_packed_col_length(max_length);
}
uint packed_col_length(const uchar *fbt_ptr, uint length) override
uint packed_col_length() const override
{
return StringPack::packed_col_length(fbt_ptr, length);
return StringPack(&my_charset_bin, pack_length()).
packed_col_length(ptr);
}
uint size_of() const override { return sizeof(*this); }

View File

@ -150,9 +150,9 @@ public:
Used in Field::pack(), and in filesort to store the addon fields.
By default, do what BINARY(N) does.
*/
static uchar *pack(uchar *to, const uchar *from, uint max_length)
static uchar *pack(uchar *to, const uchar *from)
{
return StringPack(&my_charset_bin, binary_length()).pack(to, from, max_length);
return StringPack(&my_charset_bin, binary_length()).pack(to, from);
}
/*

View File

@ -20,31 +20,52 @@
#include "sql_type_string.h"
uchar *
StringPack::pack(uchar *to, const uchar *from, uint max_length) const
// Trim trailing spaces for CHAR or 0x00 bytes for BINARY
uint StringPack::rtrimmed_length(const char *from) const
{
size_t length= MY_MIN(m_octet_length, max_length);
size_t local_char_length= char_length();
DBUG_PRINT("debug", ("length: %zu ", length));
DBUG_PRINT("debug", ("length: %u ", (uint) m_octet_length));
if (mbmaxlen() > 1)
{
/*
Suppose we have CHAR(100) CHARACTER SET utf8mb4.
Its octet_length is 400.
- In case of ASCII characters only, the leftmost 100 bytes
contain real data, the other 300 bytes are padding spaces.
- In case of 100 2-byte characters, the leftmost 200 bytes
contain real data, the other 200 bytes are padding spaces.
- All 400 bytes contain real data (without padding spaces)
only in case of 100 4-byte characters, which is a rare scenario.
There are two approaches possible to trim the data:
1. Left-to-right: call charpos() to find the end of the 100th
character, then switch to a right-to-left loop to trim trailing spaces.
2. Right-to-left: trim characters from the position "from+400" towards
the beginning.
N1 should be faster in an average case, and is much faster for pure ASCII.
*/
size_t length= charset()->charpos(from, from+m_octet_length, char_length());
return (uint) charset()->lengthsp((const char*) from, length);
}
if (length > local_char_length)
local_char_length= charset()->charpos(from, from + length,
local_char_length);
set_if_smaller(length, local_char_length);
/*
TODO: change charset interface to add a new function that does
the following or add a flag to lengthsp to do it itself
(this is for not packing padding adding bytes in BINARY
fields).
*/
if (mbmaxlen() == 1)
{
while (length && from[length-1] == charset()->pad_char)
length --;
}
else
length= charset()->lengthsp((const char*) from, length);
size_t length= m_octet_length;
while (length && from[length - 1] == charset()->pad_char)
length --;
return (uint) length;
}
uchar *
StringPack::pack(uchar *to, const uchar *from) const
{
size_t length= rtrimmed_length((const char *) from);
// Length always stored little-endian
*to++= (uchar) length;

View File

@ -23,24 +23,29 @@ class StringPack
CHARSET_INFO *charset() const { return m_cs; }
uint mbmaxlen() const { return m_cs->mbmaxlen; };
uint32 char_length() const { return m_octet_length / mbmaxlen(); }
// Trim trailing spaces for CHAR or 0x00 bytes for BINARY
uint rtrimmed_length(const char *from) const;
static uint length_bytes(uint max_length)
{
return max_length > 255 ? 2 : 1;
}
public:
StringPack(CHARSET_INFO *cs, uint32 octet_length)
:m_cs(cs),
m_octet_length(octet_length)
{ }
uchar *pack(uchar *to, const uchar *from, uint max_length) const;
uchar *pack(uchar *to, const uchar *from) const;
const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end,
uint param_data) const;
public:
static uint max_packed_col_length(uint max_length)
{
return (max_length > 255 ? 2 : 1) + max_length;
return length_bytes(max_length) + max_length;
}
static uint packed_col_length(const uchar *data_ptr, uint length)
uint packed_col_length(const uchar *data_ptr) const
{
if (length > 255)
return uint2korr(data_ptr)+2;
return (uint) *data_ptr + 1;
return length_bytes(m_octet_length) +
rtrimmed_length((const char *) data_ptr);
}
};