1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-27018 IF and COALESCE lose "json" property

Hybrid functions (IF, COALESCE, etc) did not preserve the JSON property
from their arguments. The same problem was repeatable for single row subselects.

The problem happened because the method Item::is_json_type() was inconsistently
implemented across the Item hierarchy. For example, Item_hybrid_func
and Item_singlerow_subselect did not override is_json_type().

Solution:

- Removing Item::is_json_type()

- Implementing specific JSON type handlers:
  Type_handler_string_json
  Type_handler_varchar_json
  Type_handler_tiny_blob_json
  Type_handler_blob_json
  Type_handler_medium_blob_json
  Type_handler_long_blob_json

- Reusing the existing data type infrastructure to pass JSON
  type handlers across all item types, including classes Item_hybrid_func
  and Item_singlerow_subselect. Note, these two classes themselves do not
  need any changes!

- Extending the data type infrastructure so data types can inherit
  their properties (e.g. aggregation rules) from their base data types.
  E.g. VARCHAR/JSON acts as VARCHAR, LONGTEXT/JSON acts as LONGTEXT
  when mixed to a non-JSON data type. This is done by:
    - adding virtual method Type_handler::type_handler_base()
    - adding a helper class Type_handler_pair
    - refactoring Type_handler_hybrid_field_type methods
      aggregate_for_result(), aggregate_for_min_max(),
      aggregate_for_num_op() to use Type_handler_pair.

This change also fixes:

  MDEV-27361 Hybrid functions with JSON arguments do not send format metadata

Also, adding mtr tests for JSON replication. It was not covered yet.
And the current patch changes the replication code slightly.
This commit is contained in:
Alexander Barkov
2022-01-10 18:05:55 +04:00
parent 28e166d643
commit e4b302e436
33 changed files with 4015 additions and 100 deletions

View File

@ -1388,5 +1388,14 @@ id materials
DROP TABLE t1;
DROP TABLE t2;
#
# MDEV-27018 IF and COALESCE lose "json" property
#
SELECT json_object('a', if(1, json_object('b', 'c'), json_object('e', 'f')));
json_object('a', if(1, json_object('b', 'c'), json_object('e', 'f')))
{"a": {"b": "c"}}
SELECT json_object('a', coalesce(json_object('b', 'c')));
json_object('a', coalesce(json_object('b', 'c')))
{"a": {"b": "c"}}
#
# End of 10.5 tests
#

View File

@ -879,6 +879,14 @@ SELECT t1.id, JSON_ARRAYAGG(JSON_OBJECT('id',t2.id) ORDER BY t2.id) as materials
DROP TABLE t1;
DROP TABLE t2;
--echo #
--echo # MDEV-27018 IF and COALESCE lose "json" property
--echo #
SELECT json_object('a', if(1, json_object('b', 'c'), json_object('e', 'f')));
SELECT json_object('a', coalesce(json_object('b', 'c')));
--echo #
--echo # End of 10.5 tests
--echo #

View File

@ -126,5 +126,38 @@ def JSON_COMPACT('{}') 253 (format=json) 6 0 Y 0 0 33
js0 JSON_COMPACT(js0) JSON_COMPACT('{}')
DROP TABLE t1;
#
# MDEV-27361 Hybrid functions with JSON arguments do not send format metadata
#
CREATE TABLE t1 (a JSON);
INSERT INTO t1 VALUES ('{"a":"b"}');
SELECT a, JSON_COMPACT(a), COALESCE(a) FROM t1;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def test t1 t1 a a 252 (format=json) 4294967295 9 Y 144 0 33
def JSON_COMPACT(a) 251 (format=json) 4294967295 9 Y 128 0 33
def COALESCE(a) 251 (format=json) 4294967295 9 Y 128 39 33
a JSON_COMPACT(a) COALESCE(a)
{"a":"b"} {"a":"b"} {"a":"b"}
SELECT JSON_ARRAYAGG(1), JSON_ARRAYAGG(a) FROM t1;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def JSON_ARRAYAGG(1) 252 (format=json) 9437184 3 Y 0 0 33
def JSON_ARRAYAGG(a) 252 (format=json) 12582912 11 Y 128 0 33
JSON_ARRAYAGG(1) JSON_ARRAYAGG(a)
[1] [{"a":"b"}]
SELECT JSON_OBJECTAGG('a','b'), JSON_OBJECTAGG('a',a) FROM t1;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def JSON_OBJECTAGG('a','b') 252 (format=json) 9437184 9 Y 0 0 33
def JSON_OBJECTAGG('a',a) 252 (format=json) 12582912 15 Y 128 0 33
JSON_OBJECTAGG('a','b') JSON_OBJECTAGG('a',a)
{"a":"b"} {"a":{"a":"b"}}
DROP TABLE t1;
#
# MDEV-27018 IF and COALESCE lose "json" property
#
SELECT json_object('a', (SELECT json_objectagg(b, c) FROM (SELECT 'b','c') d)) AS j FROM DUAL;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def j 250 (format=json) 9437283 16 Y 0 39 33
j
{"a": {"b":"c"}}
#
# End of 10.5 tests
#

View File

@ -88,6 +88,34 @@ SELECT js0, JSON_COMPACT(js0), JSON_COMPACT('{}') FROM t1;
--enable_ps_protocol
DROP TABLE t1;
--echo #
--echo # MDEV-27361 Hybrid functions with JSON arguments do not send format metadata
--echo #
CREATE TABLE t1 (a JSON);
INSERT INTO t1 VALUES ('{"a":"b"}');
--disable_ps_protocol
--enable_metadata
SELECT a, JSON_COMPACT(a), COALESCE(a) FROM t1;
SELECT JSON_ARRAYAGG(1), JSON_ARRAYAGG(a) FROM t1;
SELECT JSON_OBJECTAGG('a','b'), JSON_OBJECTAGG('a',a) FROM t1;
--disable_metadata
--disable_ps_protocol
DROP TABLE t1;
--echo #
--echo # MDEV-27018 IF and COALESCE lose "json" property
--echo #
--disable_ps_protocol
--enable_metadata
SELECT json_object('a', (SELECT json_objectagg(b, c) FROM (SELECT 'b','c') d)) AS j FROM DUAL;
--disable_metadata
--disable_ps_protocol
--echo #
--echo # End of 10.5 tests
--echo #

