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