summaryrefslogtreecommitdiffstats
path: root/sql/sql_type_json.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:24:36 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:24:36 +0000
commit06eaf7232e9a920468c0f8d74dcf2fe8b555501c (patch)
treee2c7b5777f728320e5b5542b6213fd3591ba51e2 /sql/sql_type_json.cc
parentInitial commit. (diff)
downloadmariadb-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.cc243
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;
+}