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