1 /* Copyright (c) 2008, 2021, Oracle and/or its affiliates.
2 
3   This program is free software; you can redistribute it and/or modify
4   it under the terms of the GNU General Public License, version 2.0,
5   as published by the Free Software Foundation.
6 
7   This program is also distributed with certain software (including
8   but not limited to OpenSSL) that is licensed under separate terms,
9   as designated in a particular file or component or in included license
10   documentation.  The authors of MySQL hereby grant you an additional
11   permission to link the program and your derivative works with the
12   separately licensed software that they have included with MySQL.
13 
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License, version 2.0, for more details.
18 
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software Foundation,
21   51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22 
23 /**
24   @file storage/perfschema/table_setup_objects.cc
25   Table SETUP_OBJECTS (implementation).
26 */
27 
28 #include "my_global.h"
29 #include "my_thread.h"
30 #include "pfs_instr.h"
31 #include "pfs_column_types.h"
32 #include "pfs_column_values.h"
33 #include "pfs_setup_object.h"
34 #include "table_setup_objects.h"
35 #include "table_helper.h"
36 #include "pfs_global.h"
37 #include "pfs_buffer_container.h"
38 #include "field.h"
39 
40 THR_LOCK table_setup_objects::m_table_lock;
41 
42 static const TABLE_FIELD_TYPE field_types[]=
43 {
44   {
45     { C_STRING_WITH_LEN("OBJECT_TYPE") },
46     { C_STRING_WITH_LEN("enum(\'EVENT\',\'FUNCTION\',\'PROCEDURE\',\'TABLE\',\'TRIGGER\'") },
47     { NULL, 0}
48   },
49   {
50     { C_STRING_WITH_LEN("OBJECT_SCHEMA") },
51     { C_STRING_WITH_LEN("varchar(64)") },
52     { NULL, 0}
53   },
54   {
55     { C_STRING_WITH_LEN("OBJECT_NAME") },
56     { C_STRING_WITH_LEN("varchar(64)") },
57     { NULL, 0}
58   },
59   {
60     { C_STRING_WITH_LEN("ENABLED") },
61     { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") },
62     { NULL, 0}
63   },
64   {
65     { C_STRING_WITH_LEN("TIMED") },
66     { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") },
67     { NULL, 0}
68   }
69 };
70 
71 TABLE_FIELD_DEF
72 table_setup_objects::m_field_def=
73 { 5, field_types };
74 
75 PFS_engine_table_share
76 table_setup_objects::m_share=
77 {
78   { C_STRING_WITH_LEN("setup_objects") },
79   &pfs_editable_acl,
80   table_setup_objects::create,
81   table_setup_objects::write_row,
82   table_setup_objects::delete_all_rows,
83   table_setup_objects::get_row_count,
84   sizeof(PFS_simple_index),
85   &m_table_lock,
86   &m_field_def,
87   false, /* checked */
88   false  /* perpetual */
89 };
90 
update_derived_flags()91 int update_derived_flags()
92 {
93   PFS_thread *thread= PFS_thread::get_current_thread();
94   if (unlikely(thread == NULL))
95     return HA_ERR_OUT_OF_MEM;
96 
97   update_table_share_derived_flags(thread);
98   update_program_share_derived_flags(thread);
99   update_table_derived_flags();
100   return 0;
101 }
102 
create(void)103 PFS_engine_table* table_setup_objects::create(void)
104 {
105   return new table_setup_objects();
106 }
107 
write_row(TABLE * table,unsigned char * buf,Field ** fields)108 int table_setup_objects::write_row(TABLE *table, unsigned char *buf,
109                                    Field **fields)
110 {
111   int result;
112   Field *f;
113   enum_object_type object_type= OBJECT_TYPE_TABLE;
114   String object_schema_data("%", 1, &my_charset_utf8_bin);
115   String object_name_data("%", 1, &my_charset_utf8_bin);
116   String *object_schema= &object_schema_data;
117   String *object_name= &object_name_data;
118   enum_yes_no enabled_value= ENUM_YES;
119   enum_yes_no timed_value= ENUM_YES;
120   bool enabled= true;
121   bool timed= true;
122 
123   for (; (f= *fields) ; fields++)
124   {
125     if (bitmap_is_set(table->write_set, f->field_index))
126     {
127       switch(f->field_index)
128       {
129       case 0: /* OBJECT_TYPE */
130         object_type= (enum_object_type) get_field_enum(f);
131         break;
132       case 1: /* OBJECT_SCHEMA */
133         object_schema= get_field_varchar_utf8(f, &object_schema_data);
134         break;
135       case 2: /* OBJECT_NAME */
136         object_name= get_field_varchar_utf8(f, &object_name_data);
137         break;
138       case 3: /* ENABLED */
139         enabled_value= (enum_yes_no) get_field_enum(f);
140         break;
141       case 4: /* TIMED */
142         timed_value= (enum_yes_no) get_field_enum(f);
143         break;
144       default:
145         assert(false);
146       }
147     }
148   }
149 
150   /* Reject illegal enum values in OBJECT_TYPE */
151   if (object_type < FIRST_OBJECT_TYPE ||
152       object_type > LAST_OBJECT_TYPE  ||
153       object_type == OBJECT_TYPE_TEMPORARY_TABLE)
154     return HA_ERR_NO_REFERENCED_ROW;
155 
156   /* Reject illegal enum values in ENABLED */
157   if ((enabled_value != ENUM_YES) && (enabled_value != ENUM_NO))
158     return HA_ERR_NO_REFERENCED_ROW;
159 
160   /* Reject illegal enum values in TIMED */
161   if ((timed_value != ENUM_YES) && (timed_value != ENUM_NO))
162     return HA_ERR_NO_REFERENCED_ROW;
163 
164   enabled= (enabled_value == ENUM_YES) ? true : false;
165   timed= (timed_value == ENUM_YES) ? true : false;
166 
167   result= insert_setup_object(object_type, object_schema, object_name,
168                               enabled, timed);
169   if (result == 0)
170     result= update_derived_flags();
171   return result;
172 }
173 
delete_all_rows(void)174 int table_setup_objects::delete_all_rows(void)
175 {
176   int result= reset_setup_object();
177   if (result == 0)
178     result= update_derived_flags();
179   return result;
180 }
181 
get_row_count(void)182 ha_rows table_setup_objects::get_row_count(void)
183 {
184   return global_setup_object_container.get_row_count();
185 }
186 
table_setup_objects()187 table_setup_objects::table_setup_objects()
188   : PFS_engine_table(&m_share, &m_pos),
189   m_row_exists(false), m_pos(0), m_next_pos(0)
190 {}
191 
reset_position(void)192 void table_setup_objects::reset_position(void)
193 {
194   m_pos.m_index= 0;
195   m_next_pos.m_index= 0;
196 }
197 
rnd_next(void)198 int table_setup_objects::rnd_next(void)
199 {
200   PFS_setup_object *pfs;
201 
202   m_pos.set_at(&m_next_pos);
203   PFS_setup_object_iterator it= global_setup_object_container.iterate(m_pos.m_index);
204   pfs= it.scan_next(& m_pos.m_index);
205   if (pfs != NULL)
206   {
207     make_row(pfs);
208     m_next_pos.set_after(&m_pos);
209     return 0;
210   }
211 
212   return HA_ERR_END_OF_FILE;
213 }
214 
rnd_pos(const void * pos)215 int table_setup_objects::rnd_pos(const void *pos)
216 {
217   PFS_setup_object *pfs;
218 
219   set_position(pos);
220 
221   pfs= global_setup_object_container.get(m_pos.m_index);
222   if (pfs != NULL)
223   {
224     make_row(pfs);
225     return 0;
226   }
227 
228   return HA_ERR_RECORD_DELETED;
229 }
230 
make_row(PFS_setup_object * pfs)231 void table_setup_objects::make_row(PFS_setup_object *pfs)
232 {
233   pfs_optimistic_state lock;
234 
235   m_row_exists= false;
236 
237   pfs->m_lock.begin_optimistic_lock(&lock);
238 
239   m_row.m_object_type= pfs->get_object_type();
240   memcpy(m_row.m_schema_name, pfs->m_schema_name, pfs->m_schema_name_length);
241   m_row.m_schema_name_length= pfs->m_schema_name_length;
242   memcpy(m_row.m_object_name, pfs->m_object_name, pfs->m_object_name_length);
243   m_row.m_object_name_length= pfs->m_object_name_length;
244   m_row.m_enabled_ptr= &pfs->m_enabled;
245   m_row.m_timed_ptr= &pfs->m_timed;
246 
247   if (pfs->m_lock.end_optimistic_lock(&lock))
248     m_row_exists= true;
249 }
250 
read_row_values(TABLE * table,unsigned char * buf,Field ** fields,bool read_all)251 int table_setup_objects::read_row_values(TABLE *table,
252                                          unsigned char *buf,
253                                          Field **fields,
254                                          bool read_all)
255 {
256   Field *f;
257 
258   if (unlikely(! m_row_exists))
259     return HA_ERR_RECORD_DELETED;
260 
261   /* Set the null bits */
262   assert(table->s->null_bytes == 1);
263   buf[0]= 0;
264 
265   for (; (f= *fields) ; fields++)
266   {
267     if (read_all || bitmap_is_set(table->read_set, f->field_index))
268     {
269       switch(f->field_index)
270       {
271       case 0: /* OBJECT_TYPE */
272         set_field_enum(f, m_row.m_object_type);
273         break;
274       case 1: /* OBJECT_SCHEMA */
275         if (m_row.m_schema_name_length)
276           set_field_varchar_utf8(f, m_row.m_schema_name,
277                                  m_row.m_schema_name_length);
278         else
279           f->set_null();
280         break;
281       case 2: /* OBJECT_NAME */
282         if (m_row.m_object_name_length)
283           set_field_varchar_utf8(f, m_row.m_object_name,
284                                  m_row.m_object_name_length);
285         else
286           f->set_null();
287         break;
288       case 3: /* ENABLED */
289         set_field_enum(f, (*m_row.m_enabled_ptr) ? ENUM_YES : ENUM_NO);
290         break;
291       case 4: /* TIMED */
292         set_field_enum(f, (*m_row.m_timed_ptr) ? ENUM_YES : ENUM_NO);
293         break;
294       default:
295         assert(false);
296       }
297     }
298   }
299 
300   return 0;
301 }
302 
update_row_values(TABLE * table,const unsigned char *,unsigned char *,Field ** fields)303 int table_setup_objects::update_row_values(TABLE *table,
304                                            const unsigned char *,
305                                            unsigned char *,
306                                            Field **fields)
307 {
308   int result;
309   Field *f;
310   enum_yes_no value;
311 
312   for (; (f= *fields) ; fields++)
313   {
314     if (bitmap_is_set(table->write_set, f->field_index))
315     {
316       switch(f->field_index)
317       {
318       case 0: /* OBJECT_TYPE */
319       case 1: /* OBJECT_SCHEMA */
320       case 2: /* OBJECT_NAME */
321         return HA_ERR_WRONG_COMMAND;
322       case 3: /* ENABLED */
323         value= (enum_yes_no) get_field_enum(f);
324         /* Reject illegal enum values in ENABLED */
325         if ((value != ENUM_YES) && (value != ENUM_NO))
326           return HA_ERR_NO_REFERENCED_ROW;
327         *m_row.m_enabled_ptr= (value == ENUM_YES) ? true : false;
328         break;
329       case 4: /* TIMED */
330         value= (enum_yes_no) get_field_enum(f);
331         /* Reject illegal enum values in TIMED */
332         if ((value != ENUM_YES) && (value != ENUM_NO))
333           return HA_ERR_NO_REFERENCED_ROW;
334         *m_row.m_timed_ptr= (value == ENUM_YES) ? true : false;
335         break;
336       default:
337         assert(false);
338       }
339     }
340   }
341 
342   result= update_derived_flags();
343   return result;
344 }
345 
delete_row_values(TABLE * table,const unsigned char * buf,Field ** fields)346 int table_setup_objects::delete_row_values(TABLE *table,
347                                            const unsigned char *buf,
348                                            Field **fields)
349 {
350   assert(m_row_exists);
351 
352   CHARSET_INFO *cs= &my_charset_utf8_bin;
353   enum_object_type object_type= OBJECT_TYPE_TABLE;
354   String object_schema(m_row.m_schema_name, m_row.m_schema_name_length, cs);
355   String object_name(m_row.m_object_name, m_row.m_object_name_length, cs);
356 
357   int result= delete_setup_object(object_type, &object_schema, &object_name);
358 
359   if (result == 0)
360     result= update_derived_flags();
361   return result;
362 }
363 
364