1 #ifndef SQL_TYPE_JSON_INCLUDED
2 #define SQL_TYPE_JSON_INCLUDED
3 /*
4    Copyright (c) 2019, 2021 MariaDB
5 
6    This program is free software; you can redistribute it and/or
7    modify it under the terms of the GNU General Public License
8    as published by the Free Software Foundation; version 2 of
9    the License.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
19 */
20 
21 #include "mariadb.h"
22 #include "sql_type.h"
23 
24 
25 class Type_handler_json_common
26 {
27 public:
28   static Virtual_column_info *make_json_valid_expr(THD *thd,
29                                             const LEX_CSTRING *field_name);
30   static bool make_json_valid_expr_if_needed(THD *thd, Column_definition *c);
set_format_name(Send_field_extended_metadata * to)31   static bool set_format_name(Send_field_extended_metadata *to)
32   {
33     static const Lex_cstring fmt(STRING_WITH_LEN("json"));
34     return to->set_format_name(fmt);
35   }
36   static const Type_handler *json_type_handler(uint max_octet_length);
37   static const Type_handler *json_blob_type_handler_by_length_bytes(uint len);
38   static const Type_handler *json_type_handler_sum(const Item_sum *sum);
39   static const Type_handler *json_type_handler_from_generic(const Type_handler *th);
40   static bool has_json_valid_constraint(const Field *field);
41   static const Type_collection *type_collection();
is_json_type_handler(const Type_handler * handler)42   static bool is_json_type_handler(const Type_handler *handler)
43   {
44     return handler->type_collection() == type_collection();
45   }
46 };
47 
48 
49 template <class BASE, const Named_type_handler<BASE> &thbase>
50 class Type_handler_general_purpose_string_to_json:
51                                             public BASE,
52                                             public Type_handler_json_common
53 {
54 public:
type_handler_base()55   const Type_handler *type_handler_base() const override
56   {
57     return &thbase;
58   }
type_collection()59   const Type_collection *type_collection() const override
60   {
61     return Type_handler_json_common::type_collection();
62   }
Column_definition_validate_check_constraint(THD * thd,Column_definition * c)63   bool Column_definition_validate_check_constraint(THD *thd,
64                                                    Column_definition *c)
65                                                    const override
66   {
67     return make_json_valid_expr_if_needed(thd, c) ||
68            BASE::Column_definition_validate_check_constraint(thd, c);
69   }
Column_definition_data_type_info_image(Binary_string * to,const Column_definition & def)70   bool Column_definition_data_type_info_image(Binary_string *to,
71                                               const Column_definition &def)
72                                               const override
73   {
74     /*
75       Override the inherited method to avoid JSON type handlers writing any
76       extended metadata to FRM. JSON type handlers are currently detected
77       only by CHECK(JSON_VALID()) constraint. This may change in the future
78       to do write extended metadata to FRM, for more reliable detection.
79     */
80     return false;
81   }
82 
Item_append_extended_type_info(Send_field_extended_metadata * to,const Item * item)83   bool Item_append_extended_type_info(Send_field_extended_metadata *to,
84                                       const Item *item) const override
85   {
86     return set_format_name(to); // Send "format=json" in the protocol
87   }
88 
Item_hybrid_func_fix_attributes(THD * thd,const char * name,Type_handler_hybrid_field_type * hybrid,Type_all_attributes * attr,Item ** items,uint nitems)89   bool Item_hybrid_func_fix_attributes(THD *thd,
90                                        const char *name,
91                                        Type_handler_hybrid_field_type *hybrid,
92                                        Type_all_attributes *attr,
93                                        Item **items, uint nitems)
94                                        const override
95   {
96     if (BASE::Item_hybrid_func_fix_attributes(thd, name, hybrid, attr,
97                                               items, nitems))
98       return true;
99     /*
100       The above call can change the type handler on "hybrid", e.g.
101       choose a proper BLOB type handler according to the calculated max_length.
102       Convert general purpose string type handler to its JSON counterpart.
103       This makes hybrid functions preserve JSON data types, e.g.:
104         COALESCE(json_expr1, json_expr2) -> JSON
105     */
106     hybrid->set_handler(json_type_handler_from_generic(hybrid->type_handler()));
107     return false;
108   }
109 };
110 
111 
112 class Type_handler_string_json:
113   public Type_handler_general_purpose_string_to_json<Type_handler_string,
114                                                      type_handler_string>
115 { };
116 
117 
118 class Type_handler_varchar_json:
119   public Type_handler_general_purpose_string_to_json<Type_handler_varchar,
120                                                      type_handler_varchar>
121 { };
122 
123 class Type_handler_tiny_blob_json:
124   public Type_handler_general_purpose_string_to_json<Type_handler_tiny_blob,
125                                                      type_handler_tiny_blob>
126 { };
127 
128 class Type_handler_blob_json:
129   public Type_handler_general_purpose_string_to_json<Type_handler_blob,
130                                                      type_handler_blob>
131 { };
132 
133 
134 class Type_handler_medium_blob_json:
135   public Type_handler_general_purpose_string_to_json<Type_handler_medium_blob,
136                                                      type_handler_medium_blob>
137 { };
138 
139 class Type_handler_long_blob_json:
140   public Type_handler_general_purpose_string_to_json<Type_handler_long_blob,
141                                                      type_handler_long_blob>
142 { };
143 
144 
145 
146 extern MYSQL_PLUGIN_IMPORT
147   Named_type_handler<Type_handler_string_json> type_handler_string_json;
148 
149 extern MYSQL_PLUGIN_IMPORT
150   Named_type_handler<Type_handler_varchar_json> type_handler_varchar_json;
151 
152 extern MYSQL_PLUGIN_IMPORT
153   Named_type_handler<Type_handler_tiny_blob_json> type_handler_tiny_blob_json;
154 
155 extern MYSQL_PLUGIN_IMPORT
156   Named_type_handler<Type_handler_blob_json> type_handler_blob_json;
157 
158 extern MYSQL_PLUGIN_IMPORT
159   Named_type_handler<Type_handler_medium_blob_json> type_handler_medium_blob_json;
160 
161 extern MYSQL_PLUGIN_IMPORT
162   Named_type_handler<Type_handler_long_blob_json> type_handler_long_blob_json;
163 
164 
165 #endif // SQL_TYPE_JSON_INCLUDED
166