1 /* Copyright (c) 2015, 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 rules_table_service.cc
25   Implementation of the service for accessing the rewrite rules table.
26 */
27 
28 #include <mysql/service_rules_table.h>
29 
30 #include "thr_lock.h"
31 #include "table.h"
32 #include "handler.h"
33 #include "my_base.h"
34 #include "my_bitmap.h"
35 #include "field.h"
36 #include "sql_string.h"
37 #include "transaction.h"
38 #include "sql_base.h"
39 
40 namespace rules_table_service
41 {
42 
43 int MY_ATTRIBUTE((visibility("default")))
dummy_function_to_ensure_we_are_linked_into_the_server()44 dummy_function_to_ensure_we_are_linked_into_the_server() { return 1; }
45 
46 const char *db_name= "query_rewrite";
47 const char *table_name= "rewrite_rules";
48 
read()49 int Cursor::read()
50 {
51   TABLE *table= m_table_list->table;
52   m_last_read_status= table->file->ha_rnd_next(table->record[0]);
53   if (m_last_read_status != 0)
54     m_is_finished= true;
55   return m_last_read_status;
56 }
57 
58 
free_string(const char * str)59 void free_string(const char *str) { delete [] str; }
60 
61 
add_column(MY_BITMAP * map,Cursor::column_id column)62 static void add_column(MY_BITMAP *map, Cursor::column_id column)
63 {
64   if (column != Cursor::ILLEGAL_COLUMN_ID)
65     bitmap_set_bit(map, column);
66 }
67 
68 
Cursor(MYSQL_THD mysql_thd)69 Cursor::Cursor(MYSQL_THD mysql_thd) :
70   m_thd(mysql_thd),
71   m_table_list(NULL),
72   m_is_finished(true),
73   m_table_is_malformed(true)
74 {
75   m_table_list= new TABLE_LIST;
76   if (m_table_list == NULL)
77     return; // Error
78 
79   // The below function will memset() the whole object with 0's.
80   m_table_list->init_one_table(db_name, strlen(db_name),
81                                table_name, strlen(table_name),
82                                "alias", TL_WRITE_DEFAULT);
83 
84   m_table_list->updating= true;
85 
86   if (open_and_lock_tables(m_thd, m_table_list, MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY))
87     return; // Error
88 
89   TABLE *table= m_table_list->table;
90   if (table == NULL)
91     return; // Error
92 
93   m_pattern_column= field_index("pattern");
94   m_pattern_database_column= field_index("pattern_database");
95   m_replacement_column= field_index("replacement");
96   m_enabled_column= field_index("enabled");
97 
98   // The following columns are not required for the Cursor to work.
99   m_message_column= field_index("message");
100   m_pattern_digest_column= field_index("pattern_digest");
101   m_normalized_pattern_column= field_index("normalized_pattern");
102 
103   if (m_pattern_column == ILLEGAL_COLUMN_ID ||
104       m_pattern_database_column == ILLEGAL_COLUMN_ID ||
105       m_replacement_column == ILLEGAL_COLUMN_ID ||
106       m_enabled_column == ILLEGAL_COLUMN_ID)
107   {
108     trans_rollback_stmt(m_thd);
109     close_thread_tables(m_thd);
110 
111     /*
112       We are never going to use this table, we might as well get rid of the
113       reference to it.
114     */
115     delete m_table_list;
116     m_table_list= NULL;
117     m_table_is_malformed= true;
118     return; // Error
119   }
120   else
121     m_table_is_malformed= false;
122 
123   add_column(table->read_set, pattern_column());
124   add_column(table->read_set, pattern_database_column());
125   add_column(table->read_set, replacement_column());
126   add_column(table->read_set, enabled_column());
127   add_column(table->read_set, message_column());
128 
129   add_column(table->write_set, enabled_column());
130   add_column(table->write_set, message_column());
131   add_column(table->write_set, pattern_digest_column());
132   add_column(table->write_set, normalized_pattern_column());
133 
134   if (m_table_list->table->file->ha_rnd_init(true) != 0)
135     return; // Error
136 
137   // No error occured, set this to false.
138   m_is_finished= false;
139 
140   read();
141 }
142 
143 
fetch_string(int fieldno)144 const char *Cursor::fetch_string(int fieldno)
145 {
146   Field **fields= m_table_list->table->field;
147   Field *field= fields[fieldno];
148   if (field->is_null())
149     return NULL;
150   String value_buf;
151   String *value= field->val_str(&value_buf);
152   size_t length= value->length();
153   char *res= new char[length + 1];
154   strncpy(res, value->ptr(), length);
155   res[length]= '\0';
156   return res;
157 }
158 
159 
field_index(const char * field_name)160 int Cursor::field_index(const char *field_name)
161 {
162   TABLE *table= m_table_list->table;
163   for (uint i= 0; i < table->s->fields; ++i)
164     if (strcmp(table->field[i]->field_name, field_name) == 0)
165       return i;
166   return -1;
167 }
168 
169 
make_writeable()170 void Cursor::make_writeable()
171 {
172   TABLE *table= m_table_list->table;
173   memcpy(table->record[1], table->record[0], table->s->rec_buff_length);
174 }
175 
176 
set(int colno,const char * str,size_t length)177 void Cursor::set(int colno, const char* str, size_t length)
178 {
179   TABLE *table= m_table_list->table;
180   Field *field= table->field[colno];
181 
182   const CHARSET_INFO *charset= &my_charset_utf8_unicode_ci;
183   if (str == NULL)
184     field->set_null(0);
185   else
186   {
187     field->store(str, length, charset);
188     field->set_notnull(0);
189   }
190 }
191 
192 
write()193 int Cursor::write()
194 {
195   TABLE *table= m_table_list->table;
196   return table->file->ha_update_row(table->record[1], table->record[0]);
197 }
198 
had_serious_read_error() const199 bool Cursor::had_serious_read_error() const
200 {
201   return
202     m_last_read_status != 0 &&
203     m_last_read_status != HA_ERR_END_OF_FILE;
204 }
205 
~Cursor()206 Cursor::~Cursor()
207 {
208   if (m_table_list != NULL && m_table_list->table != NULL)
209     m_table_list->table->file->ha_rnd_end();
210   delete m_table_list;
211 }
212 
213 
end()214 Cursor end() { return Cursor(); }
215 
216 }
217