View File

@ -0,0 +1,22 @@
include/master-slave.inc
[connection master]
#
# Start of 10.5 tests
#
#
# MDEV-27018 IF and COALESCE lose "json" property
#
CREATE TABLE t1 (a CHAR(100) CHECK(JSON_VALID(a)));
connection slave;
connection master;
INSERT INTO t1 VALUES (JSON_OBJECT('a','b'));
connection slave;
SELECT * FROM t1 ORDER BY a;
a
{"a": "b"}
connection master;
DROP TABLE t1;
#
# End of 10.5 tests
#
include/rpl_end.inc

View File

@ -0,0 +1,22 @@
include/master-slave.inc
[connection master]
#
# Start of 10.5 tests
#
#
# MDEV-27018 IF and COALESCE lose "json" property
#
CREATE TABLE t1 (a LONGTEXT CHECK(JSON_VALID(a)));
connection slave;
connection master;
INSERT INTO t1 VALUES (JSON_OBJECT('a','b'));
connection slave;
SELECT * FROM t1 ORDER BY a;
a
{"a": "b"}
connection master;
DROP TABLE t1;
#
# End of 10.5 tests
#
include/rpl_end.inc

View File

@ -0,0 +1,22 @@
include/master-slave.inc
[connection master]
#
# Start of 10.5 tests
#
#
# MDEV-27018 IF and COALESCE lose "json" property
#
CREATE TABLE t1 (a MEDIUMTEXT CHECK(JSON_VALID(a)));
connection slave;
connection master;
INSERT INTO t1 VALUES (JSON_OBJECT('a','b'));
connection slave;
SELECT * FROM t1 ORDER BY a;
a
{"a": "b"}
connection master;
DROP TABLE t1;
#
# End of 10.5 tests
#
include/rpl_end.inc

View File

@ -0,0 +1,22 @@
include/master-slave.inc
[connection master]
#
# Start of 10.5 tests
#
#
# MDEV-27018 IF and COALESCE lose "json" property
#
CREATE TABLE t1 (a TEXT CHECK(JSON_VALID(a)));
connection slave;
connection master;
INSERT INTO t1 VALUES (JSON_OBJECT('a','b'));
connection slave;
SELECT * FROM t1 ORDER BY a;
a
{"a": "b"}
connection master;
DROP TABLE t1;
#
# End of 10.5 tests
#
include/rpl_end.inc

View File

@ -0,0 +1,22 @@
include/master-slave.inc
[connection master]
#
# Start of 10.5 tests
#
#
# MDEV-27018 IF and COALESCE lose "json" property
#
CREATE TABLE t1 (a TINYTEXT CHECK(JSON_VALID(a)));
connection slave;
connection master;
INSERT INTO t1 VALUES (JSON_OBJECT('a','b'));
connection slave;
SELECT * FROM t1 ORDER BY a;
a
{"a": "b"}
connection master;
DROP TABLE t1;
#
# End of 10.5 tests
#
include/rpl_end.inc

View File

@ -0,0 +1,22 @@
include/master-slave.inc
[connection master]
#
# Start of 10.5 tests
#
#
# MDEV-27018 IF and COALESCE lose "json" property
#
CREATE TABLE t1 (a VARCHAR(100) CHECK(JSON_VALID(a)));
connection slave;
connection master;
INSERT INTO t1 VALUES (JSON_OBJECT('a','b'));
connection slave;
SELECT * FROM t1 ORDER BY a;
a
{"a": "b"}
connection master;
DROP TABLE t1;
#
# End of 10.5 tests
#
include/rpl_end.inc

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
--source include/master-slave.inc
--echo #
--echo # Start of 10.5 tests
--echo #
--echo #
--echo # MDEV-27018 IF and COALESCE lose "json" property
--echo #
CREATE TABLE t1 (a CHAR(100) CHECK(JSON_VALID(a)));
--sync_slave_with_master
--connection master
INSERT INTO t1 VALUES (JSON_OBJECT('a','b'));
--sync_slave_with_master
SELECT * FROM t1 ORDER BY a;
--connection master
DROP TABLE t1;
--echo #
--echo # End of 10.5 tests
--echo #
--source include/rpl_end.inc

View File

@ -0,0 +1,27 @@
--source include/master-slave.inc
--echo #
--echo # Start of 10.5 tests
--echo #
--echo #
--echo # MDEV-27018 IF and COALESCE lose "json" property
--echo #
CREATE TABLE t1 (a LONGTEXT CHECK(JSON_VALID(a)));
--sync_slave_with_master
--connection master
INSERT INTO t1 VALUES (JSON_OBJECT('a','b'));
--sync_slave_with_master
SELECT * FROM t1 ORDER BY a;
--connection master
DROP TABLE t1;
--echo #
--echo # End of 10.5 tests
--echo #
--source include/rpl_end.inc

View File

@ -0,0 +1,27 @@
--source include/master-slave.inc
--echo #
--echo # Start of 10.5 tests
--echo #
--echo #
--echo # MDEV-27018 IF and COALESCE lose "json" property
--echo #
CREATE TABLE t1 (a MEDIUMTEXT CHECK(JSON_VALID(a)));
--sync_slave_with_master
--connection master
INSERT INTO t1 VALUES (JSON_OBJECT('a','b'));
--sync_slave_with_master
SELECT * FROM t1 ORDER BY a;
--connection master
DROP TABLE t1;
--echo #
--echo # End of 10.5 tests
--echo #
--source include/rpl_end.inc

View File

@ -0,0 +1,27 @@
--source include/master-slave.inc
--echo #
--echo # Start of 10.5 tests
--echo #
--echo #
--echo # MDEV-27018 IF and COALESCE lose "json" property
--echo #
CREATE TABLE t1 (a TEXT CHECK(JSON_VALID(a)));
--sync_slave_with_master
--connection master
INSERT INTO t1 VALUES (JSON_OBJECT('a','b'));
--sync_slave_with_master
SELECT * FROM t1 ORDER BY a;
--connection master
DROP TABLE t1;
--echo #
--echo # End of 10.5 tests
--echo #
--source include/rpl_end.inc

