1 /* Copyright (c) 2004, 2013, 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 as published by
5   the Free Software Foundation; version 2 of the License.
6 
7   This program is distributed in the hope that it will be useful,
8   but WITHOUT ANY WARRANTY; without even the implied warranty of
9   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10   GNU General Public License for more details.
11 
12   You should have received a copy of the GNU General Public License
13   along with this program; if not, write to the Free Software
14   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
15 
16 /*
17   Please read ha_exmple.cc before reading this file.
18   Please keep in mind that the federated storage engine implements all methods
19   that are required to be implemented. handler.h has a full list of methods
20   that you can implement.
21 */
22 
23 #ifdef USE_PRAGMA_INTERFACE
24 #pragma interface			/* gcc class implementation */
25 #endif
26 
27 #include <mysql.h>
28 
29 /*
30   handler::print_error has a case statement for error numbers.
31   This value is (10000) is far out of range and will envoke the
32   default: case.
33   (Current error range is 120-159 from include/my_base.h)
34 */
35 #define HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM 10000
36 
37 #define FEDERATED_QUERY_BUFFER_SIZE (STRING_BUFFER_USUAL_SIZE * 5)
38 #define FEDERATED_RECORDS_IN_RANGE 2
39 #define FEDERATED_MAX_KEY_LENGTH 3500 // Same as innodb
40 
41 /*
42   FEDERATED_SHARE is a structure that will be shared amoung all open handlers
43   The example implements the minimum of what you will probably need.
44 */
45 typedef struct st_federated_share {
46   MEM_ROOT mem_root;
47 
48   bool parsed;
49   /* this key is unique db/tablename */
50   const char *share_key;
51   /*
52     the primary select query to be used in rnd_init
53   */
54   char *select_query;
55   /*
56     remote host info, parse_url supplies
57   */
58   char *server_name;
59   char *connection_string;
60   char *scheme;
61   char *connect_string;
62   char *hostname;
63   char *username;
64   char *password;
65   char *database;
66   char *table_name;
67   char *table;
68   char *socket;
69   char *sport;
70   int share_key_length;
71   ushort port;
72 
73   size_t table_name_length, server_name_length, connect_string_length, use_count;
74   mysql_mutex_t mutex;
75   THR_LOCK lock;
76 } FEDERATED_SHARE;
77 
78 /*
79   Class definition for the storage engine
80 */
81 class ha_federated: public handler
82 {
83   THR_LOCK_DATA lock;      /* MySQL lock */
84   FEDERATED_SHARE *share;    /* Shared lock info */
85   MYSQL *mysql; /* MySQL connection */
86   MYSQL_RES *stored_result;
87   /**
88     Array of all stored results we get during a query execution.
89   */
90   DYNAMIC_ARRAY results;
91   bool position_called, table_will_be_deleted;
92   MYSQL_ROW_OFFSET current_position;  // Current position used by ::position()
93   int remote_error_number;
94   char remote_error_buf[FEDERATED_QUERY_BUFFER_SIZE];
95   bool ignore_duplicates, replace_duplicates;
96   bool insert_dup_update;
97   DYNAMIC_STRING bulk_insert;
98 
99 private:
100   /*
101       return 0 on success
102       return errorcode otherwise
103   */
104   uint convert_row_to_internal_format(uchar *buf, MYSQL_ROW row,
105                                       MYSQL_RES *result);
106   bool create_where_from_key(String *to, KEY *key_info,
107                              const key_range *start_key,
108                              const key_range *end_key,
109                              bool records_in_range, bool eq_range);
110   int stash_remote_error();
111 
112   bool append_stmt_insert(String *query);
113 
114   int read_next(uchar *buf, MYSQL_RES *result);
115   int index_read_idx_with_result_set(uchar *buf, uint index,
116                                      const uchar *key,
117                                      uint key_len,
118                                      ha_rkey_function find_flag,
119                                      MYSQL_RES **result);
120   int real_query(const char *query, size_t length);
121   int real_connect();
122 public:
123   ha_federated(handlerton *hton, TABLE_SHARE *table_arg);
~ha_federated()124   ~ha_federated() {}
125   /*
126     Next pointer used in transaction
127   */
128   ha_federated *trx_next;
129   /*
130     The name of the index type that will be used for display
131     don't implement this method unless you really have indexes
132    */
133   // perhaps get index type
index_type(uint inx)134   const char *index_type(uint inx) { return "REMOTE"; }
135   /*
136     This is a list of flags that says what the storage engine
137     implements. The current table flags are documented in
138     handler.h
139   */
table_flags()140   ulonglong table_flags() const
141   {
142     /* fix server to be able to get remote server table flags */
143     return (HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED
144             | HA_REC_NOT_IN_SEQ | HA_AUTO_PART_KEY | HA_CAN_INDEX_BLOBS |
145             HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
146             HA_NO_PREFIX_CHAR_KEYS | HA_PRIMARY_KEY_REQUIRED_FOR_DELETE |
147             HA_NO_TRANSACTIONS /* until fixed by WL#2952 */ |
148             HA_PARTIAL_COLUMN_READ | HA_NULL_IN_KEY |
149             HA_CAN_ONLINE_BACKUPS | HA_NON_COMPARABLE_ROWID |
150             HA_CAN_REPAIR);
151   }
152   /*
153     This is a bitmap of flags that says how the storage engine
154     implements indexes. The current index flags are documented in
155     handler.h. If you do not implement indexes, just return zero
156     here.
157 
158     part is the key part to check. First key part is 0
159     If all_parts it's set, MySQL want to know the flags for the combined
160     index up to and including 'part'.
161   */
162     /* fix server to be able to get remote server index flags */
index_flags(uint inx,uint part,bool all_parts)163   ulong index_flags(uint inx, uint part, bool all_parts) const
164   {
165     return (HA_READ_NEXT | HA_READ_RANGE | HA_READ_AFTER_KEY);
166   }
max_supported_record_length()167   uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; }
max_supported_keys()168   uint max_supported_keys()          const { return MAX_KEY; }
max_supported_key_parts()169   uint max_supported_key_parts()     const { return MAX_REF_PARTS; }
max_supported_key_length()170   uint max_supported_key_length()    const { return FEDERATED_MAX_KEY_LENGTH; }
max_supported_key_part_length()171   uint max_supported_key_part_length() const { return FEDERATED_MAX_KEY_LENGTH; }
172   /*
173     Called in test_quick_select to determine if indexes should be used.
174     Normally, we need to know number of blocks . For federated we need to
175     know number of blocks on remote side, and number of packets and blocks
176     on the network side (?)
177     Talk to Kostja about this - how to get the
178     number of rows * ...
179     disk scan time on other side (block size, size of the row) + network time ...
180     The reason for "records * 1000" is that such a large number forces
181     this to use indexes "
182   */
scan_time()183   double scan_time()
184   {
185     DBUG_PRINT("info", ("records %lu", (ulong) stats.records));
186     return (double)(stats.records*1000);
187   }
188   /*
189     The next method will never be called if you do not implement indexes.
190   */
read_time(uint index,uint ranges,ha_rows rows)191   double read_time(uint index, uint ranges, ha_rows rows)
192   {
193     /*
194       Per Brian, this number is bugus, but this method must be implemented,
195       and at a later date, he intends to document this issue for handler code
196     */
197     return (double) rows /  20.0+1;
198   }
199 
keys_to_use_for_scanning()200   const key_map *keys_to_use_for_scanning() { return &key_map_full; }
201   /*
202     Everything below are methods that we implment in ha_federated.cc.
203 
204     Most of these methods are not obligatory, skip them and
205     MySQL will treat them as not implemented
206   */
207   int open(const char *name, int mode, uint test_if_locked);    // required
208   int close(void);                                              // required
209 
210   void start_bulk_insert(ha_rows rows, uint flags);
211   int end_bulk_insert();
212   int write_row(const uchar *buf);
213   int update_row(const uchar *old_data, const uchar *new_data);
214   int delete_row(const uchar *buf);
215   int index_init(uint keynr, bool sorted);
216   ha_rows estimate_rows_upper_bound();
217   int index_read(uchar *buf, const uchar *key,
218                  uint key_len, enum ha_rkey_function find_flag);
219   int index_read_idx(uchar *buf, uint idx, const uchar *key,
220                      uint key_len, enum ha_rkey_function find_flag);
221   int index_next(uchar *buf);
222   int index_end();
223   int read_range_first(const key_range *start_key,
224                                const key_range *end_key,
225                                bool eq_range, bool sorted);
226   int read_range_next();
227   /*
228     unlike index_init(), rnd_init() can be called two times
229     without rnd_end() in between (it only makes sense if scan=1).
230     then the second call should prepare for the new table scan
231     (e.g if rnd_init allocates the cursor, second call should
232     position it to the start of the table, no need to deallocate
233     and allocate it again
234   */
235   int rnd_init(bool scan);                                      //required
236   int rnd_end();
237   int rnd_next(uchar *buf);                                      //required
238   int rnd_next_int(uchar *buf);
239   int rnd_pos(uchar *buf, uchar *pos);                            //required
240   void position(const uchar *record);                            //required
241   /*
242     A ref is a pointer inside a local buffer. It is not comparable to
243     other ref's. This is never called as HA_NON_COMPARABLE_ROWID is set.
244   */
cmp_ref(const uchar * ref1,const uchar * ref2)245   int cmp_ref(const uchar *ref1, const uchar *ref2)
246   {
247 #ifdef NOT_YET
248     DBUG_ASSERT(0);
249     return 0;
250 #else
251     return handler::cmp_ref(ref1,ref2);         /* Works if table scan is used */
252 #endif
253   }
254   int info(uint);                                              //required
255   int extra(ha_extra_function operation);
256 
257   void update_auto_increment(void);
258   int repair(THD* thd, HA_CHECK_OPT* check_opt);
259   int optimize(THD* thd, HA_CHECK_OPT* check_opt);
delete_table(const char * name)260   int delete_table(const char *name)
261   {
262     return 0;
263   }
264   int delete_all_rows(void);
265   int truncate();
266   int create(const char *name, TABLE *form,
267              HA_CREATE_INFO *create_info);                      //required
268   ha_rows records_in_range(uint inx,
269                            const key_range *start_key,
270                            const key_range *end_key,
271                            page_range *pages);
table_cache_type()272   uint8 table_cache_type() { return HA_CACHE_TBL_NOCACHE; }
273 
274   THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
275                              enum thr_lock_type lock_type);     //required
276   bool get_error_message(int error, String *buf);
277 
278   MYSQL_RES *store_result(MYSQL *mysql);
279   void free_result();
280 
281   int external_lock(THD *thd, int lock_type);
282   int connection_commit();
283   int connection_rollback();
284   int connection_autocommit(bool state);
285   int execute_simple_query(const char *query, int len);
286   int reset(void);
287 };
288 
289