mariadb/storage/connect/ha_connect.h
Olivier Bertrand 16893bc076 - Add index read previous capacity.
modified:
  storage/connect/ha_connect.cc
  storage/connect/ha_connect.h
  storage/connect/xindex.cpp

- Optimize retrieving numeric values in scan_record. Was previously
  translating numeric values to character representation back and forth.
modified:
  storage/connect/ha_connect.cc
  storage/connect/mysql-test/connect/r/xml.result

- Modify Pivot table creation to avoid reading the entire source table
  when making columns from Discovery. MDEV-6024
modified:
  storage/connect/tabpivot.cpp
2014-04-08 11:15:08 +02:00

499 lines
18 KiB
C++

/* Copyright (C) Olivier Bertrand 2004 - 2013
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/** @file ha_connect.h
@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
/****************************************************************************/
/* 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, char *name) {
char *nm= NULL;
if (name) {nm= (char*)PlugSubAlloc(g, NULL, strlen(name) + 1);
strcpy(nm, name);}
return nm;}
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_table_option_struct TOS, *PTOS;
typedef struct ha_field_option_struct FOS, *PFOS;
extern handlerton *connect_hton;
/**
structure for CREATE TABLE options (table options)
These can be specified in the CREATE TABLE:
CREATE TABLE ( ... ) {...here...}
*/
struct ha_table_option_struct {
const char *type;
const char *filename;
const char *optname;
const char *tabname;
const char *tablist;
const char *dbname;
const char *separator;
//const char *connect;
const char *qchar;
const char *module;
const char *subtype;
const char *catfunc;
const char *srcdef;
const char *colist;
const char *oplist;
const char *data_charset;
ulonglong lrecl;
ulonglong elements;
//ulonglong estimate;
ulonglong multiple;
ulonglong header;
ulonglong quoted;
ulonglong ending;
ulonglong compressed;
bool mapped;
bool huge;
bool split;
bool readonly;
bool sepindex;
};
/**
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 fldlen;
const char *dateformat;
const char *fieldformat;
char *special;
};
/** @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();
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);
char *GetStringOption(char *opname, char *sdef= NULL);
PTOS GetTableOptionStruct(TABLE *table_arg);
bool GetBooleanOption(char *opname, bool bdef);
bool SetBooleanOption(char *opname, bool b);
int GetIntegerOption(char *opname);
bool CheckString(const char *str1, const char *str2);
bool SameString(TABLE *tab, char *opn);
bool SetIntegerOption(char *opname, int n);
bool SameInt(TABLE *tab, char *opn);
bool SameBool(TABLE *tab, char *opn);
bool FileExists(const char *fn);
bool NoFieldOptionChange(TABLE *tab);
PFOS GetFieldOptionStruct(Field *fp);
void *GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf);
PIXDEF GetIndexInfo(TABLE_SHARE *s= NULL);
const char *GetDBName(const char *name);
const char *GetTableName(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);
PTDB GetTDB(PGLOBAL g);
int OpenTable(PGLOBAL g, bool del= false);
bool IsOpened(void);
int CloseTable(PGLOBAL g);
int MakeRecord(char *buf);
int ScanRecord(PGLOBAL g, uchar *buf);
int CheckRecord(PGLOBAL g, const uchar *oldbuf, uchar *newbuf);
int ReadIndexed(uchar *buf, OPVAL op, const uchar* key= NULL,
uint key_len= 0);
/** @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) { return "XPLUG"; }
/** @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
{
return HA_READ_NEXT | HA_READ_RANGE | HA_READ_ORDER |
HA_READ_PREV | HA_KEYREAD_ONLY | HA_KEY_SCAN_NOT_ROR;
} // end of index_flags
/** @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, AMT tty, Item *cond);
const char *GetValStr(OPVAL vop, bool neg);
/**
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(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, 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, key_range *min_key,
key_range *max_key);
/**
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);
protected:
bool check_privileges(THD *thd, PTOS options, char *dbn);
MODE CheckMode(PGLOBAL g, THD *thd, MODE newmode, bool *chk, 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
PTDB tdbp; // To table class object
PVAL sdvalin; // Used to convert date values
PVAL sdvalout; // Used to convert date values
bool istable; // True for table handler
//char tname[64]; // The table 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
int indexing; // Type of indexing for CONNECT
int locked; // Table lock
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