1 | /* Copyright (C) MariaDB Corporation Ab |
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 Street, Fifth Floor, Boston, MA 02111-1301 USA */ |
15 | |
16 | /** @file ha_connect.h |
17 | Author Olivier Bertrand |
18 | |
19 | @brief |
20 | The ha_connect engine is a prototype storage engine to access external data. |
21 | |
22 | @see |
23 | /sql/handler.h and /storage/connect/ha_connect.cc |
24 | */ |
25 | |
26 | #ifdef USE_PRAGMA_INTERFACE |
27 | #pragma interface /* gcc class implementation */ |
28 | #endif |
29 | |
30 | /****************************************************************************/ |
31 | /* mycat.h contains the TOS, PTOS, ha_table_option_struct declarations. */ |
32 | /****************************************************************************/ |
33 | #include "mycat.h" |
34 | |
35 | /****************************************************************************/ |
36 | /* Structures used to pass info between CONNECT and ha_connect. */ |
37 | /****************************************************************************/ |
38 | typedef struct _create_xinfo { |
39 | char *Type; /* Retrieved from table comment */ |
40 | char *Filename; /* Set if not standard */ |
41 | char *IndexFN; /* Set if not standard */ |
42 | ulonglong Maxrows; /* Estimated max nb of rows */ |
43 | ulong Lrecl; /* Set if not default */ |
44 | ulong Elements; /* Number of lines in blocks */ |
45 | bool Fixed; /* False for DOS type */ |
46 | void *Pcf; /* To list of columns */ |
47 | void *Pxdf; /* To list of indexes */ |
48 | } CRXINFO, *PCXF; |
49 | |
50 | typedef struct _xinfo { |
51 | ulonglong data_file_length; /* Length of data file */ |
52 | ha_rows records; /* Records in table */ |
53 | ulong mean_rec_length; /* Physical record length */ |
54 | char *data_file_name; /* Physical file name */ |
55 | } XINFO, *PXF; |
56 | |
57 | class XCHK : public BLOCK { |
58 | public: |
59 | XCHK(void) {oldsep= newsep= false; |
60 | oldopn= newopn= NULL; |
61 | oldpix= newpix= NULL;} |
62 | |
63 | inline char *SetName(PGLOBAL g, PCSZ name) {return PlugDup(g, name);} |
64 | |
65 | bool oldsep; // Sepindex before create/alter |
66 | bool newsep; // Sepindex after create/alter |
67 | char *oldopn; // Optname before create/alter |
68 | char *newopn; // Optname after create/alter |
69 | PIXDEF oldpix; // The indexes before create/alter |
70 | PIXDEF newpix; // The indexes after create/alter |
71 | }; // end of class XCHK |
72 | |
73 | typedef class XCHK *PCHK; |
74 | typedef class user_connect *PCONNECT; |
75 | typedef struct ha_field_option_struct FOS, *PFOS; |
76 | typedef struct ha_index_option_struct XOS, *PXOS; |
77 | |
78 | extern handlerton *connect_hton; |
79 | |
80 | /** |
81 | structure for CREATE TABLE options (table options) |
82 | |
83 | These can be specified in the CREATE TABLE: |
84 | CREATE TABLE ( ... ) {...here...} |
85 | |
86 | ------ Was moved to mycat.h ------ |
87 | */ |
88 | |
89 | /** |
90 | structure for CREATE TABLE options (field options) |
91 | |
92 | These can be specified in the CREATE TABLE per field: |
93 | CREATE TABLE ( field ... {...here...}, ... ) |
94 | */ |
95 | struct ha_field_option_struct |
96 | { |
97 | ulonglong offset; |
98 | ulonglong freq; |
99 | ulonglong fldlen; |
100 | uint opt; |
101 | const char *dateformat; |
102 | const char *fieldformat; |
103 | char *special; |
104 | }; |
105 | |
106 | /* |
107 | index options can be declared similarly |
108 | using the ha_index_option_struct structure. |
109 | |
110 | Their values can be specified in the CREATE TABLE per index: |
111 | CREATE TABLE ( field ..., .., INDEX .... *here*, ... ) |
112 | */ |
113 | struct ha_index_option_struct |
114 | { |
115 | bool dynamic; |
116 | bool mapped; |
117 | }; |
118 | |
119 | /** @brief |
120 | CONNECT_SHARE is a structure that will be shared among all open handlers. |
121 | This example implements the minimum of what you will probably need. |
122 | */ |
123 | class CONNECT_SHARE : public Handler_share { |
124 | public: |
125 | mysql_mutex_t mutex; |
126 | THR_LOCK lock; |
127 | CONNECT_SHARE() |
128 | { |
129 | thr_lock_init(&lock); |
130 | } |
131 | ~CONNECT_SHARE() |
132 | { |
133 | thr_lock_delete(&lock); |
134 | mysql_mutex_destroy(&mutex); |
135 | } |
136 | }; |
137 | |
138 | typedef class ha_connect *PHC; |
139 | |
140 | /** @brief |
141 | Class definition for the storage engine |
142 | */ |
143 | class ha_connect: public handler |
144 | { |
145 | THR_LOCK_DATA lock; ///< MySQL lock |
146 | CONNECT_SHARE *share; ///< Shared lock info |
147 | CONNECT_SHARE *get_share(); |
148 | |
149 | protected: |
150 | char *PlugSubAllocStr(PGLOBAL g, void *memp, const char *str, size_t length) |
151 | { |
152 | char *ptr= (char*)PlgDBSubAlloc(g, memp, length + 1); |
153 | |
154 | if (ptr) { |
155 | memcpy(ptr, str, length); |
156 | ptr[length]= '\0'; |
157 | } // endif ptr |
158 | |
159 | return ptr; |
160 | } // end of PlugSubAllocStr |
161 | |
162 | public: |
163 | ha_connect(handlerton *hton, TABLE_SHARE *table_arg); |
164 | ~ha_connect(); |
165 | |
166 | // CONNECT Implementation |
167 | //static bool connect_init(void); |
168 | //static bool connect_end(void); |
169 | TABTYPE GetRealType(PTOS pos= NULL); |
170 | char *GetRealString(PCSZ s); |
171 | PCSZ GetStringOption(PCSZ opname, PCSZ sdef= NULL); |
172 | PTOS GetTableOptionStruct(TABLE_SHARE *s= NULL); |
173 | bool GetBooleanOption(PCSZ opname, bool bdef); |
174 | bool SetBooleanOption(PCSZ opname, bool b); |
175 | int GetIntegerOption(PCSZ opname); |
176 | bool GetIndexOption(KEY *kp, PCSZ opname); |
177 | bool CheckString(PCSZ str1, PCSZ str2); |
178 | bool SameString(TABLE *tab, PCSZ opn); |
179 | bool SetIntegerOption(PCSZ opname, int n); |
180 | bool SameInt(TABLE *tab, PCSZ opn); |
181 | bool SameBool(TABLE *tab, PCSZ opn); |
182 | bool FileExists(const char *fn, bool bf); |
183 | bool NoFieldOptionChange(TABLE *tab); |
184 | PFOS GetFieldOptionStruct(Field *fp); |
185 | void *GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf); |
186 | PXOS GetIndexOptionStruct(KEY *kp); |
187 | PIXDEF GetIndexInfo(TABLE_SHARE *s= NULL); |
188 | bool CheckVirtualIndex(TABLE_SHARE *s); |
189 | PCSZ GetDBName(PCSZ name); |
190 | PCSZ GetTableName(void); |
191 | char *GetPartName(void); |
192 | //int GetColNameLen(Field *fp); |
193 | //char *GetColName(Field *fp); |
194 | //void AddColName(char *cp, Field *fp); |
195 | TABLE *GetTable(void) {return table;} |
196 | bool IsSameIndex(PIXDEF xp1, PIXDEF xp2); |
197 | bool IsPartitioned(void); |
198 | bool IsUnique(uint n); |
199 | PCSZ GetDataPath(void) {return datapath;} |
200 | |
201 | bool SetDataPath(PGLOBAL g, PCSZ path); |
202 | PTDB GetTDB(PGLOBAL g); |
203 | int OpenTable(PGLOBAL g, bool del= false); |
204 | bool CheckColumnList(PGLOBAL g); |
205 | bool IsOpened(void); |
206 | int CloseTable(PGLOBAL g); |
207 | int MakeRecord(char *buf); |
208 | int ScanRecord(PGLOBAL g, const uchar *buf); |
209 | int CheckRecord(PGLOBAL g, const uchar *oldbuf, const uchar *newbuf); |
210 | int ReadIndexed(uchar *buf, OPVAL op, const key_range *kr= NULL); |
211 | bool IsIndexed(Field *fp); |
212 | bool MakeKeyWhere(PGLOBAL g, PSTRG qry, OPVAL op, char q, |
213 | const key_range *kr); |
214 | //inline char *Strz(LEX_STRING &ls); |
215 | key_range start_key; |
216 | |
217 | |
218 | /** @brief |
219 | The name that will be used for display purposes. |
220 | */ |
221 | const char *table_type() const {return "CONNECT" ;} |
222 | |
223 | /** @brief |
224 | The name of the index type that will be used for display. |
225 | Don't implement this method unless you really have indexes. |
226 | */ |
227 | const char *index_type(uint inx); |
228 | |
229 | /** @brief |
230 | The file extensions. |
231 | */ |
232 | //const char **bas_ext() const; |
233 | |
234 | /** |
235 | Check if a storage engine supports a particular alter table in-place |
236 | @note Called without holding thr_lock.c lock. |
237 | */ |
238 | virtual enum_alter_inplace_result |
239 | check_if_supported_inplace_alter(TABLE *altered_table, |
240 | Alter_inplace_info *ha_alter_info); |
241 | |
242 | /** @brief |
243 | This is a list of flags that indicate what functionality the storage engine |
244 | implements. The current table flags are documented in handler.h |
245 | */ |
246 | ulonglong table_flags() const; |
247 | |
248 | /** @brief |
249 | This is a bitmap of flags that indicates how the storage engine |
250 | implements indexes. The current index flags are documented in |
251 | handler.h. If you do not implement indexes, just return zero here. |
252 | |
253 | @details |
254 | part is the key part to check. First key part is 0. |
255 | If all_parts is set, MySQL wants to know the flags for the combined |
256 | index, up to and including 'part'. |
257 | */ |
258 | ulong index_flags(uint inx, uint part, bool all_parts) const; |
259 | |
260 | /** @brief |
261 | unireg.cc will call max_supported_record_length(), max_supported_keys(), |
262 | max_supported_key_parts(), uint max_supported_key_length() |
263 | to make sure that the storage engine can handle the data it is about to |
264 | send. Return *real* limits of your storage engine here; MySQL will do |
265 | min(your_limits, MySQL_limits) automatically. |
266 | */ |
267 | uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; } |
268 | |
269 | /** @brief |
270 | unireg.cc will call this to make sure that the storage engine can handle |
271 | the data it is about to send. Return *real* limits of your storage engine |
272 | here; MySQL will do min(your_limits, MySQL_limits) automatically. |
273 | |
274 | @details |
275 | There is no need to implement ..._key_... methods if your engine doesn't |
276 | support indexes. |
277 | */ |
278 | uint max_supported_keys() const { return 10; } |
279 | |
280 | /** @brief |
281 | unireg.cc will call this to make sure that the storage engine can handle |
282 | the data it is about to send. Return *real* limits of your storage engine |
283 | here; MySQL will do min(your_limits, MySQL_limits) automatically. |
284 | |
285 | @details |
286 | There is no need to implement ..._key_... methods if your engine doesn't |
287 | support indexes. |
288 | */ |
289 | uint max_supported_key_parts() const { return 10; } |
290 | |
291 | /** @brief |
292 | unireg.cc will call this to make sure that the storage engine can handle |
293 | the data it is about to send. Return *real* limits of your storage engine |
294 | here; MySQL will do min(your_limits, MySQL_limits) automatically. |
295 | |
296 | @details |
297 | There is no need to implement ..._key_... methods if your engine doesn't |
298 | support indexes. |
299 | */ |
300 | uint max_supported_key_length() const { return 255; } |
301 | |
302 | /** @brief |
303 | Called in test_quick_select to determine if indexes should be used. |
304 | */ |
305 | virtual double scan_time() { return (double) (stats.records+stats.deleted) / 20.0+10; } |
306 | |
307 | /** @brief |
308 | This method will never be called if you do not implement indexes. |
309 | */ |
310 | virtual double read_time(uint, uint, ha_rows rows) |
311 | { return (double) rows / 20.0+1; } |
312 | |
313 | /* |
314 | Everything below are methods that we implement in ha_connect.cc. |
315 | |
316 | Most of these methods are not obligatory, skip them and |
317 | MySQL will treat them as not implemented |
318 | */ |
319 | virtual bool get_error_message(int error, String *buf); |
320 | |
321 | /** |
322 | Push condition down to the table handler. |
323 | |
324 | @param cond Condition to be pushed. The condition tree must not be |
325 | modified by the by the caller. |
326 | |
327 | @return |
328 | The 'remainder' condition that caller must use to filter out records. |
329 | NULL means the handler will not return rows that do not match the |
330 | passed condition. |
331 | |
332 | @note |
333 | The pushed conditions form a stack (from which one can remove the |
334 | last pushed condition using cond_pop). |
335 | The table handler filters out rows using (pushed_cond1 AND pushed_cond2 |
336 | AND ... AND pushed_condN) |
337 | or less restrictive condition, depending on handler's capabilities. |
338 | |
339 | handler->ha_reset() call empties the condition stack. |
340 | Calls to rnd_init/rnd_end, index_init/index_end etc do not affect the |
341 | condition stack. |
342 | */ |
343 | virtual const COND *cond_push(const COND *cond); |
344 | PCFIL CheckCond(PGLOBAL g, PCFIL filp, const Item *cond); |
345 | const char *GetValStr(OPVAL vop, bool neg); |
346 | PFIL CondFilter(PGLOBAL g, Item *cond); |
347 | //PFIL CheckFilter(PGLOBAL g); |
348 | |
349 | /** admin commands - called from mysql_admin_table */ |
350 | virtual int check(THD* thd, HA_CHECK_OPT* check_opt) |
351 | { |
352 | // TODO: implement it |
353 | return HA_ADMIN_OK; // Just to avoid error message with checktables |
354 | } // end of check |
355 | |
356 | /** |
357 | Number of rows in table. It will only be called if |
358 | (table_flags() & (HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT)) != 0 |
359 | */ |
360 | virtual ha_rows records(); |
361 | |
362 | /** |
363 | Type of table for caching query |
364 | CONNECT should not use caching because its tables are external |
365 | data prone to me modified out of MariaDB |
366 | */ |
367 | virtual uint8 table_cache_type(void) |
368 | { |
369 | #if defined(MEMORY_TRACE) |
370 | // Temporary until bug MDEV-4771 is fixed |
371 | return HA_CACHE_TBL_NONTRANSACT; |
372 | #else |
373 | return HA_CACHE_TBL_NOCACHE; |
374 | #endif |
375 | } |
376 | |
377 | /** @brief |
378 | We implement this in ha_connect.cc; it's a required method. |
379 | */ |
380 | int open(const char *name, int mode, uint test_if_locked); // required |
381 | |
382 | /** @brief |
383 | We implement this in ha_connect.cc; it's a required method. |
384 | */ |
385 | int close(void); // required |
386 | |
387 | /** @brief |
388 | We implement this in ha_connect.cc. It's not an obligatory method; |
389 | skip it and and MySQL will treat it as not implemented. |
390 | */ |
391 | int write_row(uchar *buf); |
392 | |
393 | /** @brief |
394 | We implement this in ha_connect.cc. It's not an obligatory method; |
395 | skip it and and MySQL will treat it as not implemented. |
396 | */ |
397 | int update_row(const uchar *old_data, const uchar *new_data); |
398 | |
399 | /** @brief |
400 | We implement this in ha_connect.cc. It's not an obligatory method; |
401 | skip it and and MySQL will treat it as not implemented. |
402 | */ |
403 | int delete_row(const uchar *buf); |
404 | |
405 | // Added to the connect handler |
406 | int index_init(uint idx, bool sorted); |
407 | int index_end(); |
408 | int index_read(uchar * buf, const uchar * key, uint key_len, |
409 | enum ha_rkey_function find_flag); |
410 | int index_next_same(uchar *buf, const uchar *key, uint keylen); |
411 | |
412 | /** @brief |
413 | We implement this in ha_connect.cc. It's not an obligatory method; |
414 | skip it and and MySQL will treat it as not implemented. |
415 | */ |
416 | //int index_read_map(uchar *buf, const uchar *key, |
417 | // key_part_map keypart_map, enum ha_rkey_function find_flag); |
418 | |
419 | /** @brief |
420 | We implement this in ha_connect.cc. It's not an obligatory method; |
421 | skip it and and MySQL will treat it as not implemented. |
422 | */ |
423 | int index_next(uchar *buf); |
424 | |
425 | /** @brief |
426 | We implement this in ha_connect.cc. It's not an obligatory method; |
427 | skip it and and MySQL will treat it as not implemented. |
428 | */ |
429 | int index_prev(uchar *buf); |
430 | |
431 | /** @brief |
432 | We implement this in ha_connect.cc. It's not an obligatory method; |
433 | skip it and and MySQL will treat it as not implemented. |
434 | */ |
435 | int index_first(uchar *buf); |
436 | |
437 | /** @brief |
438 | We implement this in ha_connect.cc. It's not an obligatory method; |
439 | skip it and and MySQL will treat it as not implemented. |
440 | */ |
441 | int index_last(uchar *buf); |
442 | |
443 | /* Index condition pushdown implementation */ |
444 | //Item *idx_cond_push(uint keyno, Item* idx_cond); |
445 | |
446 | /** @brief |
447 | Unlike index_init(), rnd_init() can be called two consecutive times |
448 | without rnd_end() in between (it only makes sense if scan=1). In this |
449 | case, the second call should prepare for the new table scan (e.g if |
450 | rnd_init() allocates the cursor, the second call should position the |
451 | cursor to the start of the table; no need to deallocate and allocate |
452 | it again. This is a required method. |
453 | */ |
454 | int rnd_init(bool scan); //required |
455 | int rnd_end(); |
456 | int rnd_next(uchar *buf); ///< required |
457 | int rnd_pos(uchar *buf, uchar *pos); ///< required |
458 | void position(const uchar *record); ///< required |
459 | int info(uint); ///< required |
460 | int (enum ha_extra_function operation); |
461 | int start_stmt(THD *thd, thr_lock_type lock_type); |
462 | int external_lock(THD *thd, int lock_type); ///< required |
463 | int delete_all_rows(void); |
464 | ha_rows records_in_range(uint inx, key_range *min_key, |
465 | key_range *max_key); |
466 | /** |
467 | These methods can be overridden, but their default implementation |
468 | provide useful functionality. |
469 | */ |
470 | int rename_table(const char *from, const char *to); |
471 | /** |
472 | Delete a table in the engine. Called for base as well as temporary |
473 | tables. |
474 | */ |
475 | int delete_table(const char *name); |
476 | /** |
477 | Called by delete_table and rename_table |
478 | */ |
479 | int delete_or_rename_table(const char *from, const char *to); |
480 | int create(const char *name, TABLE *form, |
481 | HA_CREATE_INFO *create_info); ///< required |
482 | bool check_if_incompatible_data(HA_CREATE_INFO *info, |
483 | uint table_changes); |
484 | |
485 | THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, |
486 | enum thr_lock_type lock_type); ///< required |
487 | int optimize(THD* thd, HA_CHECK_OPT* check_opt); |
488 | |
489 | /** |
490 | * Multi Range Read interface |
491 | */ |
492 | int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param, |
493 | uint n_ranges, uint mode, HANDLER_BUFFER *buf); |
494 | int multi_range_read_next(range_id_t *range_info); |
495 | ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, |
496 | void *seq_init_param, |
497 | uint n_ranges, uint *bufsz, |
498 | uint *flags, Cost_estimate *cost); |
499 | ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys, |
500 | uint key_parts, uint *bufsz, |
501 | uint *flags, Cost_estimate *cost); |
502 | int multi_range_read_explain_info(uint mrr_mode, char *str, size_t size); |
503 | |
504 | int reset(void) {ds_mrr.dsmrr_close(); return 0;} |
505 | |
506 | /* Index condition pushdown implementation */ |
507 | // Item *idx_cond_push(uint keyno, Item* idx_cond); |
508 | private: |
509 | DsMrr_impl ds_mrr; |
510 | |
511 | protected: |
512 | bool check_privileges(THD *thd, PTOS options, const char *dbn, bool quick=false); |
513 | MODE CheckMode(PGLOBAL g, THD *thd, MODE newmode, bool *chk, bool *cras); |
514 | char *GetDBfromName(const char *name); |
515 | |
516 | // Members |
517 | static ulong num; // Tracable handler number |
518 | PCONNECT xp; // To user_connect associated class |
519 | ulong hnum; // The number of this handler |
520 | query_id_t valid_query_id; // The one when tdbp was allocated |
521 | query_id_t creat_query_id; // The one when handler was allocated |
522 | PCSZ datapath; // Is the Path of DB data directory |
523 | PTDB tdbp; // To table class object |
524 | PVAL sdvalin1; // Used to convert date values |
525 | PVAL sdvalin2; // Used to convert date values |
526 | PVAL sdvalin3; // Used to convert date values |
527 | PVAL sdvalin4; // Used to convert date values |
528 | PVAL sdvalout; // Used to convert date values |
529 | bool istable; // True for table handler |
530 | char partname[65]; // The partition name |
531 | MODE xmod; // Table mode |
532 | XINFO xinfo; // The table info structure |
533 | bool valid_info; // True if xinfo is valid |
534 | bool stop; // Used when creating index |
535 | bool alter; // True when converting to other engine |
536 | bool mrr; // True when getting index positions |
537 | bool nox; // True when index should not be made |
538 | bool abort; // True after error in UPDATE/DELETE |
539 | int indexing; // Type of indexing for CONNECT |
540 | int locked; // Table lock |
541 | MY_BITMAP *part_id; // Columns used for partition func |
542 | THR_LOCK_DATA lock_data; |
543 | |
544 | public: |
545 | TABLE_SHARE *tshp; // Used by called tables |
546 | char *data_file_name; |
547 | char *index_file_name; |
548 | uint int_table_flags; // Inherited from MyISAM |
549 | bool enable_activate_all_index; // Inherited from MyISAM |
550 | }; // end of ha_connect class definition |
551 | |