View File

@ -0,0 +1,27 @@
--source include/master-slave.inc
--echo #
--echo # Start of 10.5 tests
--echo #
--echo #
--echo # MDEV-27018 IF and COALESCE lose "json" property
--echo #
CREATE TABLE t1 (a TINYTEXT CHECK(JSON_VALID(a)));
--sync_slave_with_master
--connection master
INSERT INTO t1 VALUES (JSON_OBJECT('a','b'));
--sync_slave_with_master
SELECT * FROM t1 ORDER BY a;
--connection master
DROP TABLE t1;
--echo #
--echo # End of 10.5 tests
--echo #
--source include/rpl_end.inc

View File

@ -0,0 +1,27 @@
--source include/master-slave.inc
--echo #
--echo # Start of 10.5 tests
--echo #
--echo #
--echo # MDEV-27018 IF and COALESCE lose "json" property
--echo #
CREATE TABLE t1 (a VARCHAR(100) CHECK(JSON_VALID(a)));
--sync_slave_with_master
--connection master
INSERT INTO t1 VALUES (JSON_OBJECT('a','b'));
--sync_slave_with_master
SELECT * FROM t1 ORDER BY a;
--connection master
DROP TABLE t1;
--echo #
--echo # End of 10.5 tests
--echo #
--source include/rpl_end.inc

View File

