mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
f36ca142f7
Prototype change: - virtual ha_rows records_in_range(uint inx, key_range *min_key, - key_range *max_key) + virtual ha_rows records_in_range(uint inx, const key_range *min_key, + const key_range *max_key, + page_range *res) The handler can ignore the page_range parameter. In the case the handler updates the parameter, the optimizer can deduce the following: - If previous range's last key is on the same block as next range's first key - If the current key range is in one block - We can also assume that the first and last block read are cached! This can be used for a better calculation of IO seeks when we estimate the cost of a range index scan. The parameter is fully implemented for MyISAM, Aria and InnoDB. A separate patch will update handler::multi_range_read_info_const() to take the benefits of this change and also remove the double records_in_range() calls that are not anymore needed.
555 lines
20 KiB
C++
555 lines
20 KiB
C++
/* Copyright (C) MariaDB Corporation Ab
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
|
|
|
|
/** @file ha_connect.h
|
|
Author Olivier Bertrand
|
|
|
|
@brief
|
|
The ha_connect engine is a prototype storage engine to access external data.
|
|
|
|
@see
|
|
/sql/handler.h and /storage/connect/ha_connect.cc
|
|
*/
|
|
|
|
#ifdef USE_PRAGMA_INTERFACE
|
|
#pragma interface /* gcc class implementation */
|
|
#endif
|
|
|
|
/****************************************************************************/
|
|
/* mycat.h contains the TOS, PTOS, ha_table_option_struct declarations. */
|
|
/****************************************************************************/
|
|
#include "mycat.h"
|
|
|
|
#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
|
|
bool MongoEnabled(void);
|
|
#endif // JAVA_SUPPORT || CMGO_SUPPORT
|
|
|
|
/****************************************************************************/
|
|
/* Structures used to pass info between CONNECT and ha_connect. */
|
|
/****************************************************************************/
|
|
typedef struct _create_xinfo {
|
|
char *Type; /* Retrieved from table comment */
|
|
char *Filename; /* Set if not standard */
|
|
char *IndexFN; /* Set if not standard */
|
|
ulonglong Maxrows; /* Estimated max nb of rows */
|
|
ulong Lrecl; /* Set if not default */
|
|
ulong Elements; /* Number of lines in blocks */
|
|
bool Fixed; /* False for DOS type */
|
|
void *Pcf; /* To list of columns */
|
|
void *Pxdf; /* To list of indexes */
|
|
} CRXINFO, *PCXF;
|
|
|
|
typedef struct _xinfo {
|
|
ulonglong data_file_length; /* Length of data file */
|
|
ha_rows records; /* Records in table */
|
|
ulong mean_rec_length; /* Physical record length */
|
|
char *data_file_name; /* Physical file name */
|
|
} XINFO, *PXF;
|
|
|
|
class XCHK : public BLOCK {
|
|
public:
|
|
XCHK(void) {oldsep= newsep= false;
|
|
oldopn= newopn= NULL;
|
|
oldpix= newpix= NULL;}
|
|
|
|
inline char *SetName(PGLOBAL g, PCSZ name) {return PlugDup(g, name);}
|
|
|
|
bool oldsep; // Sepindex before create/alter
|
|
bool newsep; // Sepindex after create/alter
|
|
char *oldopn; // Optname before create/alter
|
|
char *newopn; // Optname after create/alter
|
|
PIXDEF oldpix; // The indexes before create/alter
|
|
PIXDEF newpix; // The indexes after create/alter
|
|
}; // end of class XCHK
|
|
|
|
typedef class XCHK *PCHK;
|
|
typedef class user_connect *PCONNECT;
|
|
typedef struct ha_field_option_struct FOS, *PFOS;
|
|
typedef struct ha_index_option_struct XOS, *PXOS;
|
|
|
|
extern handlerton *connect_hton;
|
|
|
|
/**
|
|
structure for CREATE TABLE options (table options)
|
|
|
|
These can be specified in the CREATE TABLE:
|
|
CREATE TABLE ( ... ) {...here...}
|
|
|
|
------ Was moved to mycat.h ------
|
|
*/
|
|
|
|
/**
|
|
structure for CREATE TABLE options (field options)
|
|
|
|
These can be specified in the CREATE TABLE per field:
|
|
CREATE TABLE ( field ... {...here...}, ... )
|
|
*/
|
|
struct ha_field_option_struct
|
|
{
|
|
ulonglong offset;
|
|
ulonglong freq;
|
|
ulonglong fldlen;
|
|
uint opt;
|
|
const char *dateformat;
|
|
const char *fieldformat;
|
|
char *special;
|
|
};
|
|
|
|
/*
|
|
index options can be declared similarly
|
|
using the ha_index_option_struct structure.
|
|
|
|
Their values can be specified in the CREATE TABLE per index:
|
|
CREATE TABLE ( field ..., .., INDEX .... *here*, ... )
|
|
*/
|
|
struct ha_index_option_struct
|
|
{
|
|
bool dynamic;
|
|
bool mapped;
|
|
};
|
|
|
|
/** @brief
|
|
CONNECT_SHARE is a structure that will be shared among all open handlers.
|
|
This example implements the minimum of what you will probably need.
|
|
*/
|
|
class CONNECT_SHARE : public Handler_share {
|
|
public:
|
|
mysql_mutex_t mutex;
|
|
THR_LOCK lock;
|
|
CONNECT_SHARE()
|
|
{
|
|
thr_lock_init(&lock);
|
|
}
|
|
~CONNECT_SHARE()
|
|
{
|
|
thr_lock_delete(&lock);
|
|
mysql_mutex_destroy(&mutex);
|
|
}
|
|
};
|
|
|
|
typedef class ha_connect *PHC;
|
|
|
|
/** @brief
|
|
Class definition for the storage engine
|
|
*/
|
|
class ha_connect: public handler
|
|
{
|
|
THR_LOCK_DATA lock; ///< MySQL lock
|
|
CONNECT_SHARE *share; ///< Shared lock info
|
|
CONNECT_SHARE *get_share();
|
|
|
|
protected:
|
|
char *PlugSubAllocStr(PGLOBAL g, void *memp, const char *str, size_t length)
|
|
{
|
|
char *ptr= (char*)PlgDBSubAlloc(g, memp, length + 1);
|
|
|
|
if (ptr) {
|
|
memcpy(ptr, str, length);
|
|
ptr[length]= '\0';
|
|
} // endif ptr
|
|
|
|
return ptr;
|
|
} // end of PlugSubAllocStr
|
|
|
|
public:
|
|
ha_connect(handlerton *hton, TABLE_SHARE *table_arg);
|
|
~ha_connect();
|
|
|
|
// CONNECT Implementation
|
|
//static bool connect_init(void);
|
|
//static bool connect_end(void);
|
|
TABTYPE GetRealType(PTOS pos= NULL);
|
|
char *GetRealString(PCSZ s);
|
|
PCSZ GetStringOption(PCSZ opname, PCSZ sdef= NULL);
|
|
PTOS GetTableOptionStruct(TABLE_SHARE *s= NULL);
|
|
bool GetBooleanOption(PCSZ opname, bool bdef);
|
|
bool SetBooleanOption(PCSZ opname, bool b);
|
|
int GetIntegerOption(PCSZ opname);
|
|
bool GetIndexOption(KEY *kp, PCSZ opname);
|
|
bool CheckString(PCSZ str1, PCSZ str2);
|
|
bool SameString(TABLE *tab, PCSZ opn);
|
|
bool SetIntegerOption(PCSZ opname, int n);
|
|
bool SameInt(TABLE *tab, PCSZ opn);
|
|
bool SameBool(TABLE *tab, PCSZ opn);
|
|
bool FileExists(const char *fn, bool bf);
|
|
bool NoFieldOptionChange(TABLE *tab);
|
|
PFOS GetFieldOptionStruct(Field *fp);
|
|
void *GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf);
|
|
PXOS GetIndexOptionStruct(KEY *kp);
|
|
PIXDEF GetIndexInfo(TABLE_SHARE *s= NULL);
|
|
bool CheckVirtualIndex(TABLE_SHARE *s);
|
|
PCSZ GetDBName(PCSZ name);
|
|
PCSZ GetTableName(void);
|
|
char *GetPartName(void);
|
|
//int GetColNameLen(Field *fp);
|
|
//char *GetColName(Field *fp);
|
|
//void AddColName(char *cp, Field *fp);
|
|
TABLE *GetTable(void) {return table;}
|
|
bool IsSameIndex(PIXDEF xp1, PIXDEF xp2);
|
|
bool IsPartitioned(void);
|
|
bool IsUnique(uint n);
|
|
PCSZ GetDataPath(void) {return datapath;}
|
|
|
|
bool SetDataPath(PGLOBAL g, PCSZ path);
|
|
PTDB GetTDB(PGLOBAL g);
|
|
int OpenTable(PGLOBAL g, bool del= false);
|
|
bool CheckColumnList(PGLOBAL g);
|
|
bool IsOpened(void);
|
|
int CloseTable(PGLOBAL g);
|
|
int MakeRecord(char *buf);
|
|
int ScanRecord(PGLOBAL g, const uchar *buf);
|
|
int CheckRecord(PGLOBAL g, const uchar *oldbuf, const uchar *newbuf);
|
|
int ReadIndexed(uchar *buf, OPVAL op, const key_range *kr= NULL);
|
|
bool IsIndexed(Field *fp);
|
|
bool MakeKeyWhere(PGLOBAL g, PSTRG qry, OPVAL op, char q,
|
|
const key_range *kr);
|
|
//inline char *Strz(LEX_STRING &ls);
|
|
key_range start_key;
|
|
|
|
|
|
/** @brief
|
|
The name that will be used for display purposes.
|
|
*/
|
|
const char *table_type() const {return "CONNECT";}
|
|
|
|
/** @brief
|
|
The name of the index type that will be used for display.
|
|
Don't implement this method unless you really have indexes.
|
|
*/
|
|
const char *index_type(uint inx);
|
|
|
|
/** @brief
|
|
The file extensions.
|
|
*/
|
|
//const char **bas_ext() const;
|
|
|
|
/**
|
|
Check if a storage engine supports a particular alter table in-place
|
|
@note Called without holding thr_lock.c lock.
|
|
*/
|
|
virtual enum_alter_inplace_result
|
|
check_if_supported_inplace_alter(TABLE *altered_table,
|
|
Alter_inplace_info *ha_alter_info);
|
|
|
|
/** @brief
|
|
This is a list of flags that indicate what functionality the storage engine
|
|
implements. The current table flags are documented in handler.h
|
|
*/
|
|
ulonglong table_flags() const;
|
|
|
|
/** @brief
|
|
This is a bitmap of flags that indicates how the storage engine
|
|
implements indexes. The current index flags are documented in
|
|
handler.h. If you do not implement indexes, just return zero here.
|
|
|
|
@details
|
|
part is the key part to check. First key part is 0.
|
|
If all_parts is set, MySQL wants to know the flags for the combined
|
|
index, up to and including 'part'.
|
|
*/
|
|
ulong index_flags(uint inx, uint part, bool all_parts) const;
|
|
|
|
/** @brief
|
|
unireg.cc will call max_supported_record_length(), max_supported_keys(),
|
|
max_supported_key_parts(), uint max_supported_key_length()
|
|
to make sure that the storage engine can handle the data it is about to
|
|
send. Return *real* limits of your storage engine here; MySQL will do
|
|
min(your_limits, MySQL_limits) automatically.
|
|
*/
|
|
uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; }
|
|
|
|
/** @brief
|
|
unireg.cc will call this to make sure that the storage engine can handle
|
|
the data it is about to send. Return *real* limits of your storage engine
|
|
here; MySQL will do min(your_limits, MySQL_limits) automatically.
|
|
|
|
@details
|
|
There is no need to implement ..._key_... methods if your engine doesn't
|
|
support indexes.
|
|
*/
|
|
uint max_supported_keys() const { return 10; }
|
|
|
|
/** @brief
|
|
unireg.cc will call this to make sure that the storage engine can handle
|
|
the data it is about to send. Return *real* limits of your storage engine
|
|
here; MySQL will do min(your_limits, MySQL_limits) automatically.
|
|
|
|
@details
|
|
There is no need to implement ..._key_... methods if your engine doesn't
|
|
support indexes.
|
|
*/
|
|
uint max_supported_key_parts() const { return 10; }
|
|
|
|
/** @brief
|
|
unireg.cc will call this to make sure that the storage engine can handle
|
|
the data it is about to send. Return *real* limits of your storage engine
|
|
here; MySQL will do min(your_limits, MySQL_limits) automatically.
|
|
|
|
@details
|
|
There is no need to implement ..._key_... methods if your engine doesn't
|
|
support indexes.
|
|
*/
|
|
uint max_supported_key_length() const { return 255; }
|
|
|
|
/** @brief
|
|
Called in test_quick_select to determine if indexes should be used.
|
|
*/
|
|
virtual double scan_time() { return (double) (stats.records+stats.deleted) / 20.0+10; }
|
|
|
|
/** @brief
|
|
This method will never be called if you do not implement indexes.
|
|
*/
|
|
virtual double read_time(uint, uint, ha_rows rows)
|
|
{ return (double) rows / 20.0+1; }
|
|
|
|
/*
|
|
Everything below are methods that we implement in ha_connect.cc.
|
|
|
|
Most of these methods are not obligatory, skip them and
|
|
MySQL will treat them as not implemented
|
|
*/
|
|
virtual bool get_error_message(int error, String *buf);
|
|
|
|
/**
|
|
Push condition down to the table handler.
|
|
|
|
@param cond Condition to be pushed. The condition tree must not be
|
|
modified by the by the caller.
|
|
|
|
@return
|
|
The 'remainder' condition that caller must use to filter out records.
|
|
NULL means the handler will not return rows that do not match the
|
|
passed condition.
|
|
|
|
@note
|
|
The pushed conditions form a stack (from which one can remove the
|
|
last pushed condition using cond_pop).
|
|
The table handler filters out rows using (pushed_cond1 AND pushed_cond2
|
|
AND ... AND pushed_condN)
|
|
or less restrictive condition, depending on handler's capabilities.
|
|
|
|
handler->ha_reset() call empties the condition stack.
|
|
Calls to rnd_init/rnd_end, index_init/index_end etc do not affect the
|
|
condition stack.
|
|
*/
|
|
virtual const COND *cond_push(const COND *cond);
|
|
PCFIL CheckCond(PGLOBAL g, PCFIL filp, const Item *cond);
|
|
const char *GetValStr(OPVAL vop, bool neg);
|
|
PFIL CondFilter(PGLOBAL g, Item *cond);
|
|
//PFIL CheckFilter(PGLOBAL g);
|
|
|
|
/** admin commands - called from mysql_admin_table */
|
|
virtual int check(THD* thd, HA_CHECK_OPT* check_opt);
|
|
|
|
/**
|
|
Number of rows in table. It will only be called if
|
|
(table_flags() & (HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT)) != 0
|
|
*/
|
|
virtual ha_rows records();
|
|
|
|
/**
|
|
Type of table for caching query
|
|
CONNECT should not use caching because its tables are external
|
|
data prone to me modified out of MariaDB
|
|
*/
|
|
virtual uint8 table_cache_type(void)
|
|
{
|
|
#if defined(MEMORY_TRACE)
|
|
// Temporary until bug MDEV-4771 is fixed
|
|
return HA_CACHE_TBL_NONTRANSACT;
|
|
#else
|
|
return HA_CACHE_TBL_NOCACHE;
|
|
#endif
|
|
}
|
|
|
|
/** @brief
|
|
We implement this in ha_connect.cc; it's a required method.
|
|
*/
|
|
int open(const char *name, int mode, uint test_if_locked); // required
|
|
|
|
/** @brief
|
|
We implement this in ha_connect.cc; it's a required method.
|
|
*/
|
|
int close(void); // required
|
|
|
|
/** @brief
|
|
We implement this in ha_connect.cc. It's not an obligatory method;
|
|
skip it and and MySQL will treat it as not implemented.
|
|
*/
|
|
int write_row(const uchar *buf);
|
|
|
|
/** @brief
|
|
We implement this in ha_connect.cc. It's not an obligatory method;
|
|
skip it and and MySQL will treat it as not implemented.
|
|
*/
|
|
int update_row(const uchar *old_data, const uchar *new_data);
|
|
|
|
/** @brief
|
|
We implement this in ha_connect.cc. It's not an obligatory method;
|
|
skip it and and MySQL will treat it as not implemented.
|
|
*/
|
|
int delete_row(const uchar *buf);
|
|
|
|
// Added to the connect handler
|
|
int index_init(uint idx, bool sorted);
|
|
int index_end();
|
|
int index_read(uchar * buf, const uchar * key, uint key_len,
|
|
enum ha_rkey_function find_flag);
|
|
int index_next_same(uchar *buf, const uchar *key, uint keylen);
|
|
|
|
/** @brief
|
|
We implement this in ha_connect.cc. It's not an obligatory method;
|
|
skip it and and MySQL will treat it as not implemented.
|
|
*/
|
|
//int index_read_map(uchar *buf, const uchar *key,
|
|
// key_part_map keypart_map, enum ha_rkey_function find_flag);
|
|
|
|
/** @brief
|
|
We implement this in ha_connect.cc. It's not an obligatory method;
|
|
skip it and and MySQL will treat it as not implemented.
|
|
*/
|
|
int index_next(uchar *buf);
|
|
|
|
/** @brief
|
|
We implement this in ha_connect.cc. It's not an obligatory method;
|
|
skip it and and MySQL will treat it as not implemented.
|
|
*/
|
|
int index_prev(uchar *buf);
|
|
|
|
/** @brief
|
|
We implement this in ha_connect.cc. It's not an obligatory method;
|
|
skip it and and MySQL will treat it as not implemented.
|
|
*/
|
|
int index_first(uchar *buf);
|
|
|
|
/** @brief
|
|
We implement this in ha_connect.cc. It's not an obligatory method;
|
|
skip it and and MySQL will treat it as not implemented.
|
|
*/
|
|
int index_last(uchar *buf);
|
|
|
|
/* Index condition pushdown implementation */
|
|
//Item *idx_cond_push(uint keyno, Item* idx_cond);
|
|
|
|
/** @brief
|
|
Unlike index_init(), rnd_init() can be called two consecutive times
|
|
without rnd_end() in between (it only makes sense if scan=1). In this
|
|
case, the second call should prepare for the new table scan (e.g if
|
|
rnd_init() allocates the cursor, the second call should position the
|
|
cursor to the start of the table; no need to deallocate and allocate
|
|
it again. This is a required method.
|
|
*/
|
|
int rnd_init(bool scan); //required
|
|
int rnd_end();
|
|
int rnd_next(uchar *buf); ///< required
|
|
int rnd_pos(uchar *buf, uchar *pos); ///< required
|
|
void position(const uchar *record); ///< required
|
|
int info(uint); ///< required
|
|
int extra(enum ha_extra_function operation);
|
|
int start_stmt(THD *thd, thr_lock_type lock_type);
|
|
int external_lock(THD *thd, int lock_type); ///< required
|
|
int delete_all_rows(void);
|
|
ha_rows records_in_range(uint inx, const key_range *start_key,
|
|
const key_range *end_key, page_range *pages);
|
|
/**
|
|
These methods can be overridden, but their default implementation
|
|
provide useful functionality.
|
|
*/
|
|
int rename_table(const char *from, const char *to);
|
|
/**
|
|
Delete a table in the engine. Called for base as well as temporary
|
|
tables.
|
|
*/
|
|
int delete_table(const char *name);
|
|
/**
|
|
Called by delete_table and rename_table
|
|
*/
|
|
int delete_or_rename_table(const char *from, const char *to);
|
|
int create(const char *name, TABLE *form,
|
|
HA_CREATE_INFO *create_info); ///< required
|
|
bool check_if_incompatible_data(HA_CREATE_INFO *info,
|
|
uint table_changes);
|
|
|
|
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
|
|
enum thr_lock_type lock_type); ///< required
|
|
int optimize(THD* thd, HA_CHECK_OPT* check_opt);
|
|
|
|
/**
|
|
* Multi Range Read interface
|
|
*/
|
|
int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
|
|
uint n_ranges, uint mode, HANDLER_BUFFER *buf);
|
|
int multi_range_read_next(range_id_t *range_info);
|
|
ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
|
|
void *seq_init_param,
|
|
uint n_ranges, uint *bufsz,
|
|
uint *flags, Cost_estimate *cost);
|
|
ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
|
|
uint key_parts, uint *bufsz,
|
|
uint *flags, Cost_estimate *cost);
|
|
int multi_range_read_explain_info(uint mrr_mode, char *str, size_t size);
|
|
|
|
int reset(void) {ds_mrr.dsmrr_close(); return 0;}
|
|
|
|
/* Index condition pushdown implementation */
|
|
// Item *idx_cond_push(uint keyno, Item* idx_cond);
|
|
private:
|
|
DsMrr_impl ds_mrr;
|
|
|
|
protected:
|
|
bool check_privileges(THD *thd, PTOS options, const char *dbn, bool quick=false);
|
|
MODE CheckMode(PGLOBAL g, THD *thd, MODE newmode, bool *chk, bool *cras);
|
|
int check_stmt(PGLOBAL g, MODE newmode, bool cras);
|
|
char *GetDBfromName(const char *name);
|
|
|
|
// Members
|
|
static ulong num; // Tracable handler number
|
|
PCONNECT xp; // To user_connect associated class
|
|
ulong hnum; // The number of this handler
|
|
query_id_t valid_query_id; // The one when tdbp was allocated
|
|
query_id_t creat_query_id; // The one when handler was allocated
|
|
PCSZ datapath; // Is the Path of DB data directory
|
|
PTDB tdbp; // To table class object
|
|
PVAL sdvalin1; // Used to convert date values
|
|
PVAL sdvalin2; // Used to convert date values
|
|
PVAL sdvalin3; // Used to convert date values
|
|
PVAL sdvalin4; // Used to convert date values
|
|
PVAL sdvalout; // Used to convert date values
|
|
bool istable; // True for table handler
|
|
char partname[65]; // The partition name
|
|
MODE xmod; // Table mode
|
|
XINFO xinfo; // The table info structure
|
|
bool valid_info; // True if xinfo is valid
|
|
bool stop; // Used when creating index
|
|
bool alter; // True when converting to other engine
|
|
bool mrr; // True when getting index positions
|
|
bool nox; // True when index should not be made
|
|
bool abort; // True after error in UPDATE/DELETE
|
|
int indexing; // Type of indexing for CONNECT
|
|
int locked; // Table lock
|
|
MY_BITMAP *part_id; // Columns used for partition func
|
|
THR_LOCK_DATA lock_data;
|
|
|
|
public:
|
|
TABLE_SHARE *tshp; // Used by called tables
|
|
char *data_file_name;
|
|
char *index_file_name;
|
|
uint int_table_flags; // Inherited from MyISAM
|
|
bool enable_activate_all_index; // Inherited from MyISAM
|
|
}; // end of ha_connect class definition
|
|
|
|
#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
|
|
bool MongoEnabled(void);
|
|
#endif // JAVA_SUPPORT || CMGO_SUPPORT
|