diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:24:36 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:24:36 +0000 |
commit | 06eaf7232e9a920468c0f8d74dcf2fe8b555501c (patch) | |
tree | e2c7b5777f728320e5b5542b6213fd3591ba51e2 /sql/sql_type_json.cc | |
parent | Initial commit. (diff) | |
download | mariadb-06eaf7232e9a920468c0f8d74dcf2fe8b555501c.tar.xz mariadb-06eaf7232e9a920468c0f8d74dcf2fe8b555501c.zip |
Adding upstream version 1:10.11.6.upstream/1%10.11.6
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sql/sql_type_json.cc')
-rw-r--r-- | sql/sql_type_json.cc | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/sql/sql_type_json.cc b/sql/sql_type_json.cc new file mode 100644 index 00000000..27072de2 --- /dev/null +++ b/sql/sql_type_json.cc @@ -0,0 +1,243 @@ +/* + 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 + as published by the Free Software Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "sql_type_json.h" +#include "sql_class.h" + + +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_common::make_json_valid_expr(THD *thd, + const LEX_CSTRING *field_name) +{ + Lex_ident_sys_st str; + Item *field, *expr; + str.set_valid_utf8(field_name); + if (unlikely(!(field= thd->lex->create_item_ident_field(thd, + Lex_ident_sys(), + Lex_ident_sys(), + str)))) + return 0; + if (unlikely(!(expr= new (thd->mem_root) Item_func_json_valid(thd, field)))) + return 0; + return add_virtual_expression(thd, expr); +} + + +bool Type_handler_json_common::make_json_valid_expr_if_needed(THD *thd, + Column_definition *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_collection *Type_handler_json_common::type_collection() +{ + static Type_collection_json type_collection_json; + return &type_collection_json; +} |