1 /*
2    Copyright (c) 2012, 2021, Oracle and/or its affiliates.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #ifndef NDB_REPL_TAB_H
26 #define NDB_REPL_TAB_H
27 
28 #include <my_global.h>
29 
30 #ifdef HAVE_NDB_BINLOG
31 #include <mysql_com.h>  /* NAME_CHAR_LEN */
32 #include <ndbapi/NdbApi.hpp>
33 
34 /*
35   Ndb_rep_tab_key
36 
37   This class represents the key columns of the
38   mysql.ndb_replication system table
39   It is used when reading values from that table
40 */
41 class Ndb_rep_tab_key
42 {
43 public:
44   static const uint DB_MAXLEN= NAME_CHAR_LEN - 1;
45   static const uint TABNAME_MAXLEN= NAME_CHAR_LEN - 1;
46 
47   /* Char arrays in varchar format with 1 length byte and
48    * trailing 0
49    */
50   char db[ DB_MAXLEN + 2 ];
51   char table_name[ TABNAME_MAXLEN + 2 ];
52   uint server_id;
53 
Ndb_rep_tab_key()54   Ndb_rep_tab_key()
55   {
56     db[0] = 0;
57     table_name[0] = 0;
58     server_id = 0;
59   }
60 
61   /* Constructor from normal null terminated strings */
62   Ndb_rep_tab_key(const char* _db,
63                   const char* _table_name,
64                   uint _server_id);
65 
66   /* Add null terminators to VARCHAR format string values */
67   void null_terminate_strings();
68 
get_db()69   const char* get_db() const
70   {
71     return &db[1];
72   };
73 
get_table_name()74   const char* get_table_name() const
75   {
76     return &table_name[1];
77   };
78 
79   static const int MIN_MATCH_VAL = 1;
80   static const int EXACT_MATCH_DB = 4;
81   static const int EXACT_MATCH_TABLE_NAME = 2;
82   static const int EXACT_MATCH_SERVER_ID = 1;
83 
84   static const int EXACT_MATCH_QUALITY =
85     MIN_MATCH_VAL +
86     EXACT_MATCH_DB +
87     EXACT_MATCH_TABLE_NAME +
88     EXACT_MATCH_SERVER_ID;
89 
90   /*
91     This static method attempts an exact, then a wild
92     match between the passed key (with optional wild
93     characters), and the passed candidate row
94     returns :
95      1  : Exact match
96      0  : Wild match
97      -1 : No match
98   */
99   static int attempt_match(const char* keyptr,
100                            const uint keylen,
101                            const char* candidateptr,
102                            const uint candidatelen,
103                            const int exactmatchvalue);
104 
105   /* This static method compares a fixed key value with
106    * a possibly wildcard containing candidate_row.
107    * If there is no match, 0 is returned.
108    * >0 means there is a match, with larger numbers
109    * indicating a better match quality.
110    * An exact match returns EXACT_MATCH_QUALITY
111    */
112   static int get_match_quality(const Ndb_rep_tab_key* key,
113                                const Ndb_rep_tab_key* candidate_row);
114 };
115 
116 /*
117   Ndb_rep_tab_row
118 
119   This class represents a row in the mysql.ndb_replication table
120 */
121 class Ndb_rep_tab_row
122 {
123 public:
124   static const uint MAX_CONFLICT_FN_SPEC_LEN = 255;
125   static const uint CONFLICT_FN_SPEC_BUF_LEN =
126     MAX_CONFLICT_FN_SPEC_LEN + 1; /* Trailing '\0' */
127 
128   Ndb_rep_tab_key key;
129   uint binlog_type;
130   bool cfs_is_null;
131   /* Buffer has space for leading length byte */
132   char conflict_fn_spec[ CONFLICT_FN_SPEC_BUF_LEN + 1 ];
133 
134   Ndb_rep_tab_row();
135 
null_terminate_strings()136   void null_terminate_strings()
137   {
138     key.null_terminate_strings();
139     uint speclen= 0;
140     speclen = conflict_fn_spec[0];
141 
142     assert(speclen <= MAX_CONFLICT_FN_SPEC_LEN);
143     conflict_fn_spec[1 + speclen] = '\0';
144   }
145 
get_conflict_fn_spec()146   const char* get_conflict_fn_spec()
147   {
148     return &conflict_fn_spec[1];
149   }
150 
set_conflict_fn_spec_null(bool null)151   void set_conflict_fn_spec_null(bool null)
152   {
153     if (null)
154     {
155       cfs_is_null = true;
156       conflict_fn_spec[0] = 0;
157       conflict_fn_spec[1] = 0;
158     }
159     else
160     {
161       cfs_is_null = false;
162     }
163   }
164 };
165 
166 /**
167    Ndb_rep_tab_reader
168 
169    A helper class for accessing the mysql.ndb_replication
170    table
171 */
172 class Ndb_rep_tab_reader
173 {
174 private:
175   static const char *ndb_rep_db;
176   static const char *ndb_replication_table;
177   static const char *nrt_db;
178   static const char *nrt_table_name;
179   static const char *nrt_server_id;
180   static const char *nrt_binlog_type;
181   static const char *nrt_conflict_fn;
182 
183   Uint32 binlog_flags;
184   char conflict_fn_buffer[ Ndb_rep_tab_row::CONFLICT_FN_SPEC_BUF_LEN ];
185   char warning_msg_buffer[ FN_REFLEN ];
186 
187   const char* conflict_fn_spec;
188   const char* warning_msg;
189 
190   /**
191      check_schema
192 
193      Checks that the schema of the mysql.ndb_replication table
194      is acceptable.
195      Returns
196      0 if ok
197      -1 if a column has an error.  Col name in error_str
198      -2 if there's a more general error.  Error description in
199         error_str
200   */
201   static
202   int check_schema(const NdbDictionary::Table* reptab,
203                    NdbDictionary::Dictionary* dict,
204                    const char** error_str);
205 
206   /**
207      scan_candidates
208 
209      Scans the ndb_replication table for rows matching the
210      passed db, table_name, server_id triple.
211      Returns the quality of the match made.
212 
213      -1 = Error in processing, see msg
214      0 = No match, use defaults.
215      >0 = Use data in best_match
216 
217      if msg is set on return it contains a warning.
218      Warnings may be produces in non error scenarios
219   */
220   int scan_candidates(Ndb* ndb,
221                       const NdbDictionary::Table* reptab,
222                       const char* db,
223                       const char* table_name,
224                       uint server_id,
225                       Ndb_rep_tab_row& best_match);
226 public:
227   Ndb_rep_tab_reader();
~Ndb_rep_tab_reader()228   ~Ndb_rep_tab_reader() {};
229 
230   /**
231      lookup
232 
233      lookup scans the mysql.ndb_replication table for
234      the best matching entry for the supplied db,
235      table_name, server_id triple.
236      A buffer for the conflict_fn spec, and for any
237      error or warning messages must be supplied.
238      The passed binlog_flags, conflict_fn_spec and
239      message may be updated as a result
240 
241      Returns :
242        0  : Success.
243        <0 : Error.
244   */
245   int lookup(Ndb* ndb,
246              /* Keys */
247              const char* db,
248              const char* table_name,
249              uint server_id);
250 
251   /* Following only valid after a call to lookup() */
252   Uint32 get_binlog_flags() const;
253   const char* get_conflict_fn_spec() const;
254   const char* get_warning_message() const;
255 };
256 
257 /* #ifdef HAVE_NDB_BINLOG */
258 #endif
259 
260 /* #ifdef NDB_REPL_TAB_H */
261 #endif
262