@ -0,0 +1,143 @@
--echo #
--echo # Start of 10.5 tests
--echo #
--echo #
--echo # MDEV-27361 Hybrid functions with JSON arguments do not send format metadata
--echo #
# Mix all columns in the given table tbl to each other and calculate expr.
DELIMITER $$;
CREATE PROCEDURE p1(tbl TEXT, expr TEXT)
BEGIN
DECLARE t1cols INT DEFAULT (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME=tbl AND TABLE_SCHEMA='test');
FOR a IN 0..(t1cols-1) DO
FOR b IN 0..(t1cols-1) DO
BEGIN
DECLARE query TEXT DEFAULT CONCAT('SELECT ', expr, ' FROM ', tbl);
SET query= REPLACE(query, 'olt1', a);
SET query= REPLACE(query, 'olt2', b);
EXECUTE IMMEDIATE query;
END;
END FOR;
END FOR;
END;
$$
DELIMITER ;$$
# Mix all columns in table t1 to all columns in table t2 and calculate expr
DELIMITER $$;
CREATE PROCEDURE p2(expr TEXT)
BEGIN
DECLARE t1cols INT DEFAULT (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test');
DECLARE t2cols INT DEFAULT (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME='t2' AND TABLE_SCHEMA='test');
FOR a IN 0..(t1cols-1) DO
FOR b IN 0..(t2cols-1) DO
BEGIN
DECLARE query TEXT DEFAULT CONCAT('SELECT ', expr, ' FROM t1, t2');
SET query= REPLACE(query, 'olt1', a);
SET query= REPLACE(query, 'olt2', b);
EXECUTE IMMEDIATE query;
END;
END FOR;
END FOR;
END;
$$
DELIMITER ;$$
CREATE TABLE t1
(
c0 CHAR(30) DEFAULT '1' CHECK(JSON_VALID(c0)),
c1 VARCHAR(30) DEFAULT '1' CHECK(JSON_VALID(c1)),
c2 TINYTEXT DEFAULT '1' CHECK(JSON_VALID(c2)),
c3 TEXT DEFAULT '1' CHECK(JSON_VALID(c3)),
c4 MEDIUMTEXT DEFAULT '1' CHECK(JSON_VALID(c4)),
c5 LONGTEXT DEFAULT '1' CHECK(JSON_VALID(c5)),
# The below data types do not have any special JSON properties.
# Just checking CHECK(JSON_VALID()) does not give any unexpected surprises.
c6 INT DEFAULT '1' CHECK(JSON_VALID(c6)),
c7 ENUM('1') DEFAULT '1' CHECK(JSON_VALID(c7))
);
INSERT INTO t1 VALUES ();
CREATE TABLE t1c
(
c0 CHAR(30) DEFAULT '1' CHECK(JSON_VALID(c0)),
c1 VARCHAR(30) COMPRESSED DEFAULT '1' CHECK(JSON_VALID(c1)),
c2 TINYTEXT COMPRESSED DEFAULT '1' CHECK(JSON_VALID(c2)),
c3 TEXT COMPRESSED DEFAULT '1' CHECK(JSON_VALID(c3)),
c4 MEDIUMTEXT COMPRESSED DEFAULT '1' CHECK(JSON_VALID(c4)),
c5 LONGTEXT COMPRESSED DEFAULT '1' CHECK(JSON_VALID(c5)),
# The below data types do not have any special JSON properties.
# Just checking CHECK(JSON_VALID()) does not give any unexpected surprises.
c6 INT DEFAULT '1' CHECK(JSON_VALID(c6)),
c7 ENUM('1') DEFAULT '1' CHECK(JSON_VALID(c7))
);
INSERT INTO t1c VALUES ();
CREATE TABLE t2
(
c0 CHAR(30) DEFAULT '1',
c1 VARCHAR(30) DEFAULT '1',
c2 TINYTEXT DEFAULT '1',
c3 TEXT DEFAULT '1',
c4 MEDIUMTEXT DEFAULT '1',
c5 LONGTEXT DEFAULT '1',
c6 INT DEFAULT 1,
c7 DOUBLE DEFAULT 1,
c8 DECIMAL(10,2) DEFAULT 1.23,
c9 TIME DEFAULT '10:20:30',
c10 DATE DEFAULT '2001-01-01',
c11 DATETIME DEFAULT '2001-01-01 10:20:30',
c12 ENUM('1','2') DEFAULT '1'
);
INSERT INTO t2 VALUES ();
--disable_ps_protocol
--enable_metadata
CALL p1('t1', 'COALESCE(colt1, colt2)');
CALL p1('t1', 'LEAST(colt1, colt2)');
CALL p1('t1', 'colt1+colt2');
--disable_metadata
--disable_ps_protocol
--disable_ps_protocol
--enable_metadata
CALL p1('t1c', 'COALESCE(colt1, colt2)');
CALL p1('t1c', 'LEAST(colt1, colt2)');
CALL p1('t1c', 'colt1+colt2');
--disable_metadata
--disable_ps_protocol
--disable_ps_protocol
--enable_metadata
CALL p2('COALESCE(t1.colt1, t2.colt2)');
CALL p2('LEAST(t1.colt1, t2.colt2)');
CALL p2('t1.colt1+t2.colt2');
--disable_metadata
--disable_ps_protocol
DROP PROCEDURE p1;
DROP PROCEDURE p2;
DROP TABLE t1, t1c, t2;
--echo #
--echo # End of 10.5 tests
--echo #

View File

@ -0,0 +1,42 @@
#
# MDEV-27018 IF and COALESCE lose "json" property
#
CREATE TABLE t1 (a INET6, b JSON, c LONGTEXT);
INSERT INTO t1 VALUES ('::', '{"b": "b"}', '{"c": "c"}');
SELECT
COALESCE(a,b), COALESCE(a,c),
LEAST(a,b), LEAST(a,c)
FROM t1 LIMIT 0;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def COALESCE(a,b) 254 (type=inet6) 39 0 Y 32 0 8
def COALESCE(a,c) 254 (type=inet6) 39 0 Y 32 0 8
def LEAST(a,b) 254 (type=inet6) 39 0 Y 32 0 8
def LEAST(a,c) 254 (type=inet6) 39 0 Y 32 0 8
COALESCE(a,b) COALESCE(a,c) LEAST(a,b) LEAST(a,c)
CREATE TABLE t2 AS
SELECT
COALESCE(a,b), COALESCE(a,c),
LEAST(a,b), LEAST(a,c)
FROM t1 LIMIT 0;
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`COALESCE(a,b)` inet6 DEFAULT NULL,
`COALESCE(a,c)` inet6 DEFAULT NULL,
`LEAST(a,b)` inet6 DEFAULT NULL,
`LEAST(a,c)` inet6 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t2;
SELECT * FROM t1 WHERE a=b;
a b c
Warnings:
Warning 1292 Incorrect inet6 value: '{"b": "b"}'
SELECT * FROM t1 WHERE a=c;
a b c
Warnings:
Warning 1292 Incorrect inet6 value: '{"c": "c"}'
SELECT a+b FROM t1;
ERROR HY000: Illegal parameter data types inet6 and longblob/json for operation '+'
SELECT a+c FROM t1;
ERROR HY000: Illegal parameter data types inet6 and longblob for operation '+'
DROP TABLE t1;

View File

@ -0,0 +1,50 @@
--echo #
--echo # MDEV-27018 IF and COALESCE lose "json" property
--echo #
#
# Testing that JSON data types inherit properties
# from their non-JSON counterparts when mixed to INET6.
#
# E.g. JSON acts exactly like LONGTEXT when mixed to INET6:
#
# - COALESCE(inet6,json) returns inet6 (type aggregation for result)
# - LEAST(inet6,json) returns inet6 (type aggregation for min/max)
# - inet6=json is compared as inet6 (type aggregation for comparison)
# - inet6+json returns an error (type aggregation for numeric op)
#
# Mixing INET6 and JSON is actually meaningless:
# Non of valid JSON values are valid INET6.
#
# Some queries below intentionally use LIMIT 0 to avoid errors.
#
CREATE TABLE t1 (a INET6, b JSON, c LONGTEXT);
INSERT INTO t1 VALUES ('::', '{"b": "b"}', '{"c": "c"}');
--disable_ps_protocol
--enable_metadata
SELECT
COALESCE(a,b), COALESCE(a,c),
LEAST(a,b), LEAST(a,c)
FROM t1 LIMIT 0;
--disable_metadata
--enable_ps_protocol
CREATE TABLE t2 AS
SELECT
COALESCE(a,b), COALESCE(a,c),
LEAST(a,b), LEAST(a,c)
FROM t1 LIMIT 0;
SHOW CREATE TABLE t2;
DROP TABLE t2;
SELECT * FROM t1 WHERE a=b;
SELECT * FROM t1 WHERE a=c;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT a+b FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT a+c FROM t1;
DROP TABLE t1;

View File

@ -7277,6 +7277,19 @@ bool Field_longstr::send(Protocol *protocol)
}
const Type_handler *Field_string::type_handler() const
{
if (is_var_string())
return &type_handler_var_string;
/*
This is a temporary solution and will be fixed soon (in 10.9?).
Type_handler_string_json will provide its own Field_string_json.
*/
if (Type_handler_json_common::has_json_valid_constraint(this))
return &type_handler_string_json;
return &type_handler_string;
}
/* Copy a string and fill with space */
int Field_string::store(const char *from, size_t length,CHARSET_INFO *cs)
@ -7776,6 +7789,20 @@ en_fieldtype Field_string::tmp_engine_column_type(bool use_packed_rows) const
const uint Field_varstring::MAX_SIZE= UINT_MAX16;
const Type_handler *Field_varstring::type_handler() const
{
/*
This is a temporary solution and will be fixed soon (in 10.9?).
Type_handler_varchar_json will provide its own Field_varstring_json
and Field_varstring_compressed_json
*/
if (Type_handler_json_common::has_json_valid_constraint(this))
return &type_handler_varchar_json;
return &type_handler_varchar;
}
/**
Save the field metadata for varstring fields.
@ -8897,6 +8924,15 @@ void Field_blob::sort_string(uchar *to,uint length)
*/
const Type_handler *Field_blob::type_handler() const
{
/*
This is a temporary solution and will be fixed soon (in 10.9?).
Type_handler_*blob_json will provide its own Field_blob_json
and Field_blob_compressed_json.
*/
if (Type_handler_json_common::has_json_valid_constraint(this))
return Type_handler_json_common::
json_blob_type_handler_by_length_bytes(packlength);
switch (packlength) {
case 1: return &type_handler_tiny_blob;
case 2: return &type_handler_blob;

View File

@ -4010,12 +4010,7 @@ public:
NONE, field_name_arg, collation),
can_alter_field_type(1) {};
const Type_handler *type_handler() const override
{
if (is_var_string())
return &type_handler_var_string;
return &type_handler_string;
}
const Type_handler *type_handler() const override;
enum ha_base_keytype key_type() const override
{ return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; }
en_fieldtype tmp_engine_column_type(bool use_packed_rows) const override;
@ -4134,8 +4129,7 @@ public:
share->varchar_fields++;
}
const Type_handler *type_handler() const override
{ return &type_handler_varchar; }
const Type_handler *type_handler() const override;
en_fieldtype tmp_engine_column_type(bool use_packed_rows) const override
{
return FIELD_VARCHAR;

View File

@ -3091,17 +3091,6 @@ Item_field::Item_field(THD *thd, Item_field *item)
}
bool Item_field::is_json_type()
{
if (!field->check_constraint ||
field->check_constraint->expr->type() != FUNC_ITEM)
return FALSE;
Item_func *f= (Item_func *) field->check_constraint->expr;
return f->functype() == Item_func::JSON_VALID_FUNC;
}
void Item_field::set_field(Field *field_par)
{
field=result_field=field_par; // for easy coding with fields

View File

@ -1868,7 +1868,6 @@ public:
table during query processing (grouping and so on)
*/
virtual bool is_result_field() { return 0; }
virtual bool is_json_type() { return false; }
virtual bool is_bool_literal() const { return false; }
/* This is to handle printing of default values */
virtual bool need_parentheses_in_default() { return false; }
@ -3427,7 +3426,6 @@ public:
my_decimal *val_decimal_result(my_decimal *) override;
bool val_bool_result() override;
bool is_null_result() override;
bool is_json_type() override;
bool send(Protocol *protocol, st_value *buffer) override;
Load_data_outvar *get_load_data_outvar() override { return this; }
bool load_data_set_null(THD *thd, const Load_data_param *param) override
@ -5463,7 +5461,6 @@ public:
{
return ref ? (*ref)->get_typelib() : NULL;
}
bool is_json_type() override { return (*ref)->is_json_type(); }
bool walk(Item_processor processor, bool walk_subquery, void *arg) override
{

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2016, 2020, MariaDB Corporation.
/* Copyright (c) 2016, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -1441,6 +1441,32 @@ null_return:
}
/*
This reproduces behavior according to the former
Item_func_conv_charset::is_json_type() which returned args[0]->is_json_type().
JSON functions with multiple string input with different character sets
wrap some arguments into Item_func_conv_charset. So the former
Item_func_conv_charset::is_json_type() took the JSON propery from args[0],
i.e. from the original argument before the conversion.
This is probably not always correct because an *explicit*
`CONVERT(arg USING charset)` is actually a general purpose string
expression, not a JSON expression.
*/
static bool is_json_type(const Item *item)
{
for ( ; ; )
{
if (Type_handler_json_common::is_json_type_handler(item->type_handler()))
return true;
const Item_func_conv_charset *func;
if (!(func= dynamic_cast<const Item_func_conv_charset*>(item)))
return false;
item= func->arguments()[0];
}
return false;
}
static int append_json_value(String *str, Item *item, String *tmp_val)
{
if (item->type_handler()->is_bool_type())
@ -1469,7 +1495,7 @@ static int append_json_value(String *str, Item *item, String *tmp_val)
String *sv= item->val_json(tmp_val);
if (item->null_value)
goto append_null;
if (item->is_json_type())
if (is_json_type(item))
return str->append(sv->ptr(), sv->length());
if (item->result_type() == STRING_RESULT)
@ -1515,7 +1541,7 @@ static int append_json_value_from_field(String *str,
String *sv= f->val_str(tmp_val, key + offset);
if (f->is_null_in_record(key))
goto append_null;
if (i->is_json_type())
if (is_json_type(i))
return str->append(sv->ptr(), sv->length());
if (i->result_type() == STRING_RESULT)

View File

@ -24,7 +24,7 @@
#include "item_cmpfunc.h" // Item_bool_func
#include "item_strfunc.h" // Item_str_func
#include "item_sum.h"
#include "sql_type_json.h"
class json_path_with_flags
{
@ -123,12 +123,9 @@ public:
:Item_str_func(thd, a, b) { }
Item_json_func(THD *thd, List<Item> &list)
:Item_str_func(thd, list) { }
bool is_json_type() override { return true; }
void make_send_field(THD *thd, Send_field *tmp_field) override
const Type_handler *type_handler() const override
{
Item_str_func::make_send_field(thd, tmp_field);
static const Lex_cstring fmt(STRING_WITH_LEN("json"));
tmp_field->set_format_name(fmt);
return Type_handler_json_common::json_type_handler(max_length);
}
};
@ -562,7 +559,10 @@ public:
}
Item_func_json_arrayagg(THD *thd, Item_func_json_arrayagg *item) :
Item_func_group_concat(thd, item) {}
bool is_json_type() override { return true; }
const Type_handler *type_handler() const override
{
return Type_handler_json_common::json_type_handler_sum(this);
}
const char *func_name() const override { return "json_arrayagg("; }
enum Sumfunctype sum_func() const override { return JSON_ARRAYAGG_FUNC; }
@ -587,16 +587,13 @@ public:
}
Item_func_json_objectagg(THD *thd, Item_func_json_objectagg *item);
bool is_json_type() override { return true; }
void cleanup() override;
enum Sumfunctype sum_func() const override {return JSON_OBJECTAGG_FUNC;}
const char *func_name() const override { return "json_objectagg"; }
const Type_handler *type_handler() const override
{
if (too_big_for_varchar())
return &type_handler_blob;
return &type_handler_varchar;
return Type_handler_json_common::json_type_handler_sum(this);
}
void clear() override;
bool add() override;

View File

@ -3,7 +3,7 @@
/*
Copyright (c) 2000, 2011, Oracle and/or its affiliates.
Copyright (c) 2009, 2019, MariaDB
Copyright (c) 2009, 2021, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -1454,7 +1454,6 @@ public:
(cs->mbmaxlen > 1 || !(cs->state & MY_CS_NONASCII))));
}
}
bool is_json_type() { return args[0]->is_json_type(); }
String *val_str(String *);
longlong val_int()
{

View File

@ -549,6 +549,8 @@ Field_longstr::rpl_conv_type_from(const Conv_source &source,
binlog_type() == MYSQL_TYPE_VARCHAR_COMPRESSED ||
binlog_type() == MYSQL_TYPE_BLOB_COMPRESSED)
same_type= binlog_type() == source.real_field_type();
else if (Type_handler_json_common::is_json_type_handler(type_handler()))
same_type= type_handler()->type_handler_base() == source.type_handler();
else
same_type= type_handler() == source.type_handler();

View File

@ -1,5 +1,5 @@
/*
Copyright (c) 2015, 2020, MariaDB
Copyright (c) 2015, 2021, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -1758,16 +1758,21 @@ const Type_handler *Type_handler_typelib::cast_to_int_type_handler() const
bool
Type_handler_hybrid_field_type::aggregate_for_result(const Type_handler *other)
{
const Type_handler *hres;
const Type_collection *c;
if (!(c= Type_handler::type_collection_for_aggregation(m_type_handler, other)) ||
!(hres= c->aggregate_for_result(m_type_handler, other)))
hres= type_handler_data->
m_type_aggregator_for_result.find_handler(m_type_handler, other);
if (!hres)
return true;
m_type_handler= hres;
return false;
Type_handler_pair tp(m_type_handler, other);
do
{
const Type_handler *hres;
const Type_collection *c;
if (((c= Type_handler::type_collection_for_aggregation(tp.a(), tp.b())) &&
(hres= c->aggregate_for_result(tp.a(), tp.b()))) ||
(hres= type_handler_data->
m_type_aggregator_for_result.find_handler(tp.a(), tp.b())))
{
m_type_handler= hres;
return false;
}
} while (tp.to_base());
return true;
}
@ -1971,26 +1976,29 @@ Type_collection_std::aggregate_for_comparison(const Type_handler *ha,
bool
Type_handler_hybrid_field_type::aggregate_for_min_max(const Type_handler *h)
{
const Type_handler *hres;
const Type_collection *c;
if (!(c= Type_handler::type_collection_for_aggregation(m_type_handler, h))||
!(hres= c->aggregate_for_min_max(m_type_handler, h)))
Type_handler_pair tp(m_type_handler, h);
do
{
/*
For now we suppose that these two expressions:
- LEAST(type1, type2)
- COALESCE(type1, type2)
return the same data type (or both expressions return error)
if type1 and/or type2 are non-traditional.
This may change in the future.
*/
hres= type_handler_data->
m_type_aggregator_for_result.find_handler(m_type_handler, h);
}
if (!hres)
return true;
m_type_handler= hres;
return false;
const Type_handler *hres;
const Type_collection *c;
if (((c= Type_handler::type_collection_for_aggregation(tp.a(), tp.b())) &&
(hres= c->aggregate_for_min_max(tp.a(), tp.b()))) ||
(hres= type_handler_data->
m_type_aggregator_for_result.find_handler(tp.a(), tp.b())))
{
/*
For now we suppose that these two expressions:
- LEAST(type1, type2)
- COALESCE(type1, type2)
return the same data type (or both expressions return error)
if type1 and/or type2 are non-traditional.
This may change in the future.
*/
m_type_handler= hres;
return false;
}
} while (tp.to_base());
return true;
}
@ -2129,15 +2137,20 @@ Type_handler_hybrid_field_type::aggregate_for_num_op(const Type_aggregator *agg,
const Type_handler *h0,
const Type_handler *h1)
{
const Type_handler *hres;
const Type_collection *c;
if (!(c= Type_handler::type_collection_for_aggregation(h0, h1)) ||
!(hres= c->aggregate_for_num_op(h0, h1)))
hres= agg->find_handler(h0, h1);
if (!hres)
return true;
m_type_handler= hres;
return false;
Type_handler_pair tp(h0, h1);
do
{
const Type_handler *hres;
const Type_collection *c;
if (((c= Type_handler::type_collection_for_aggregation(tp.a(), tp.b())) &&
(hres= c->aggregate_for_num_op(tp.a(), tp.b()))) ||
(hres= agg->find_handler(tp.a(), tp.b())))
{
m_type_handler= hres;
return false;
}
} while (tp.to_base());
return true;
}

