Commit c15914f7 authored by Sergey Petrunya's avatar Sergey Petrunya

Initial commit for Cassandra storage engine.

parent 6ed4a283
#
# suite.pm will make sure that all tests including this file
# will be skipped unless innodb or xtradb is enabled
#
# The test below is redundant
if (`SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.ENGINES WHERE engine = 'cassandra' AND support IN ('YES', 'DEFAULT', 'ENABLED')`)
{
--skip Test requires Cassandra.
}
drop table if exists t0, t1;
create table t1 (a int) engine=cassandra
thrift_host='localhost' keyspace='foo' column_family='colfam';
ERROR 42000: Incorrect column name 'First column must be named 'rowkey''
create table t1 (a int primary key, b int) engine=cassandra
thrift_host='localhost' keyspace='foo' column_family='colfam';
ERROR 42000: Incorrect column name 'First column must be named 'rowkey''
create table t1 (rowkey char(10) primary key, column1 char(10)) engine=cassandra
thrift_host='127.0.0.2' keyspace='foo' column_family='colfam';
ERROR HY000: Unable to connect to foreign data source: connect() failed: Connection refused [1]
create table t1 (rowkey char(10) primary key, column1 char(10)) engine=cassandra
thrift_host='localhost' keyspace='no_such_keyspace' column_family='colfam';
ERROR HY000: Unable to connect to foreign data source: Default TException. [Keyspace no_such_keyspace does not exist]
create table t1 (rowkey char(10) primary key, column1 char(10)) engine=cassandra
thrift_host='localhost' keyspace='no_such_keyspace';
ERROR HY000: Can't create table 'test.t1' (errno: 140)
create table t1 (rowkey char(36) primary key, column1 char(60)) engine=cassandra
thrift_host='localhost' keyspace='mariadbtest' column_family='cf1';
insert into t1 values ('key0', 'data1');
drop table t1;
#
# Tests for cassandra storage engine
#
--source include/have_cassandra.inc
--disable_warnings
drop table if exists t0, t1;
--enable_warnings
# Test various errors on table creation.
--error ER_WRONG_COLUMN_NAME
create table t1 (a int) engine=cassandra
thrift_host='localhost' keyspace='foo' column_family='colfam';
--error ER_WRONG_COLUMN_NAME
create table t1 (a int primary key, b int) engine=cassandra
thrift_host='localhost' keyspace='foo' column_family='colfam';
--error ER_CONNECT_TO_FOREIGN_DATA_SOURCE
create table t1 (rowkey char(10) primary key, column1 char(10)) engine=cassandra
thrift_host='127.0.0.2' keyspace='foo' column_family='colfam';
--error ER_CONNECT_TO_FOREIGN_DATA_SOURCE
create table t1 (rowkey char(10) primary key, column1 char(10)) engine=cassandra
thrift_host='localhost' keyspace='no_such_keyspace' column_family='colfam';
# No column family specified
--error ER_CANT_CREATE_TABLE
create table t1 (rowkey char(10) primary key, column1 char(10)) engine=cassandra
thrift_host='localhost' keyspace='no_such_keyspace';
############################################################################
## Cassandra initialization:
############################################################################
--disable_parsing
./cqlsh --cql3
CREATE KEYSPACE mariadbtest
WITH strategy_class = 'org.apache.cassandra.locator.SimpleStrategy'
AND strategy_options:replication_factor='1';
USE mariadbtest;
create columnfamily cf1 ( pk varchar primary key, data1 varchar);
--enable_parsing
############################################################################
## Cassandra initialization ends
############################################################################
# Now, create a table for real and insert data
create table t1 (rowkey char(36) primary key, column1 char(60)) engine=cassandra
thrift_host='localhost' keyspace='mariadbtest' column_family='cf1';
insert into t1 values ('key0', 'data1');
drop table t1;
############################################################################
## Cassandra cleanup
############################################################################
--disable_parsing
drop columnfamily cf1;
--enable_parsing
############################################################################
## Cassandra cleanup ends
############################################################################
SET(cassandra_sources
ha_cassandra.cc
ha_cassandra.h
cassandra_se.h
cassandra_se.cc
gen-cpp/Cassandra.cpp
gen-cpp/cassandra_types.h
gen-cpp/cassandra_types.cpp
gen-cpp/cassandra_constants.h
gen-cpp/cassandra_constants.cpp
gen-cpp/Cassandra.h)
#INCLUDE_DIRECTORIES(BEFORE ${Boost_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(AFTER /home/psergey/cassandra/thrift/include/thrift/)
#
STRING(REPLACE "-fno-exceptions" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
STRING(REPLACE "-fno-implicit-templates" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
#LINK_DIRECTORIES(/home/psergey/cassandra/thrift/lib)
MYSQL_ADD_PLUGIN(cassandra ${cassandra_sources} STORAGE_ENGINE LINK_LIBRARIES thrift)
# was: STORAGE_ENGINE MANDATORY
// Cassandra includes:
#include <inttypes.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdarg.h>
#include "Thrift.h"
#include "transport/TSocket.h"
#include "transport/TTransport.h"
#include "transport/TBufferTransports.h"
#include "protocol/TProtocol.h"
#include "protocol/TBinaryProtocol.h"
#include "gen-cpp/Cassandra.h"
// cassandra includes end
#include "cassandra_se.h"
using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::transport;
using namespace apache::thrift::protocol;
using namespace org::apache::cassandra;
void Cassandra_se_interface::print_error(const char *format, ...)
{
va_list ap;
va_start(ap, format);
// it's not a problem if output was truncated
vsnprintf(err_buffer, sizeof(err_buffer), format, ap);
va_end(ap);
}
/*
Implementation of connection to one Cassandra column family (ie., table)
*/
class Cassandra_se_impl: public Cassandra_se_interface
{
CassandraClient *cass; /* Connection to cassandra */
ConsistencyLevel::type cur_consistency_level;
std::string column_family;
std::string keyspace;
/* DDL checks */
KsDef ks_def; /* KeySpace we're using (TODO: put this in table->share) */
CfDef cf_def; /* Column family we're using (TODO: put in table->share)*/
std::vector<ColumnDef>::iterator column_ddl_it;
/* The list that was returned by the last key lookup */
std::vector<ColumnOrSuperColumn> col_supercol_vec;
public:
Cassandra_se_impl() : cass(NULL) {}
virtual ~Cassandra_se_impl(){ delete cass; }
bool connect(const char *host, const char *keyspace);
virtual void set_column_family(const char *cfname)
{
column_family.assign(cfname);
}
virtual bool insert(NameAndValue *fields);
virtual bool get_slice(char *key, size_t key_len, NameAndValue *row, bool *found);
/* Functions to enumerate ColumnFamily's DDL data */
bool setup_ddl_checks();
void first_ddl_column();
bool next_ddl_column(char **name, int *name_len, char **value, int *value_len);
};
Cassandra_se_interface *get_cassandra_se()
{
return new Cassandra_se_impl;
}
#define CASS_TRY(x) try { \
x; \
}catch(TTransportException te){ \
print_error("%s [%d]", te.what(), te.getType()); \
}catch(InvalidRequestException ire){ \
print_error("%s [%s]", ire.what(), ire.why.c_str()); \
}catch(NotFoundException nfe){ \
print_error("%s", nfe.what()); \
} catch(...) { \
print_error("Unknown Exception"); \
}
bool Cassandra_se_impl::connect(const char *host, const char *keyspace_arg)
{
bool res= true;
keyspace.assign(keyspace_arg);
try {
boost::shared_ptr<TTransport> socket =
boost::shared_ptr<TSocket>(new TSocket(host, 9160));
boost::shared_ptr<TTransport> tr =
boost::shared_ptr<TFramedTransport>(new TFramedTransport (socket));
boost::shared_ptr<TProtocol> p =
boost::shared_ptr<TBinaryProtocol>(new TBinaryProtocol(tr));
cass= new CassandraClient(p);
tr->open();
cass->set_keyspace(keyspace_arg);
res= false; // success
}catch(TTransportException te){
print_error("%s [%d]", te.what(), te.getType());
}catch(InvalidRequestException ire){
print_error("%s [%s]", ire.what(), ire.why.c_str());
}catch(NotFoundException nfe){
print_error("%s", nfe.what());
}
catch(...) {
print_error("Unknown Exception");
}
// For now:
cur_consistency_level= ConsistencyLevel::ONE;
if (setup_ddl_checks())
res= true;
return res;
}
bool Cassandra_se_impl::setup_ddl_checks()
{
try {
cass->describe_keyspace(ks_def, keyspace);
std::vector<CfDef>::iterator it;
for (it= ks_def.cf_defs.begin(); it < ks_def.cf_defs.end(); it++)
{
cf_def= *it;
if (!cf_def.name.compare(column_family))
return false;
}
print_error("describe_keyspace() didn't return our column family");
} catch (InvalidRequestException ire) {
print_error("%s [%s]", ire.what(), ire.why.c_str());
} catch (NotFoundException nfe) {
print_error("keyspace not found: %s", nfe.what());
}
return true;
}
void Cassandra_se_impl::first_ddl_column()
{
column_ddl_it= cf_def.column_metadata.begin();
}
bool Cassandra_se_impl::next_ddl_column(char **name, int *name_len,
char **type, int *type_len)
{
if (column_ddl_it == cf_def.column_metadata.end())
return true;
*name= (char*)(*column_ddl_it).name.c_str();
*name_len= (*column_ddl_it).name.length();
*type= (char*)(*column_ddl_it).validation_class.c_str();
*type_len= (*column_ddl_it).validation_class.length();
column_ddl_it++;
return false;
}
bool Cassandra_se_impl::insert(NameAndValue *fields)
{
ColumnParent cparent;
cparent.column_family= column_family;
Column c;
struct timeval td;
gettimeofday(&td, NULL);
int64_t ms = td.tv_sec;
ms = ms * 1000;
int64_t usec = td.tv_usec;
usec = usec / 1000;
ms += usec;
c.timestamp = ms;
c.__isset.timestamp = true;
std::string key;
key.assign(fields->value, fields->value_len);
fields++;
bool res= false;
try {
/* TODO: switch to batch_mutate(). Or, even to CQL? */
// TODO: what should INSERT table (co1, col2) VALUES ('foo', 'bar') mean?
// in SQL, it sets all columns.. what should it mean here? can we have
// it to work only for specified columns? (if yes, what do for
// VALUES()?)
c.__isset.value= true;
for(;fields->name; fields++)
{
c.name.assign(fields->name);
c.value.assign(fields->value, fields->value_len);
cass->insert(key, cparent, c, ConsistencyLevel::ONE);
}
} catch (...) {
res= true;
}
return res;
}
bool Cassandra_se_impl::get_slice(char *key, size_t key_len, NameAndValue *row, bool *found)
{
ColumnParent cparent;
cparent.column_family= column_family;
std::string rowkey_str;
rowkey_str.assign(key, key_len);
SlicePredicate slice_pred;
SliceRange sr;
sr.start = "";
sr.finish = "";
slice_pred.__set_slice_range(sr);
try {
std::vector<ColumnOrSuperColumn> &res= col_supercol_vec;
cass->get_slice(res, rowkey_str, cparent, slice_pred, ConsistencyLevel::ONE);
*found= true;
std::vector<ColumnOrSuperColumn>::iterator it;
if (res.size() == 0)
{
/*
No columns found. Cassandra doesn't allow records without any column =>
this means the seach key doesn't exist
*/
*found= false;
return false;
}
for (it= res.begin(); it < res.end(); it++)
{
ColumnOrSuperColumn cs= *it;
if (!cs.__isset.column)
return true;
row->name= (char*)cs.column.name.c_str();
row->value= (char*)cs.column.value.c_str();
row->value_len= cs.column.value.length();
row++;
}
row->name= NULL;
} catch (InvalidRequestException ire) {
return true;
} catch (UnavailableException ue) {
return true;
} catch (TimedOutException te) {
return true;
}
return false;
}
/*
This file is a "bridge" interface between cassandra+Thrift and MariaDB.
It is #included by both sides, so it must itself include neither (including
both together causes compile errors due to conflicts).
*/
/*
Storage for (name,value) pairs. name==NULL means 'non-object'.
This should be used for
- shipping data from sql to cassandra for INSERTs
- shipping data from cassandra to SQL for record reads.
*/
class NameAndValue
{
public:
char *name;
char *value;
size_t value_len;
};
/*
Interface to one cassandra column family, i.e. one 'table'
*/
class Cassandra_se_interface
{
public:
Cassandra_se_interface() { err_buffer[0]=0; }
virtual ~Cassandra_se_interface(){};
/* Init */
virtual bool connect(const char *host, const char *port)=0;
virtual void set_column_family(const char *cfname) = 0;
/* Check underlying DDL */
virtual bool setup_ddl_checks()=0;
virtual void first_ddl_column()=0;
virtual bool next_ddl_column(char **name, int *name_len, char **value,
int *value_len)=0;
/* Writes */
virtual bool insert(NameAndValue *fields)=0;
/* Reads */
virtual bool get_slice(char *key, size_t key_len, NameAndValue *row, bool *found)=0 ;
/* Passing error messages up to ha_cassandra */
char err_buffer[512];
const char *error_str() { return err_buffer; }
void print_error(const char *format, ...);
};
Cassandra_se_interface *get_cassandra_se();
This diff is collapsed.
This diff is collapsed.
// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.
#include "Cassandra.h"
#include <protocol/TBinaryProtocol.h>
#include <server/TSimpleServer.h>
#include <transport/TServerSocket.h>
#include <transport/TBufferTransports.h>
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using boost::shared_ptr;
using namespace ::org::apache::cassandra;
class CassandraHandler : virtual public CassandraIf {
public:
CassandraHandler() {
// Your initialization goes here
}
void login(const AuthenticationRequest& auth_request) {
// Your implementation goes here
printf("login\n");
}
void set_keyspace(const std::string& keyspace) {
// Your implementation goes here
printf("set_keyspace\n");
}
void get(ColumnOrSuperColumn& _return, const std::string& key, const ColumnPath& column_path, const ConsistencyLevel::type consistency_level) {
// Your implementation goes here
printf("get\n");
}
void get_slice(std::vector<ColumnOrSuperColumn> & _return, const std::string& key, const ColumnParent& column_parent, const SlicePredicate& predicate, const ConsistencyLevel::type consistency_level) {
// Your implementation goes here
printf("get_slice\n");
}
int32_t get_count(const std::string& key, const ColumnParent& column_parent, const SlicePredicate& predicate, const ConsistencyLevel::type consistency_level) {
// Your implementation goes here
printf("get_count\n");
}
void multiget_slice(std::map<std::string, std::vector<ColumnOrSuperColumn> > & _return, const std::vector<std::string> & keys, const ColumnParent& column_parent, const SlicePredicate& predicate, const ConsistencyLevel::type consistency_level) {
// Your implementation goes here
printf("multiget_slice\n");
}
void multiget_count(std::map<std::string, int32_t> & _return, const std::vector<std::string> & keys, const ColumnParent& column_parent, const SlicePredicate& predicate, const ConsistencyLevel::type consistency_level) {
// Your implementation goes here
printf("multiget_count\n");
}
void get_range_slices(std::vector<KeySlice> & _return, const ColumnParent& column_parent, const SlicePredicate& predicate, const KeyRange& range, const ConsistencyLevel::type consistency_level) {
// Your implementation goes here
printf("get_range_slices\n");
}
void get_paged_slice(std::vector<KeySlice> & _return, const std::string& column_family, const KeyRange& range, const std::string& start_column, const ConsistencyLevel::type consistency_level) {
// Your implementation goes here
printf("get_paged_slice\n");
}
void get_indexed_slices(std::vector<KeySlice> & _return, const ColumnParent& column_parent, const IndexClause& index_clause, const SlicePredicate& column_predicate, const ConsistencyLevel::type consistency_level) {
// Your implementation goes here
printf("get_indexed_slices\n");
}
void insert(const std::string& key, const ColumnParent& column_parent, const Column& column, const ConsistencyLevel::type consistency_level) {
// Your implementation goes here
printf("insert\n");
}
void add(const std::string& key, const ColumnParent& column_parent, const CounterColumn& column, const ConsistencyLevel::type consistency_level) {
// Your implementation goes here
printf("add\n");
}
void remove(const std::string& key, const ColumnPath& column_path, const int64_t timestamp, const ConsistencyLevel::type consistency_level) {
// Your implementation goes here
printf("remove\n");
}
void remove_counter(const std::string& key, const ColumnPath& path, const ConsistencyLevel::type consistency_level) {
// Your implementation goes here
printf("remove_counter\n");
}
void batch_mutate(const std::map<std::string, std::map<std::string, std::vector<Mutation> > > & mutation_map, const ConsistencyLevel::type consistency_level) {
// Your implementation goes here
printf("batch_mutate\n");
}
void truncate(const std::string& cfname) {
// Your implementation goes here
printf("truncate\n");
}
void describe_schema_versions(std::map<std::string, std::vector<std::string> > & _return) {
// Your implementation goes here
printf("describe_schema_versions\n");
}
void describe_keyspaces(std::vector<KsDef> & _return) {
// Your implementation goes here
printf("describe_keyspaces\n");
}
void describe_cluster_name(std::string& _return) {
// Your implementation goes here
printf("describe_cluster_name\n");
}
void describe_version(std::string& _return) {
// Your implementation goes here
printf("describe_version\n");
}
void describe_ring(std::vector<TokenRange> & _return, const std::string& keyspace) {
// Your implementation goes here
printf("describe_ring\n");
}
void describe_token_map(std::map<std::string, std::string> & _return) {
// Your implementation goes here
printf("describe_token_map\n");
}
void describe_partitioner(std::string& _return) {
// Your implementation goes here
printf("describe_partitioner\n");
}
void describe_snitch(std::string& _return) {
// Your implementation goes here
printf("describe_snitch\n");
}
void describe_keyspace(KsDef& _return, const std::string& keyspace) {
// Your implementation goes here
printf("describe_keyspace\n");
}
void describe_splits(std::vector<std::string> & _return, const std::string& cfName, const std::string& start_token, const std::string& end_token, const int32_t keys_per_split) {
// Your implementation goes here
printf("describe_splits\n");
}
void system_add_column_family(std::string& _return, const CfDef& cf_def) {
// Your implementation goes here
printf("system_add_column_family\n");
}
void system_drop_column_family(std::string& _return, const std::string& column_family) {
// Your implementation goes here
printf("system_drop_column_family\n");
}
void system_add_keyspace(std::string& _return, const KsDef& ks_def) {
// Your implementation goes here
printf("system_add_keyspace\n");
}
void system_drop_keyspace(std::string& _return, const std::string& keyspace) {
// Your implementation goes here
printf("system_drop_keyspace\n");
}
void system_update_keyspace(std::string& _return, const KsDef& ks_def) {
// Your implementation goes here
printf("system_update_keyspace\n");
}
void system_update_column_family(std::string& _return, const CfDef& cf_def) {
// Your implementation goes here
printf("system_update_column_family\n");
}
void execute_cql_query(CqlResult& _return, const std::string& query, const Compression::type compression) {
// Your implementation goes here
printf("execute_cql_query\n");
}
void prepare_cql_query(CqlPreparedResult& _return, const std::string& query, const Compression::type compression) {
// Your implementation goes here
printf("prepare_cql_query\n");
}
void execute_prepared_cql_query(CqlResult& _return, const int32_t itemId, const std::vector<std::string> & values) {
// Your implementation goes here
printf("execute_prepared_cql_query\n");
}
void set_cql_version(const std::string& version) {
// Your implementation goes here
printf("set_cql_version\n");
}
};
int main(int argc, char **argv) {
int port = 9090;
shared_ptr<CassandraHandler> handler(new CassandraHandler());
shared_ptr<TProcessor> processor(new CassandraProcessor(handler));
shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
server.serve();
return 0;
}
/**
* Autogenerated by Thrift Compiler (0.8.0)
*
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
* @generated
*/
#include "cassandra_constants.h"
namespace org { namespace apache { namespace cassandra {
const cassandraConstants g_cassandra_constants;
cassandraConstants::cassandraConstants() {
cassandra_const_VERSION = "19.32.0";
}
}}} // namespace
/**
* Autogenerated by Thrift Compiler (0.8.0)
*
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
* @generated
*/
#ifndef cassandra_CONSTANTS_H
#define cassandra_CONSTANTS_H
#include "cassandra_types.h"
namespace org { namespace apache { namespace cassandra {
class cassandraConstants {
public:
cassandraConstants();
// std::string VERSION;
char* cassandra_const_VERSION;
};
extern const cassandraConstants g_cassandra_constants;
}}} // namespace
#endif
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
/*
MP AB copyrights
*/
#ifdef USE_PRAGMA_INTERFACE
#pragma interface /* gcc class implementation */
#endif
#include "my_global.h" /* ulonglong */
#include "thr_lock.h" /* THR_LOCK, THR_LOCK_DATA */
#include "handler.h" /* handler */
#include "my_base.h" /* ha_rows */
#include "cassandra_se.h"
/** @brief
CASSANDRA_SHARE is a structure that will be shared among all open handlers.
This example implements the minimum of what you will probably need.
*/
typedef struct st_cassandra_share {
char *table_name;
uint table_name_length,use_count;
mysql_mutex_t mutex;
THR_LOCK lock;
} CASSANDRA_SHARE;
/** @brief
Class definition for the storage engine
*/
class ha_cassandra: public handler
{
THR_LOCK_DATA lock; ///< MySQL lock
CASSANDRA_SHARE *share; ///< Shared lock info
Cassandra_se_interface *se;
/* pre-allocated array of #fields elements */
NameAndValue *names_and_vals;
NameAndValue *get_names_and_vals();
public:
ha_cassandra(handlerton *hton, TABLE_SHARE *table_arg);
~ha_cassandra()
{
delete se;
}
/** @brief
The name that will be used for display purposes.
*/
const char *table_type() const { return "CASSANDRA"; }
/** @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 "HASH"; }
/** @brief
The file extensions.
*/
const char **bas_ext() const;
/** @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
{
/*
We are saying that this engine is just statement capable to have
an engine that can only handle statement-based logging. This is
used in testing.
*/
return HA_BINLOG_STMT_CAPABLE;
}
/** @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 0;
}
/** @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; }
/* Support only one Primary Key, for now */
uint max_supported_keys() const { return 1; }
uint max_supported_key_parts() const { return 1; }
/** @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 16*1024; /* just to return something*/ }
/* At the moment, we're ok with default handler::index_init() implementation. */
int index_read_map(uchar * buf, const uchar * key,
key_part_map keypart_map,
enum ha_rkey_function find_flag);
/** @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_example.cc.
Most of these methods are not obligatory, skip them and
MySQL will treat them as not implemented
*/
/** @brief
We implement this in ha_example.cc; it's a required method.
*/
int open(const char *name, int mode, uint test_if_locked); // required
/** @brief
We implement this in ha_example.cc; it's a required method.
*/
int close(void); // required
/** @brief
We implement this in ha_example.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_example.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_example.cc. It's not an obligatory method;
skip it and and MySQL will treat it as not implemented.
*/
int delete_row(const uchar *buf);
/** @brief
We implement this in ha_example.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_example.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_example.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_example.cc. It's not an obligatory method;
skip it and and MySQL will treat it as not implemented.
*/
int index_last(uchar *buf);
/** @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 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);
int delete_table(const char *from);
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
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment