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-1301 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); |
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 |
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 | */ |
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_REPAIR); |
150 | } |
151 | /* |
152 | This is a bitmap of flags that says how the storage engine |
153 | implements indexes. The current index flags are documented in |
154 | handler.h. If you do not implement indexes, just return zero |
155 | here. |
156 | |
157 | part is the key part to check. First key part is 0 |
158 | If all_parts it's set, MySQL want to know the flags for the combined |
159 | index up to and including 'part'. |
160 | */ |
161 | /* fix server to be able to get remote server index flags */ |
162 | ulong index_flags(uint inx, uint part, bool all_parts) const |
163 | { |
164 | return (HA_READ_NEXT | HA_READ_RANGE | HA_READ_AFTER_KEY); |
165 | } |
166 | uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; } |
167 | uint max_supported_keys() const { return MAX_KEY; } |
168 | uint max_supported_key_parts() const { return MAX_REF_PARTS; } |
169 | uint max_supported_key_length() const { return FEDERATED_MAX_KEY_LENGTH; } |
170 | uint max_supported_key_part_length() const { return FEDERATED_MAX_KEY_LENGTH; } |
171 | /* |
172 | Called in test_quick_select to determine if indexes should be used. |
173 | Normally, we need to know number of blocks . For federated we need to |
174 | know number of blocks on remote side, and number of packets and blocks |
175 | on the network side (?) |
176 | Talk to Kostja about this - how to get the |
177 | number of rows * ... |
178 | disk scan time on other side (block size, size of the row) + network time ... |
179 | The reason for "records * 1000" is that such a large number forces |
180 | this to use indexes " |
181 | */ |
182 | double scan_time() |
183 | { |
184 | DBUG_PRINT("info" , ("records %lu" , (ulong) stats.records)); |
185 | return (double)(stats.records*1000); |
186 | } |
187 | /* |
188 | The next method will never be called if you do not implement indexes. |
189 | */ |
190 | double read_time(uint index, uint ranges, ha_rows rows) |
191 | { |
192 | /* |
193 | Per Brian, this number is bugus, but this method must be implemented, |
194 | and at a later date, he intends to document this issue for handler code |
195 | */ |
196 | return (double) rows / 20.0+1; |
197 | } |
198 | |
199 | const key_map *keys_to_use_for_scanning() { return &key_map_full; } |
200 | /* |
201 | Everything below are methods that we implment in ha_federated.cc. |
202 | |
203 | Most of these methods are not obligatory, skip them and |
204 | MySQL will treat them as not implemented |
205 | */ |
206 | int open(const char *name, int mode, uint test_if_locked); // required |
207 | int close(void); // required |
208 | |
209 | void start_bulk_insert(ha_rows rows, uint flags); |
210 | int end_bulk_insert(); |
211 | int write_row(uchar *buf); |
212 | int update_row(const uchar *old_data, const uchar *new_data); |
213 | int delete_row(const uchar *buf); |
214 | int index_init(uint keynr, bool sorted); |
215 | ha_rows estimate_rows_upper_bound(); |
216 | int index_read(uchar *buf, const uchar *key, |
217 | uint key_len, enum ha_rkey_function find_flag); |
218 | int index_read_idx(uchar *buf, uint idx, const uchar *key, |
219 | uint key_len, enum ha_rkey_function find_flag); |
220 | int index_next(uchar *buf); |
221 | int index_end(); |
222 | int read_range_first(const key_range *start_key, |
223 | const key_range *end_key, |
224 | bool eq_range, bool sorted); |
225 | int read_range_next(); |
226 | /* |
227 | unlike index_init(), rnd_init() can be called two times |
228 | without rnd_end() in between (it only makes sense if scan=1). |
229 | then the second call should prepare for the new table scan |
230 | (e.g if rnd_init allocates the cursor, second call should |
231 | position it to the start of the table, no need to deallocate |
232 | and allocate it again |
233 | */ |
234 | int rnd_init(bool scan); //required |
235 | int rnd_end(); |
236 | int rnd_next(uchar *buf); //required |
237 | int rnd_next_int(uchar *buf); |
238 | int rnd_pos(uchar *buf, uchar *pos); //required |
239 | void position(const uchar *record); //required |
240 | int info(uint); //required |
241 | int (ha_extra_function operation); |
242 | |
243 | void update_auto_increment(void); |
244 | int repair(THD* thd, HA_CHECK_OPT* check_opt); |
245 | int optimize(THD* thd, HA_CHECK_OPT* check_opt); |
246 | |
247 | int delete_all_rows(void); |
248 | int truncate(); |
249 | int create(const char *name, TABLE *form, |
250 | HA_CREATE_INFO *create_info); //required |
251 | ha_rows records_in_range(uint inx, key_range *start_key, |
252 | key_range *end_key); |
253 | uint8 table_cache_type() { return HA_CACHE_TBL_NOCACHE; } |
254 | |
255 | THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, |
256 | enum thr_lock_type lock_type); //required |
257 | bool get_error_message(int error, String *buf); |
258 | |
259 | MYSQL_RES *store_result(MYSQL *mysql); |
260 | void free_result(); |
261 | |
262 | int external_lock(THD *thd, int lock_type); |
263 | int connection_commit(); |
264 | int connection_rollback(); |
265 | int connection_autocommit(bool state); |
266 | int execute_simple_query(const char *query, int len); |
267 | int reset(void); |
268 | }; |
269 | |
270 | |