View File

@ -2,7 +2,7 @@
#define SQL_TYPE_H_INCLUDED
/*
Copyright (c) 2015 MariaDB Foundation.
Copyright (c) 2015, 2020, MariaDB Corporation.
Copyright (c) 2015, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -45,6 +45,7 @@ class Item_param;
class Item_cache;
class Item_copy;
class Item_func_or_sum;
class Item_sum;
class Item_sum_hybrid;
class Item_sum_sum;
class Item_sum_avg;
@ -3764,6 +3765,14 @@ public:
incompatible data type.
*/
virtual bool is_param_long_data_type() const { return false; }
/*
The base type handler "this" is derived from.
"This" inherits aggregation rules from the base type handler.
*/
virtual const Type_handler *type_handler_base() const
{
return NULL;
}
virtual const Type_handler *type_handler_for_comparison() const= 0;
virtual const Type_handler *type_handler_for_native_format() const
{
@ -7471,6 +7480,41 @@ public:
const Type_handler *h0, const Type_handler *h1);
};
class Type_handler_pair
{
const Type_handler *m_a;
const Type_handler *m_b;
public:
Type_handler_pair(const Type_handler *a,
const Type_handler *b)
:m_a(a), m_b(b)
{ }
const Type_handler *a() const { return m_a; }
const Type_handler *b() const { return m_b; }
/*
Change both handlers to their parent data type handlers, if available.
For example, VARCHAR/JSON -> VARCHAR.
@returns The number of handlers changed (0,1 or 2).
*/
bool to_base()
{
bool rc= false;
const Type_handler *na= m_a->type_handler_base();
const Type_handler *nb= m_b->type_handler_base();
if (na)
{
m_a= na; rc= true;
}
if (nb)
{
m_b= nb; rc= true;
}
return rc;
}
};
/*
Helper template to simplify creating builtin types with names.
Plugin types inherit from Type_handler_xxx types that do not set the name in

View File

@ -1,5 +1,5 @@
/*
Copyright (c) 2019, MariaDB
Copyright (c) 2019, 2021 MariaDB
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -20,17 +20,111 @@
#include "sql_class.h"
Type_handler_json_longtext type_handler_json_longtext;
Named_type_handler<Type_handler_string_json>
type_handler_string_json("char/json");
Named_type_handler<Type_handler_varchar_json>
type_handler_varchar_json("varchar/json");
Named_type_handler<Type_handler_tiny_blob_json>
type_handler_tiny_blob_json("tinyblob/json");
Named_type_handler<Type_handler_blob_json>
type_handler_blob_json("blob/json");
Named_type_handler<Type_handler_medium_blob_json>
type_handler_medium_blob_json("mediumblob/json");
Named_type_handler<Type_handler_long_blob_json>
type_handler_long_blob_json("longblob/json");
// Convert general purpose string type handlers to their JSON counterparts
const Type_handler *
Type_handler_json_common::json_type_handler_from_generic(const Type_handler *th)
{
// Test in the order of likelyhood.
if (th == &type_handler_long_blob)
return &type_handler_long_blob_json;
if (th == &type_handler_varchar)
return &type_handler_varchar_json;
if (th == &type_handler_blob)
return &type_handler_blob_json;
if (th == &type_handler_tiny_blob)
return &type_handler_tiny_blob_json;
if (th == &type_handler_medium_blob)
return &type_handler_medium_blob_json;
if (th == &type_handler_string)
return &type_handler_string_json;
DBUG_ASSERT(is_json_type_handler(th));
return th;
}
/*
This method resembles what Type_handler::string_type_handler()
does for general purpose string type handlers.
*/
const Type_handler *
Type_handler_json_common::json_type_handler(uint max_octet_length)
{
if (max_octet_length >= 16777216)
return &type_handler_long_blob_json;
else if (max_octet_length >= 65536)
return &type_handler_medium_blob_json;
else if (max_octet_length >= MAX_FIELD_VARCHARLENGTH)
return &type_handler_blob_json;
return &type_handler_varchar_json;
}
/*
This method resembles what Field_blob::type_handler()
does for general purpose BLOB type handlers.
*/
const Type_handler *
Type_handler_json_common::json_blob_type_handler_by_length_bytes(uint len)
{
switch (len) {
case 1: return &type_handler_tiny_blob_json;
case 2: return &type_handler_blob_json;
case 3: return &type_handler_medium_blob_json;
}
return &type_handler_long_blob_json;
}
/*
This method resembles what Item_sum_group_concat::type_handler()
does for general purpose string type handlers.
*/
const Type_handler *
Type_handler_json_common::json_type_handler_sum(const Item_sum *item)
{
if (item->too_big_for_varchar())
return &type_handler_blob_json;
return &type_handler_varchar_json;
}
bool Type_handler_json_common::has_json_valid_constraint(const Field *field)
{
return field->check_constraint &&
field->check_constraint->expr &&
field->check_constraint->expr->type() == Item::FUNC_ITEM &&
static_cast<const Item_func *>(field->check_constraint->expr)->
functype() == Item_func::JSON_VALID_FUNC;
}
/**
Create JSON_VALID(field_name) expression
*/
Virtual_column_info *
Type_handler_json_longtext::make_json_valid_expr(THD *thd,
const LEX_CSTRING *field_name)
const
Type_handler_json_common::make_json_valid_expr(THD *thd,
const LEX_CSTRING *field_name)
{
Lex_ident_sys_st str;
Item *field, *expr;
@ -46,12 +140,118 @@ Type_handler_json_longtext::make_json_valid_expr(THD *thd,
}
bool Type_handler_json_longtext::
Column_definition_validate_check_constraint(THD *thd,
Column_definition * c) const
bool Type_handler_json_common::make_json_valid_expr_if_needed(THD *thd,
Column_definition *c)
{
if (!c->check_constraint &&
!(c->check_constraint= make_json_valid_expr(thd, &c->field_name)))
return true;
return Type_handler::Column_definition_validate_check_constraint(thd, c);
return !c->check_constraint &&
!(c->check_constraint= make_json_valid_expr(thd, &c->field_name));
}
class Type_collection_json: public Type_collection
{
const Type_handler *aggregate_common(const Type_handler *a,
const Type_handler *b) const
{
if (a == b)
return a;
if (a == &type_handler_null)
return b;
if (b == &type_handler_null)
return a;
return NULL;
}
/*
Aggregate two JSON type handlers for result.
If one of the handlers is not JSON, NULL is returned.
*/
const Type_handler *aggregate_json_for_result(const Type_handler *a,
const Type_handler *b) const
{
if (!Type_handler_json_common::is_json_type_handler(a) ||
!Type_handler_json_common::is_json_type_handler(b))
return NULL;
// Here we have two JSON data types. Let's aggregate their base types.
const Type_handler *a0= a->type_handler_base();
const Type_handler *b0= b->type_handler_base();
// Base types are expected to belong to type_collection_std:
DBUG_ASSERT(a0->type_collection() == type_handler_null.type_collection());
DBUG_ASSERT(b0->type_collection() == type_handler_null.type_collection());
const Type_handler *c= a0->type_collection()->aggregate_for_result(a0, b0);
return Type_handler_json_common::json_type_handler_from_generic(c);
}
public:
const Type_handler *aggregate_for_result(const Type_handler *a,
const Type_handler *b)
const override
{
const Type_handler *h;
if ((h= aggregate_common(a, b)) ||
(h= aggregate_json_for_result(a, b)))
return h;
/*
One of the types is not JSON.
Let the caller aggregate according to the derived rules:
COALESCE(VARCHAR/JSON, TEXT) -> COALESCE(VARCHAR, TEXT)
*/
return NULL;
}
const Type_handler *aggregate_for_min_max(const Type_handler *a,
const Type_handler *b)
const override
{
/*
No JSON specific rules.
Let the caller aggregate according to the derived rules:
LEAST(VARCHAR/JSON, TEXT/JSON) -> LEAST(VARCHAR, TEXT)
*/
return NULL;
}
const Type_handler *aggregate_for_comparison(const Type_handler *a,
const Type_handler *b)
const override
{
/*
All JSON types return &type_handler_long_blob
in type_handler_for_comparison(). We should not get here.
*/
DBUG_ASSERT(0);
return NULL;
}
const Type_handler *aggregate_for_num_op(const Type_handler *a,
const Type_handler *b)
const override
{
/*
No JSON specific rules.
Let the caller aggregate according to the derived rules:
(VARCHAR/JSON + TEXT/JSON) -> (VARCHAR + TEXT)
*/
return NULL;
}
const Type_handler *handler_by_name(const LEX_CSTRING &name) const override
{
/*
Name resolution is not needed yet.
JSON is not fully pluggable at the moment:
- It is parsed using a hard-coded rule in sql_yacc.yy
- It does not store extended data type information into
FRM file yet. JSON is detected by CHECK(JSON_VALID(col))
and this detection is also hard-coded.
This will change in the future.
*/
return NULL;
}
};
const Type_collection *Type_handler_json_common::type_collection()
{
static Type_collection_json type_collection_json;
return &type_collection_json;
}

View File

@ -1,7 +1,7 @@
#ifndef SQL_TYPE_JSON_INCLUDED
#define SQL_TYPE_JSON_INCLUDED
/*
Copyright (c) 2019, MariaDB
Copyright (c) 2019, 2021 MariaDB
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -21,18 +21,145 @@
#include "mariadb.h"
#include "sql_type.h"
class Type_handler_json_longtext: public Type_handler_long_blob
class Type_handler_json_common
{
Virtual_column_info *make_json_valid_expr(THD *thd,
const LEX_CSTRING *field_name)
const;
public:
virtual ~Type_handler_json_longtext() {}
bool Column_definition_validate_check_constraint(THD *thd,
Column_definition *c) const;
static Virtual_column_info *make_json_valid_expr(THD *thd,
const LEX_CSTRING *field_name);
static bool make_json_valid_expr_if_needed(THD *thd, Column_definition *c);
static bool set_format_name(Send_field_extended_metadata *to)
{
static const Lex_cstring fmt(STRING_WITH_LEN("json"));
return to->set_format_name(fmt);
}
static const Type_handler *json_type_handler(uint max_octet_length);
static const Type_handler *json_blob_type_handler_by_length_bytes(uint len);
static const Type_handler *json_type_handler_sum(const Item_sum *sum);
static const Type_handler *json_type_handler_from_generic(const Type_handler *th);
static bool has_json_valid_constraint(const Field *field);
static const Type_collection *type_collection();
static bool is_json_type_handler(const Type_handler *handler)
{
return handler->type_collection() == type_collection();
}
};
template <class BASE, const Named_type_handler<BASE> &thbase>
class Type_handler_general_purpose_string_to_json:
public BASE,
public Type_handler_json_common
{
public:
const Type_handler *type_handler_base() const override
{
return &thbase;
}
const Type_collection *type_collection() const override
{
return Type_handler_json_common::type_collection();
}
bool Column_definition_validate_check_constraint(THD *thd,
Column_definition *c)
const override
{
return make_json_valid_expr_if_needed(thd, c) ||
BASE::Column_definition_validate_check_constraint(thd, c);
}
bool Column_definition_data_type_info_image(Binary_string *to,
const Column_definition &def)
const override
{
/*
Override the inherited method to avoid JSON type handlers writing any
extended metadata to FRM. JSON type handlers are currently detected
only by CHECK(JSON_VALID()) constraint. This may change in the future
to do write extended metadata to FRM, for more reliable detection.
*/
return false;
}
bool Item_append_extended_type_info(Send_field_extended_metadata *to,
const Item *item) const
{
return set_format_name(to); // Send "format=json" in the protocol
}
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *hybrid,
Type_all_attributes *attr,
Item **items, uint nitems)
const override
{
if (BASE::Item_hybrid_func_fix_attributes(thd, name, hybrid, attr,
items, nitems))
return true;
/*
The above call can change the type handler on "hybrid", e.g.
choose a proper BLOB type handler according to the calculated max_length.
Convert general purpose string type handler to its JSON counterpart.
This makes hybrid functions preserve JSON data types, e.g.:
COALESCE(json_expr1, json_expr2) -> JSON
*/
hybrid->set_handler(json_type_handler_from_generic(hybrid->type_handler()));
return false;
}
};
class Type_handler_string_json:
public Type_handler_general_purpose_string_to_json<Type_handler_string,
type_handler_string>
{ };
class Type_handler_varchar_json:
public Type_handler_general_purpose_string_to_json<Type_handler_varchar,
type_handler_varchar>
{ };
class Type_handler_tiny_blob_json:
public Type_handler_general_purpose_string_to_json<Type_handler_tiny_blob,
type_handler_tiny_blob>
{ };
class Type_handler_blob_json:
public Type_handler_general_purpose_string_to_json<Type_handler_blob,
type_handler_blob>
{ };
class Type_handler_medium_blob_json:
public Type_handler_general_purpose_string_to_json<Type_handler_medium_blob,
type_handler_medium_blob>
{ };
class Type_handler_long_blob_json:
public Type_handler_general_purpose_string_to_json<Type_handler_long_blob,
type_handler_long_blob>
{ };
extern MYSQL_PLUGIN_IMPORT
Type_handler_json_longtext type_handler_json_longtext;
Named_type_handler<Type_handler_string_json> type_handler_string_json;
extern MYSQL_PLUGIN_IMPORT
Named_type_handler<Type_handler_varchar_json> type_handler_varchar_json;
extern MYSQL_PLUGIN_IMPORT
Named_type_handler<Type_handler_tiny_blob_json> type_handler_tiny_blob_json;
extern MYSQL_PLUGIN_IMPORT
Named_type_handler<Type_handler_blob_json> type_handler_blob_json;
extern MYSQL_PLUGIN_IMPORT
Named_type_handler<Type_handler_medium_blob_json> type_handler_medium_blob_json;
extern MYSQL_PLUGIN_IMPORT
Named_type_handler<Type_handler_long_blob_json> type_handler_long_blob_json;
#endif // SQL_TYPE_JSON_INCLUDED

View File

@ -6431,7 +6431,7 @@ field_type_lob:
| JSON_SYM opt_compressed
{
Lex->charset= &my_charset_utf8mb4_bin;
$$.set(&type_handler_json_longtext);
$$.set(&type_handler_long_blob_json);
}
;