polardbxengine/storage/xengine/api/xengine_api.cc

1609 lines
52 KiB
C++

/*
* Copyright (c) 2020, Alibaba Group Holding Limited
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "xengine_api.h"
#include <string>
#include <set>
#include <unordered_map>
#include "table.h"
#include "./xdb_cf_manager.h"
#include "./xdb_datadic.h"
#include "./ha_xengine.h"
// Export utilities functions from myx
namespace myx {
extern int xdb_normalize_tablename(const std::string &tablename,
std::string *const strbuf);
extern Xdb_dict_manager dict_manager;
extern Xdb_cf_manager cf_manager;
extern Xdb_ddl_manager ddl_manager;
extern xengine::util::TransactionDB *xdb;
} // namespace myx
// Static function for internal use.
namespace {
static int xengine_strcasecmp(const char *a, const char *b) {
if (!a) {
if (!b) {
return(0);
} else {
return(-1);
}
} else if (!b) {
return(1);
}
return my_strcasecmp(system_charset_info, a, b);
}
static xengine_col_type_t get_col_type(Field *field) {
static std::unordered_map<int64_t, xengine_col_type_t>
mysql_engine_map = {
{MYSQL_TYPE_DECIMAL, XENGINE_DECIMAL},
{MYSQL_TYPE_NEWDECIMAL, XENGINE_NEWDECIMAL},
{MYSQL_TYPE_TINY, XENGINE_INT},
{MYSQL_TYPE_SHORT, XENGINE_INT},
{MYSQL_TYPE_LONG, XENGINE_INT},
{MYSQL_TYPE_FLOAT, XENGINE_FLOAT},
{MYSQL_TYPE_DOUBLE, XENGINE_DOUBLE},
{MYSQL_TYPE_LONGLONG, XENGINE_INT},
{MYSQL_TYPE_INT24, XENGINE_INT},
{MYSQL_TYPE_VARCHAR, XENGINE_VARCHAR_ANYCHARSET},
{MYSQL_TYPE_TINY_BLOB, XENGINE_BLOB},
{MYSQL_TYPE_MEDIUM_BLOB, XENGINE_BLOB},
{MYSQL_TYPE_LONG_BLOB, XENGINE_BLOB},
{MYSQL_TYPE_BLOB, XENGINE_BLOB},
{MYSQL_TYPE_VAR_STRING, XENGINE_VARCHAR_ANYCHARSET},
{MYSQL_TYPE_DATETIME, XENGINE_DATETIME},
{MYSQL_TYPE_DATETIME2, XENGINE_DATETIME2},
};
xengine_col_type_t result = XENGINE_VARCHAR;
enum_field_types field_type = field->real_type();
auto it = mysql_engine_map.find(field_type);
if (it != mysql_engine_map.end()) {
result = it->second;
}
if (MYSQL_TYPE_STRING == field_type) {
if (field->flags & BINARY_FLAG) {
result = XENGINE_BINARY;
} else {
result = XENGINE_CHAR;
}
}
return result;
}
static uint32_t get_pk_index(const TABLE *const table,
const myx::Xdb_tbl_def *const table_def) {
return table->s->primary_key == MAX_INDEXES ? table_def->m_key_count - 1 :
table->s->primary_key;
}
static xengine_err_t get_unpack_info(
const char *db_value,
const char **output,
uint32_t *data_len) {
*output = db_value;
*data_len = myx::xdb_netbuf_to_uint16(
reinterpret_cast<const uchar *>(db_value + 1));
return DB_SUCCESS;
}
//unused function comment by beilou
#if 0
static xengine_err_t skip_unpack_info(
bool has_unpack_info,
const char *db_value,
int64_t *pos) {
if (has_unpack_info) {
*pos += myx::xdb_netbuf_to_uint16(
reinterpret_cast<const uchar *>(db_value + 1));
}
return DB_SUCCESS;
}
static xengine_err_t get_varchar_col(
const Field_varstring *field,
char *db_value,
const char **output) {
if (nullptr == db_value) {
return DB_INVALID_NULL;
}
/* field->length_bytes is 1 or 2 */
*output = db_value + field->length_bytes;
return DB_SUCCESS;
}
#endif
static xengine_err_t copy_varchar_col(
const Field_varstring *field,
const char *db_value,
char *output) {
if (nullptr == db_value || nullptr == output) {
return DB_INVALID_NULL;
}
uint32_t data_len;
/* field->length_bytes is 1 or 2 */
if (field->length_bytes == 1) {
data_len = (uchar)db_value[0];
} else {
DBUG_ASSERT(field->length_bytes == 2);
data_len = uint2korr(db_value);
}
memcpy(output, db_value, field->length_bytes);
if (data_len > field->field_length) {
/* The data on disk is longer than table DDL allows? */
return DB_DATA_MISMATCH;
}
memcpy(output + field->length_bytes, db_value + field->length_bytes,
data_len);
return DB_SUCCESS;
}
static xengine_err_t skip_varchar_col(
const Field_varstring *field,
const char *db_value,
int64_t *pos) {
if (nullptr == db_value) {
return DB_INVALID_NULL;
}
/* field->length_bytes is 1 or 2 */
*pos += field->length_bytes;
if (field->length_bytes == 1) {
*pos += (uchar)db_value[0];
} else {
DBUG_ASSERT(field->length_bytes == 2);
*pos += uint2korr(db_value);
}
return DB_SUCCESS;
}
static xengine_err_t get_varchar_col_length(const Field_varstring *field,
const char *db_value,
uint64_t *res) {
if (nullptr == db_value) {
return DB_INVALID_NULL;
}
if (field->length_bytes == 1) {
*res = (uchar)db_value[0];
} else {
*res = uint2korr(db_value);
}
return DB_SUCCESS;
}
static int64_t get_length_bytes(const Field_varstring *field) {
return field->length_bytes;
}
#define PORTABLE_SIZEOF_CHAR_PTR 8
//unused function, comment by beilou
#if 0
static xengine_err_t get_blob_col(const Field_blob *field,
char *db_value,
bool db_low_byte_first,
const char **output) {
if (nullptr == db_value) {
return DB_INVALID_NULL;
}
*output = db_value + field->pack_length_no_ptr();
return DB_SUCCESS;
}
#endif
static xengine_err_t copy_blob_col(const Field_blob *field,
const char *db_value,
bool db_low_byte_first,
char *output) {
if (nullptr == db_value || nullptr == output) {
return DB_INVALID_NULL;
}
uint32_t length_bytes = field->pack_length_no_ptr();
memcpy(output, db_value, length_bytes);
memset(output + length_bytes, 0, PORTABLE_SIZEOF_CHAR_PTR);
const char *blob_ptr = db_value + length_bytes;
memcpy(output + length_bytes, &blob_ptr, sizeof(char**));
return DB_SUCCESS;
}
static xengine_err_t skip_blob_col(const Field_blob *field,
const char *db_value,
bool db_low_byte_first,
int64_t *pos) {
if (nullptr == db_value) {
return DB_INVALID_NULL;
}
uint32_t length_bytes = field->pack_length_no_ptr();
uint64_t data_len = 0;
*pos += length_bytes;
memcpy(&data_len, db_value, length_bytes);
*pos += data_len;
return DB_SUCCESS;
}
static xengine_err_t get_blob_col_length(const Field_blob *field,
const char *db_value,
bool db_low_byte_first,
uint64_t *res) {
if (nullptr == db_value || nullptr == field) {
return DB_INVALID_NULL;
}
memcpy(res, db_value, field->pack_length_no_ptr());
return DB_SUCCESS;
}
static int64_t get_length_bytes(const Field_blob *field) {
return field->pack_length_no_ptr();
}
//unused function comment by beilou
#if 0
static xengine_err_t get_normal_col(const Field *field,
const char *db_value,
const char **output) {
if (nullptr == db_value || nullptr == output) {
return DB_INVALID_NULL;
}
*output = db_value;
return DB_SUCCESS;
}
#endif
static xengine_err_t copy_normal_col(const Field *field,
const char *db_value,
char *output) {
if (nullptr == db_value || nullptr == output) {
return DB_INVALID_NULL;
}
memcpy(output, db_value, field->pack_length_in_rec());
return DB_SUCCESS;
}
static xengine_err_t skip_normal_col(const Field *field,
const char *db_value,
int64_t *pos) {
if (nullptr == db_value) {
return DB_INVALID_NULL;
}
*pos += field->pack_length_in_rec();
return DB_SUCCESS;
}
static xengine_err_t get_normal_col_length(const Field *field,
const char *db_value,
uint64_t *res) {
if (nullptr == db_value || nullptr == res) {
return DB_INVALID_NULL;
}
*res = field->pack_length_in_rec();
return DB_SUCCESS;
}
//unused function comment by beilou
#if 0
static int64_t get_length_bytes(const Field *field) {
return 0;
}
#endif
static xengine_err_t xengine_tuple_copy_col(int64_t src_idx,
xengine_tuple_t *src,
int64_t idx,
xengine_tuple_t *tpl) {
uint64_t len = tpl->length_array_[idx] = src->length_array_[src_idx];
tpl->offset_array_[idx] = src->offset_array_[src_idx];
tpl->data_array_[idx] = src->data_array_[src_idx] - src->data_ + tpl->data_;
memcpy(tpl->data_array_[idx], src->data_array_[src_idx], len);
return DB_SUCCESS;
}
static xengine_err_t xengine_convert_value(std::set<uint32_t> &field_offset_set,
const char *row_value,
xengine_table_def_t table_def,
myx::Xdb_key_def *key_def,
xengine_tuple_t *result) {
const char *unpack_info = nullptr;
uint32_t unpack_info_len = 0;
auto table = static_cast<TABLE *>(table_def->table_);
int64_t pos = table_def->null_bytes_;
const char *null_bytes = row_value;
if (key_def->table_has_unpack_info(table)) {
get_unpack_info(row_value + pos, &unpack_info, &unpack_info_len);
pos += unpack_info_len;
}
// Parse and copy column one by one.
Field **field_array = reinterpret_cast<Field **>(table_def->field_array_);
for (int64_t k = 0; k < table_def->col_array_len_; ++k) {
// For unpacked key, don't call the skip...col function bscause this
// field is not in the value.
if (field_offset_set.find(static_cast<uint32_t>(k)) !=
field_offset_set.end()) {
continue;
}
const Field *field = field_array[k];
int64_t field_offset = field->ptr - table->record[0];
char *tpl_cursor = result->data_ + field_offset;
enum_field_types field_type = field->real_type();
result->offset_array_[k] = field_offset;
// null columns, fill default value.
int64_t null_byte_offset = table_def->null_byte_offset_array_[k];
unsigned char null_mask = table_def->null_mask_array_[k];
if (null_mask & (*(null_bytes + null_byte_offset))) {
const char *default_value = reinterpret_cast<const char *>(
table->s->default_values + field_offset);
memcpy(tpl_cursor, default_value, field->pack_length());
result->length_array_[k] = XENGINE_SQL_NULL;
result->data_array_[k] = nullptr;
continue;
}
// normal fill.
if (MYSQL_TYPE_BLOB == field_type) {
const Field_blob *blob_field = static_cast<const Field_blob *>(field);
copy_blob_col(blob_field, row_value + pos, true, tpl_cursor);
skip_blob_col(blob_field, row_value + pos, true, &pos);
get_blob_col_length(blob_field, tpl_cursor, true,
result->length_array_ + k);
result->data_array_[k] = *(reinterpret_cast<char**>(
tpl_cursor + get_length_bytes(blob_field)));
} else if (MYSQL_TYPE_VARCHAR == field_type) {
const Field_varstring *varchar_field =
static_cast<const Field_varstring *>(field);
copy_varchar_col(varchar_field, row_value + pos, tpl_cursor);
skip_varchar_col(varchar_field, row_value + pos, &pos);
get_varchar_col_length(varchar_field, tpl_cursor,
result->length_array_ + k);
result->data_array_[k] = tpl_cursor + get_length_bytes(varchar_field);
} else {
copy_normal_col(field, row_value + pos, tpl_cursor);
skip_normal_col(field, row_value + pos, &pos);
get_normal_col_length(field, tpl_cursor, result->length_array_ + k);
result->data_array_[k] = tpl_cursor;
}
}
return DB_SUCCESS;
}
// Malloc data for the member of xengine_tuple_t. Need a tuple instance created.
// This function will not set the content in offset_array_, length_array_ and
// data_array_.
// This function will only allocate once for all memoery requirements.
// The buffer can be divided into 4 continuous parts:
// [data_: col_buffer_size]
// [offset_array_: sizeof(int64_t) * col_array_len]
// [length_array_: sizeof(uint64_t) * col_array_len]
// [data_array_: sizeof(char*) * col_array_len]
static xengine_err_t xengine_create_tuple(int64_t col_array_len,
int64_t col_buffer_size,
xengine_tuple_t *tuple) {
// tuple will be sent to C code in X-KV and then free, so use malloc.
tuple->size_ = col_buffer_size;
int64_t offset_data = 0;
int64_t offset_offset =
offset_data + sizeof(tuple->data_[0]) * col_buffer_size;
int64_t offset_length =
offset_offset + sizeof(tuple->offset_array_[0]) * col_array_len;
int64_t offset_data_array =
offset_length + sizeof(tuple->length_array_[0]) * col_array_len;
int64_t offset_null_array =
offset_data_array + sizeof(tuple->data_array_[0]) * col_array_len;
int64_t offset_mask_array =
offset_null_array + sizeof(tuple->null_offset_array_[0]) * col_array_len;
int64_t total_mem_size =
offset_mask_array + sizeof(tuple->null_mask_array_[0]) * col_array_len;
void *mem = malloc(total_mem_size);
if (NULL == mem) {
return DB_OUT_OF_MEMORY;
}
memset(mem, 0x00, sizeof(char) * total_mem_size);
tuple->data_ = (char *) mem + offset_data;
tuple->offset_array_ = (int64_t *) ((char *) mem + offset_offset);
tuple->length_array_ = (uint64_t *) ((char *) mem + offset_length);
tuple->data_array_ = (char**) ((char *) mem + offset_data_array);
tuple->null_offset_array_ = (int64_t *) ((char *) mem + offset_null_array);
tuple->null_mask_array_ = (uchar *) ((char *) mem + offset_mask_array);
tuple->key_parts_ = 0;
tuple->buffer_ = nullptr;
return DB_SUCCESS;
}
static void xengine_free_tuple(xengine_tuple_t *tuple) {
if (NULL != tuple) {
free(tuple->data_);
delete static_cast<std::string*>(tuple->buffer_);
}
free(tuple);
}
static void xengine_free_iter(xengine_iter_t *iter) {
if (NULL != iter) {
free(iter->key_tuple_.data_);
delete static_cast<std::string*>(iter->key_tuple_.buffer_);
free(iter->value_tuple_.data_);
delete static_cast<std::string*>(iter->value_tuple_.buffer_);
free(iter->upper_bound_);
free(iter->lower_bound_);
delete static_cast<xengine::db::Iterator *>(iter->iter_);
}
free(iter);
}
// We construct the key tuple in the following rule:
// 1. Get the total buffer size including all columns in this table.
// 2. Create a buffer with the buffer size.
// 3. For each part of the key, find its column offset in the buffer.
// 4. Index these offset using increamental index from 0 in
// data_array_ and offset_array_
// The key tuple is different with value tuple. In a value tuple, the
// data_array_[i] and offset_array_[i] allway point to the i th column
// in the buffer. But in a key tuple, the data_array_[i] and offset_array_[i]
// will point to the real column of ths i th part of the key
static xengine_err_t xengine_bless_key_tuple(xengine_table_def_t table_def,
xengine_key_def_t key_def,
xengine_tuple_t *tuple,
int64_t key_parts) {
xengine_err_t result = DB_SUCCESS;
auto table = static_cast<TABLE *>(table_def->table_);
auto db_key_def = static_cast<myx::Xdb_key_def *>(key_def);
std::unique_ptr<Field*[]> field_array;
field_array.reset(new Field*[key_parts]);
for (int64_t i = 0; i < key_parts; ++i) {
Field *field = db_key_def->get_table_field_for_part_no(table, i);
field_array[i] = field;
}
int64_t col_num = table_def->col_array_len_;
int64_t buffer_size = table_def->col_buffer_size_;
result = xengine_create_tuple(col_num, buffer_size, tuple);
if (DB_SUCCESS != result) {
return result;
}
int64_t first_offset = field_array[0]->ptr - table->record[0];
memset(tuple->data_, 0x00, sizeof(tuple->data_[0]) * first_offset);
for (int64_t i = 0; i < key_parts; ++i) {
Field *field = field_array[i];
int64_t offset = field->ptr - table->record[0];
tuple->offset_array_[i] = offset;
int64_t length_bytes = 0;
enum_field_types field_type = field->real_type();
if (MYSQL_TYPE_BLOB == field_type) {
length_bytes = get_length_bytes(static_cast<Field_blob *>(field));
} else if (MYSQL_TYPE_VARCHAR == field_type) {
length_bytes = get_length_bytes(static_cast<Field_varstring *>(field));
}
tuple->data_array_[i] = tuple->data_ + offset + length_bytes;
if (MYSQL_TYPE_STRING == field_type) {
memset(tuple->data_array_[i], 0x20, field->pack_length_in_rec());
}
// Here, field->m_null_ptr and field->null_bit is nullptr and so useless.
uint16_t index = field->field_index;
tuple->null_offset_array_[i] = table_def->null_byte_offset_array_[index];
tuple->null_mask_array_[i] = table_def->null_mask_array_[index];
}
return result;
}
static xengine_err_t xengine_create_iter(xengine_table_def_t table_def,
xengine_key_def_t key_def,
xengine_iter_t **iter) {
auto db_key_def = static_cast<myx::Xdb_key_def *>(key_def);
auto db_table_def = static_cast<myx::Xdb_tbl_def *>(table_def->db_obj_);
auto table = static_cast<TABLE *>(table_def->table_);
int64_t value_col_num = table_def->col_array_len_;
int64_t value_buffer_size = table_def->col_buffer_size_;
uint32_t pk_parts =
static_cast<myx::Xdb_key_def *>(table_def->pk_def_)->get_key_parts();
xengine_iter_t *new_iter = (xengine_iter_t *) malloc(sizeof(xengine_iter_t));
if (NULL == new_iter) {
goto end;
}
new_iter->key_tuple_.data_ = NULL;
new_iter->value_tuple_.data_ = NULL;
if (myx::Xdb_key_def::INDEX_TYPE_PRIMARY == db_key_def->m_index_type) {
new_iter->seek_key_parts_ = pk_parts;
} else if (!db_key_def->table_has_hidden_pk(table)) {
new_iter->seek_key_parts_ = db_key_def->get_key_parts() - pk_parts;
} else {
new_iter->seek_key_parts_ = db_key_def->get_key_parts() - 1 /* hidden pk */;
}
if (DB_SUCCESS != xengine_bless_key_tuple(table_def, key_def,
&new_iter->key_tuple_,
new_iter->seek_key_parts_)) {
goto free_iter;
}
if (DB_SUCCESS != xengine_create_tuple(value_col_num, value_buffer_size,
&new_iter->value_tuple_)) {
goto free_key_tuple;
}
new_iter->upper_bound_ = (char *) malloc(
sizeof(char) * db_key_def->max_storage_fmt_length());
new_iter->upper_bound_size_ = 0;
if (NULL == new_iter->upper_bound_) {
goto free_value_tuple;
}
new_iter->lower_bound_ = (char *) malloc(
sizeof(char) * db_key_def->max_storage_fmt_length());
new_iter->lower_bound_size_ = 0;
if (NULL == new_iter->lower_bound_) {
goto free_upper_bound;
}
*iter = new_iter;
return DB_SUCCESS;
free_upper_bound:
free(new_iter->upper_bound_);
free_value_tuple:
xengine_free_tuple(&new_iter->value_tuple_);
free_key_tuple:
xengine_free_tuple(&new_iter->key_tuple_);
free_iter:
xengine_free_iter(new_iter);
end:
return DB_OUT_OF_MEMORY;
}
}; // namespace
using namespace xengine;
using namespace common;
xengine_err_t xengine_trx_start(xengine_trx_t *trx,
xengine_trx_level_t trx_level,
xengine_bool_t read_write,
xengine_bool_t auto_commit,
void *thd)
{
return DB_ERROR;
}
xengine_trx_t *xengine_trx_begin(xengine_trx_level_t trx_level,
xengine_bool_t read_write,
xengine_bool_t auto_commit) {
xengine_trx_t *new_trx = (xengine_trx_t *) malloc(sizeof(xengine_trx_t));
new_trx->db_snapshot_ = const_cast<void*>(static_cast<const void *>(
myx::xdb->GetSnapshot()));
return new_trx;
}
uint32_t xengine_trx_read_only(xengine_trx_t *trx) {
//TODO comment by beilou 5.7->8.0
//i don't know why there is a empty function, so just abort it
abort();
return 0;
}
xengine_err_t xengine_trx_release(xengine_trx_t *trx) {
if (trx != nullptr) {
auto snapshot = static_cast<xengine::db::Snapshot *>(trx->db_snapshot_);
myx::xdb->ReleaseSnapshot(snapshot);
free(trx);
}
return DB_SUCCESS;
}
xengine_err_t xengine_trx_commit(xengine_trx_t *xengine_trx) {
return DB_ERROR;
}
xengine_err_t xengine_trx_rollback(xengine_trx_t *xengine_trx) {
return DB_ERROR;
}
xengine_err_t xengine_open_table_using_id(xengine_id_u64_t table_id,
xengine_trx_t *xengine_trx,
xengine_request_t *xengine_crsr) {
return DB_ERROR;
}
xengine_err_t xengine_open_index_using_name(xengine_request_t req,
const char *index_name,
xengine_iter_t **iter,
int *idx_type,
xengine_id_u64_t *idx_id) {
xengine_err_t result = DB_SUCCESS;
auto db_table_def = static_cast<myx::Xdb_tbl_def*>(req->table_def_->db_obj_);
auto table = static_cast<TABLE *>(req->table_def_->table_);
myx::Xdb_key_def *db_key_def = nullptr;
for (size_t i = 0; i != db_table_def->m_key_count; ++i) {
db_key_def = db_table_def->m_key_descr_arr[i].get();
if (xengine_strcasecmp(db_key_def->get_name().data(), index_name) == 0) {
*idx_id = db_key_def->get_index_number();
*idx_type = db_key_def->m_index_type ==
myx::Xdb_key_def::INDEX_TYPE_PRIMARY ? XENGINE_CLUSTERED :
table->key_info[i].flags & HA_NOSAME ? XENGINE_UNIQUE:
XENGINE_SECONDARY;
break;
}
}
if (nullptr == db_key_def) {
return DB_NOT_FOUND;
}
xengine_iter_t *new_iter;
xengine_create_iter(req->table_def_, db_key_def, &new_iter);
// target index is found, create xengine iterator.
new_iter->key_def_ = static_cast<void *>(db_key_def);
myx::GL_INDEX_ID gl_index_id = db_key_def->get_gl_index_id();
new_iter->cf_id_ = gl_index_id.cf_id;
new_iter->index_number_ = db_key_def->get_index_number();
xengine::common::ReadOptions ro;
ro.total_order_seek = true;
xengine::db::ColumnFamilyHandle *cfh = db_key_def->get_cf();
new_iter->iter_ = static_cast<void *>(myx::xdb->NewIterator(ro, cfh));
new_iter->is_primary_ =
db_key_def->m_index_type == myx::Xdb_key_def::INDEX_TYPE_PRIMARY;
*iter = new_iter;
return result;
}
xengine_err_t xengine_open_table(const char *db_name,
const char *table_name,
void *thd,
void *mysql_table,
int64_t lock_type,
xengine_request_t *req) {
int64_t db_name_len = strlen(db_name);
int64_t table_name_len = strlen(table_name);
int64_t name_len = db_name_len + table_name_len + 1;
char *name_buffer = new char[name_len + 1];
std::unique_ptr<char[]> normalized_name {name_buffer};
memcpy(name_buffer, db_name, db_name_len);
name_buffer[db_name_len] = '.';
memcpy(name_buffer + db_name_len + 1, table_name, table_name_len);
bool from_dict = false;
auto tbl_def = myx::ddl_manager.find(name_buffer, name_len, &from_dict, false);
myx::Xdb_tbl_def *xdb_table_def = tbl_def.get();
if (nullptr == xdb_table_def) {
return DB_TABLE_NOT_FOUND;
}
myx::Xdb_key_def *xdb_key_def = xdb_table_def->m_key_descr_arr->get();
if (nullptr == xdb_key_def) {
return DB_NOT_FOUND;
}
// malloc and init xegnine_request
*req = (xengine_request_t) malloc(sizeof(xengine_request));
xengine_table_def_t table_def =
(xengine_table_def_t) malloc(sizeof(*((*req)->table_def_)));
table_def->db_name_ = db_name;
table_def->table_name_ = table_name;
table_def->db_name_len_ = strlen(db_name);
table_def->table_name_len_ = strlen(table_name);
table_def->db_obj_ = static_cast<void *>(xdb_table_def);
TABLE *table = static_cast<TABLE *>(mysql_table);
int64_t number_fields = table->s->fields;
table_def->col_array_len_ = number_fields;
table_def->col_array_len_ = number_fields;
table_def->col_name_array_ = (const char **) malloc(
sizeof(char *) * number_fields);
table_def->col_length_array_ = (int64_t *) malloc(
sizeof(int64_t) * number_fields);
table_def->field_array_ = (void **) malloc(
sizeof(void *) * number_fields);
table_def->null_byte_offset_array_ = (int64_t *) malloc(
sizeof(int64_t) * number_fields);
table_def->null_mask_array_ = (unsigned char *) malloc(
sizeof(unsigned char) * number_fields);
unsigned char current_null_mask = 0x1;
int64_t current_null_byte = 0;
table_def->col_buffer_size_ = 1;
for (uint32_t i = 0; i < number_fields; ++i) {
Field *const field = table->field[i];
table_def->col_buffer_size_ += field->pack_length();
table_def->col_name_array_[i] = field->field_name;
table_def->col_length_array_[i] = field->pack_length();
table_def->field_array_[i] = static_cast<void *>(field);
if (field->real_maybe_null()) {
table_def->null_mask_array_[i] = current_null_mask;
table_def->null_byte_offset_array_[i] = current_null_byte;
if (0x80 == current_null_mask) {
current_null_mask = 0x1;
current_null_byte += 1;
} else {
current_null_mask <<= 1;
}
} else {
table_def->null_mask_array_[i] = 0;
table_def->null_byte_offset_array_[i] = 0;
}
}
table_def->null_bytes_ = current_null_byte + (~current_null_mask & 1);
table_def->table_ = table;
uint32_t pk_index = get_pk_index(table, xdb_table_def);
myx::Xdb_key_def *key_def = xdb_table_def->m_key_descr_arr[pk_index].get();
table_def->pk_def_ = key_def;
table_def->pk_parts_ = key_def->get_key_parts();
(*req)->lock_type_ = lock_type;
(*req)->table_def_ = table_def;
(*req)->read_trx_ = nullptr;
(*req)->thd_ = thd;
return DB_SUCCESS;
}
void xengine_delete_tuple(xengine_tuple_t *tuple) {
xengine_free_tuple(tuple);
}
xengine_err_t xengine_close(xengine_request_t req) {
return DB_ERROR;
}
xengine_err_t xengine_close_table(xengine_request_t req) {
if (NULL != req) {
free(req->table_def_->col_name_array_);
free(req->table_def_->col_length_array_);
free(req->table_def_->field_array_);
free(req->table_def_->null_byte_offset_array_);
free(req->table_def_->null_mask_array_);
free(req->table_def_);
free(req);
}
return DB_SUCCESS;
}
xengine_err_t xengine_new_trx(xengine_request_t req,
xengine_trx_t *xengine_trx) {
return DB_ERROR;
}
xengine_err_t xengine_commit_trx(xengine_request_t req,
xengine_trx_t *xengine_trx) {
return DB_ERROR;
}
xengine_err_t xengine_insert_row(xengine_request_t req,
const xengine_tpl_t xengine_tpl) {
return DB_ERROR;
}
xengine_err_t xengine_update_row(xengine_request_t xengine_crsr,
const xengine_tpl_t xengine_old_tpl,
const xengine_tpl_t xengine_new_tpl) {
return DB_ERROR;
}
xengine_err_t xengine_delete_row(xengine_request_t xengine_crsr) {
return DB_ERROR;
}
// Read using PK.
xengine_err_t xengine_pk_search(xengine_request_t req,
xengine_tuple_t *key_tuple,
xengine_tuple_t *value_tuple) {
xengine_table_def_t table_def = req->table_def_;
auto pk_def = static_cast<myx::Xdb_key_def *>(table_def->pk_def_);
auto table = static_cast<TABLE *>(table_def->table_);
uint32_t pack_buffer_size = pk_def->max_storage_fmt_length();
std::unique_ptr<uchar[]> pack_buf {new uchar[pack_buffer_size]};
std::unique_ptr<char[]> pack_res {new char[pack_buffer_size]};
char *packed_key_data = pack_res.get();
int64_t key_parts = pk_def->get_key_parts();
uint32_t packed_key_size = pk_def->pack_record(table, pack_buf.get(),
reinterpret_cast<uchar *>(key_tuple->data_),
reinterpret_cast<uchar *>(packed_key_data),
nullptr, false, 0, key_parts, nullptr);
assert(packed_key_size <= pack_buffer_size);
Slice key(packed_key_data, packed_key_size);
ReadOptions ro;
std::string *row_value = value_tuple->buffer_ != nullptr ?
static_cast<std::string*>(value_tuple->buffer_) :
new std::string();
xengine_trx_t *trx = req->read_trx_;
if (trx != nullptr) {
ro.snapshot = static_cast<xengine::db::Snapshot *>(trx->db_snapshot_);
}
Status s = myx::xdb->Get(ro, pk_def->get_cf(), key, row_value);
if (!s.ok()) {
return DB_GET_ERROR;
}
std::set<uint32_t> field_id_set;
if (!pk_def->table_has_hidden_pk(table)) {
for (int64_t k = 0; k != pk_def->get_key_parts(); ++k) {
Field *field = pk_def->get_table_field_for_part_no(table, k);
uint16_t field_index = field->field_index;
xengine_tuple_copy_col(k, key_tuple, field_index, value_tuple);
field_id_set.insert(field_index);
}
}
value_tuple->buffer_ = static_cast<void*>(row_value);
// Parse and copy column one by one.
return xengine_convert_value(field_id_set, row_value->data(), table_def,
pk_def, value_tuple);
}
// Read from iter.
// When seach using SK, automatically switch to PK.
xengine_err_t xengine_read_row(xengine_request_t req,
xengine_iter_t *iter,
xengine_tpl_t cmp_tpl,
int mode,
void **row_buf,
xengine_ulint_t *row_len,
xengine_ulint_t *used_len) {
int64_t pos = 0;
auto db_iter = static_cast<xengine::db::Iterator *>(iter->iter_);
xengine_table_def_t table_def = req->table_def_;
if (nullptr == db_iter) {
assert(false);
return DB_INVALID_NULL;
}
xengine_tuple_t *tpl = &(iter->value_tuple_);
xengine::common::Slice value = db_iter->value();
xengine::common::Slice key = db_iter->key();
const char *db_value = value.data();
const char *null_bytes = db_value;
// Secondary index store null info just in field data position.
int64_t null_bytes_size = iter->is_primary_ ? table_def->null_bytes_ : 0;
const char *unpack_info = nullptr;
uint32_t unpack_info_len = 0;
TABLE *table = static_cast<TABLE *>(table_def->table_);
myx::Xdb_key_def *key_def = static_cast<myx::Xdb_key_def *>(iter->key_def_);
pos += null_bytes_size;
if (key_def->table_has_unpack_info(table)) {
get_unpack_info(db_value + pos, &unpack_info, &unpack_info_len);
pos += unpack_info_len;
xengine::common::Slice unpack_slice(unpack_info, unpack_info_len);
if (key_def->unpack_record(table,
reinterpret_cast<unsigned char *>(tpl->data_),
&key, unpack_info ? &unpack_slice : nullptr,
false /* verify_checksum */)) {
return DB_UNPACK_ERROR;
}
} else if (key_def->unpack_record_1(table,
reinterpret_cast<unsigned char *>(tpl->data_),
&key, nullptr, false /* verify_checksum */)) {
return DB_UNPACK_ERROR;
}
// Read from secondary key to get PK and then call db->Get using PK.
std::string *row_value = tpl->buffer_ != nullptr ?
static_cast<std::string*>(tpl->buffer_) :
new std::string();
if (!(iter->is_primary_)) {
myx::Xdb_key_def *pk_def =
static_cast<myx::Xdb_key_def *> (table_def->pk_def_);
uint32_t pk_len = key_def->get_primary_key_tuple(table, *pk_def, &key,
reinterpret_cast<unsigned char *>(iter->key_tuple_.data_));
xengine::common::Slice row_key(iter->key_tuple_.data_, pk_len);
xengine::common::ReadOptions ro;
xengine_trx_t *trx = req->read_trx_;
// Must access the referenced PK row in the same snapshot.
if (nullptr == trx) {
return DB_SNAPSHOT_ERROR;
}
ro.snapshot = static_cast<xengine::db::Snapshot *>(trx->db_snapshot_);
xengine::common::Status status =
myx::xdb->Get(ro, pk_def->get_cf(), row_key, row_value);
if (!status.ok()) {
return DB_GET_ERROR;
}
// For hidden PK, value contains all fields.
// So fill field_d_set with only PK.
key_def = pk_def;
db_value = row_value->data();
}
std::set<uint32_t> field_id_set;
if (!key_def->table_has_hidden_pk(table)) {
for (int64_t k = 0; k != key_def->get_key_parts(); ++k) {
Field *field = key_def->get_table_field_for_part_no(table, k);
char *tpl_cursor = field->ptr - table->record[0] + tpl->data_;
uint16_t field_index = field->field_index;
field_id_set.insert(field_index);
enum_field_types field_type = field->real_type();
if (MYSQL_TYPE_BLOB == field_type) {
auto blob_field = static_cast<const Field_blob *>(field);
get_blob_col_length(blob_field, tpl_cursor, true,
tpl->length_array_ + field_index);
tpl->data_array_[field_index] =
tpl_cursor + get_length_bytes(blob_field);
} else if (MYSQL_TYPE_VARCHAR == field_type) {
auto varchar_field = static_cast<const Field_varstring *>(field);
get_varchar_col_length(varchar_field, tpl_cursor,
tpl->length_array_ + field_index);
tpl->data_array_[field_index] =
tpl_cursor + get_length_bytes(varchar_field);
} else {
get_normal_col_length(field, tpl_cursor,
tpl->length_array_ + field_index);
tpl->data_array_[field_index] = tpl_cursor;
}
}
}
// Parse and copy column one by one.
tpl->buffer_ = static_cast<void*>(row_value);
return xengine_convert_value(field_id_set, db_value, table_def, key_def, tpl);
}
xengine_err_t xengine_iter_valid(xengine_iter_t *iter) {
auto db_key_def = static_cast<myx::Xdb_key_def *>(iter->key_def_);
auto db_iter = static_cast<xengine::db::Iterator *>(iter->iter_);
xengine_err_t result = DB_SUCCESS;
if (!db_iter->Valid() || !db_key_def->covers_key(db_iter->key())) {
result = DB_END_OF_INDEX;
} else {
xengine::common::Slice current_key = db_iter->key();
// If iter->upper_bound_size_ is 0, memcmp return 0.
uint64_t cmp_size = std::min(current_key.size(), iter->upper_bound_size_);
if (memcmp(current_key.data(), iter->upper_bound_, cmp_size) > 0) {
result = DB_END_OF_INDEX;
}
}
return result;
}
xengine_err_t xengine_iter_first(xengine_iter_t *iter) {
xengine_err_t result = DB_SUCCESS;
assert(iter != nullptr);
auto db_iter = static_cast<xengine::db::Iterator *>(iter->iter_);
if (db_iter != nullptr && iter->key_def_ != nullptr) {
uchar first_key[myx::Xdb_key_def::INDEX_NUMBER_SIZE];
uint first_key_size = 0;
auto db_key_def = static_cast<myx::Xdb_key_def *>(iter->key_def_);
db_key_def->get_infimum_key(first_key, &first_key_size);
uchar* key_ptr = first_key;
db_iter->Seek(xengine::common::Slice(
reinterpret_cast<const char *>(key_ptr), first_key_size));
result = xengine_iter_valid(iter);
} else {
assert(false);
result = DB_INVALID_NULL;
}
return result;
}
xengine_err_t xengine_iter_next(xengine_iter_t *iter) {
xengine_err_t result = DB_SUCCESS;
auto db_key_def = static_cast<myx::Xdb_key_def *>(iter->key_def_);
auto db_iter = static_cast<xengine::db::Iterator *>(iter->iter_);
if (db_iter != nullptr) {
db_iter->Next();
result = xengine_iter_valid(iter);
} else {
assert(false);
result = DB_INVALID_NULL;
}
return result;
}
xengine_err_t xengine_iter_seek(xengine_request_t req,
xengine_tpl_t tpl,
xengine_iter_t *iter,
xengine_srch_mode_t xengine_srch_mode,
xengine_ulint_t direction) {
xengine_err_t result = DB_SUCCESS;
auto db_key_def = static_cast<myx::Xdb_key_def *>(iter->key_def_);
auto table = static_cast<TABLE *>(req->table_def_->table_);
uint32_t pack_buffer_size = db_key_def->max_storage_fmt_length();
std::unique_ptr<uchar[]> pack_buf {new uchar[pack_buffer_size]};
std::unique_ptr<char[]> pack_res {new char[pack_buffer_size]};
char *packed_key_data = pack_res.get();
int64_t key_parts = tpl->key_parts_;
if (key_parts == 0) {
key_parts = iter->seek_key_parts_;
}
assert(key_parts <= iter->seek_key_parts_);
uint32_t packed_key_size = db_key_def->pack_record(table, pack_buf.get(),
reinterpret_cast<uchar *>(tpl->data_),
reinterpret_cast<uchar *>(packed_key_data),
nullptr, false, 0, key_parts, nullptr);
assert(packed_key_size <= pack_buffer_size);
memcpy(iter->upper_bound_, packed_key_data, packed_key_size);
iter->upper_bound_size_ = packed_key_size;
auto db_iter = static_cast<xengine::db::Iterator *>(iter->iter_);
if (db_iter != nullptr) {
xengine::common::Slice key(packed_key_data, packed_key_size);
db_iter->Seek(key);
} else {
assert(false);
result = DB_INVALID_NULL;
}
if (DB_SUCCESS == result) {
result = xengine_iter_valid(iter);
}
return result;
}
void xengine_set_match_mode(xengine_request_t req,
xengine_match_mode_t match_mode) {
if (req != nullptr) {
req->match_mode_ = match_mode;
}
}
xengine_err_t xengine_col_set_value(xengine_tuple_t *tpl,
xengine_ulint_t col,
const void *src,
xengine_ulint_t len,
xengine_bool_t need_cpy) {
// TODO @zhencheng: process need_cpy
if (len != XENGINE_SQL_NULL) {
assert(src != nullptr);
memcpy(tpl->data_array_[col], src, len);
// Not equal means this field has length parts.
int64_t field_offset = tpl->offset_array_[col];
int64_t len_len = tpl->data_array_[col] - tpl->data_ - field_offset;
// Assume little endian.
memcpy(tpl->data_ + field_offset, &len, len_len);
} else {
tpl->data_[tpl->null_offset_array_[col]] |= tpl->null_mask_array_[col];
}
// For null fields, only set the len to XENGINE_SQL_NULL
tpl->length_array_[col] = len;
return DB_SUCCESS;
}
xengine_ulint_t xengine_col_get_len(xengine_tpl_t xengine_tpl,
xengine_ulint_t i) {
abort(); //TODO add by beilou 5.7->8.0
return 0;
}
xengine_ulint_t xengine_col_copy_value(xengine_tpl_t xengine_tpl,
xengine_ulint_t i,
void *dst,
xengine_ulint_t len) {
abort(); //TODO add by beilou 5.7->8.0
return 0;
}
xengine_err_t xengine_tuple_read_i8(xengine_tpl_t tpl,
xengine_ulint_t i,
xengine_i8_t *ival) {
*ival = *(reinterpret_cast<xengine_i8_t *>(tpl->data_array_[i]));
return DB_ERROR;
}
xengine_err_t xengine_tuple_read_u8(xengine_tpl_t tpl,
xengine_ulint_t i,
xengine_u8_t *ival) {
*ival = *(reinterpret_cast<xengine_u8_t *>(tpl->data_array_[i]));
return DB_SUCCESS;
}
xengine_err_t xengine_tuple_read_i16(xengine_tpl_t tpl,
xengine_ulint_t i,
xengine_i16_t *ival) {
*ival = *(reinterpret_cast<xengine_i16_t *>(tpl->data_array_[i]));
return DB_SUCCESS;
}
xengine_err_t xengine_tuple_read_u16(xengine_tpl_t tpl,
xengine_ulint_t i,
xengine_u16_t *ival) {
*ival = *(reinterpret_cast<xengine_u16_t *>(tpl->data_array_[i]));
return DB_SUCCESS;
}
xengine_err_t xengine_tuple_read_i24(xengine_tpl_t tpl,
xengine_ulint_t i,
xengine_i32_t *ival) {
*ival = *(reinterpret_cast<xengine_i32_t *>(tpl->data_array_[i]));
return DB_SUCCESS;
}
xengine_err_t xengine_tuple_read_u24(xengine_tpl_t tpl,
xengine_ulint_t i,
xengine_u32_t *ival) {
*ival = *(reinterpret_cast<xengine_i32_t *>(tpl->data_array_[i]));
return DB_SUCCESS;
}
xengine_err_t xengine_tuple_read_i32(xengine_tpl_t tpl,
xengine_ulint_t i,
xengine_i32_t *ival) {
*ival = *(reinterpret_cast<xengine_i32_t *>(tpl->data_array_[i]));
return DB_SUCCESS;
}
xengine_err_t xengine_tuple_read_u32(xengine_tpl_t tpl,
xengine_ulint_t i,
xengine_u32_t *ival) {
*ival = *(reinterpret_cast<xengine_i32_t *>(tpl->data_array_[i]));
return DB_SUCCESS;
}
xengine_err_t xengine_tuple_read_i64(xengine_tpl_t tpl,
xengine_ulint_t i,
xengine_i64_t *ival) {
*ival = *(reinterpret_cast<xengine_i64_t *>(tpl->data_array_[i]));
return DB_SUCCESS;
}
xengine_err_t xengine_tuple_read_u64(xengine_tpl_t tpl,
xengine_ulint_t i,
xengine_u64_t *ival) {
*ival = *(reinterpret_cast<xengine_u64_t *>(tpl->data_array_[i]));
return DB_SUCCESS;
}
const void *xengine_col_get_value(xengine_tuple_t *tpl,
xengine_ulint_t i) {
return static_cast<void*>(tpl->data_array_[i]);
}
xengine_ulint_t xengine_col_get_meta(xengine_request_t req,
xengine_tuple_t *tpl,
xengine_ulint_t i,
xengine_col_meta_t *col_meta) {
Field *field = reinterpret_cast<Field**>(req->table_def_->field_array_)[i];
col_meta->type = get_col_type(field);
uint16_t type = col_meta->client_type = col_meta->prtype = field->real_type();
col_meta->type_len = field->pack_length();
col_meta->attr = XENGINE_COL_NONE;
if (field->flags & UNSIGNED_FLAG) {
col_meta->attr |= XENGINE_COL_UNSIGNED;
}
if (nullptr == tpl) {
return 0;
}
const char *null_bytes = tpl->data_;
int64_t null_byte_offset = req->table_def_->null_byte_offset_array_[i];
unsigned char null_mask = req->table_def_->null_mask_array_[i];
if (null_mask & (*(null_bytes + null_byte_offset))) {
return XENGINE_SQL_NULL;
}
return static_cast<xengine_ulint_t>(tpl->length_array_[i]);
}
void xengine_tuple_clear(xengine_iter_t **iter,
xengine_tuple_t **tpl) {
xengine_free_iter(*iter);
xengine_free_tuple(*tpl);
}
xengine_err_t xengine_tuple_get_cluster_key(xengine_request_t xengine_crsr,
xengine_tpl_t *xengine_dst_tpl,
const xengine_tpl_t xengine_src_tpl) {
return DB_UNSUPPORTED;
}
xengine_err_t xengine_key_tuple_create(xengine_request_t req,
xengine_key_def_t key_def,
int64_t key_part,
xengine_tuple_t **tuple) {
xengine_err_t result = DB_SUCCESS;
xengine_tuple_t *new_tuple =
(xengine_tuple_t *) malloc(sizeof(xengine_tuple_t));
result = xengine_bless_key_tuple(req->table_def_, key_def,
new_tuple, key_part);
if (DB_SUCCESS != result) {
return result;
}
*tuple = new_tuple;
return DB_SUCCESS;
}
xengine_err_t xengine_value_tuple_create(xengine_table_def_t table_def,
xengine_tuple_t **tuple) {
auto new_tuple = (xengine_tuple_t *) malloc(sizeof(xengine_tuple_t));
int64_t col_num = table_def->col_array_len_;
int64_t buffer_size = table_def->col_buffer_size_;
xengine_create_tuple(col_num, buffer_size, new_tuple);
*tuple = new_tuple;
return DB_SUCCESS;
}
xengine_err_t xengine_sec_iter_create(xengine_request_t req,
const char *index_name,
xengine_iter_t **iter) {
if (NULL == iter || NULL == req->table_def_) {
assert(false);
return DB_INVALID_NULL;
}
xengine_iter_t *new_iter;
auto db_table_def = static_cast<myx::Xdb_tbl_def *>(req->table_def_->db_obj_);
myx::Xdb_key_def *db_key_def = nullptr;
for (size_t i = 0; i != db_table_def->m_key_count; ++i) {
db_key_def = db_table_def->m_key_descr_arr[i].get();
if (0 == xengine_strcasecmp(db_key_def->get_name().data(), index_name)) {
break;
}
}
if (nullptr == db_key_def) {
return DB_NOT_FOUND;
}
xengine_create_iter(req->table_def_, db_key_def, &new_iter);
new_iter->key_def_ = static_cast<void *>(db_key_def);
myx::GL_INDEX_ID gl_index_id = db_key_def->get_gl_index_id();
new_iter->cf_id_ = gl_index_id.cf_id;
new_iter->index_number_ = gl_index_id.index_id;
xengine::common::ReadOptions ro;
ro.total_order_seek = true;
xengine_trx_t *trx = req->read_trx_;
if (trx != nullptr) {
ro.snapshot = static_cast<xengine::db::Snapshot *>(trx->db_snapshot_);
}
xengine::db::ColumnFamilyHandle *cfh = db_key_def->get_cf();
new_iter->iter_ = static_cast<void *>(myx::xdb->NewIterator(ro, cfh));
new_iter->is_primary_ = false;
*iter = new_iter;
return DB_SUCCESS;
}
xengine_err_t xengine_clust_iter_create(xengine_request_t req, xengine_iter_t **iter) {
if (NULL == iter || NULL == req->table_def_) {
assert(false);
return DB_INVALID_NULL;
}
xengine_iter_t *new_iter;
auto db_table_def = static_cast<myx::Xdb_tbl_def *>(req->table_def_->db_obj_);
auto db_key_def = static_cast<myx::Xdb_key_def *>(req->table_def_->pk_def_);
xengine_create_iter(req->table_def_, db_key_def, &new_iter);
new_iter->key_def_ = static_cast<void *>(db_key_def);
myx::GL_INDEX_ID gl_index_id = db_key_def->get_gl_index_id();
new_iter->cf_id_ = gl_index_id.cf_id;
new_iter->index_number_ = gl_index_id.index_id;
xengine::common::ReadOptions ro;
ro.total_order_seek = true;
xengine_trx_t *trx = req->read_trx_;
if (trx != nullptr) {
ro.snapshot = static_cast<xengine::db::Snapshot *>(trx->db_snapshot_);
}
xengine::db::ColumnFamilyHandle *cfh = db_key_def->get_cf();
new_iter->iter_ = static_cast<void *>(myx::xdb->NewIterator(ro, cfh));
new_iter->is_primary_ = true;
*iter = new_iter;
return DB_SUCCESS;
}
// The primary key is one part of the key tuple. Don't include primary key
// part for the range scan condition in X-KV.
xengine_ulint_t xengine_iter_get_n_user_cols(const xengine_iter_t *iter) {
return iter->seek_key_parts_;
}
xengine_ulint_t xengine_iter_get_n_cols(const xengine_iter_t *iter) {
auto db_key_def = static_cast<myx::Xdb_key_def *>(iter->key_def_);
return db_key_def->get_key_parts();
}
void xengine_tuple_set_n_fields_cmp(const xengine_tpl_t tpl,
uint32_t n_fields_cmp) {
tpl->key_parts_ = static_cast<int64_t>(n_fields_cmp);
}
void xengine_delete_iter(xengine_iter_t *iter) {
xengine_free_iter(iter);
}
xengine_err_t xengine_clust_search_tuple_create(xengine_request_t req,
xengine_iter_t *iter) {
return DB_UNSUPPORTED;
}
xengine_err_t xengine_truncate(xengine_request_t *xengine_crsr,
xengine_id_u64_t *table_id) {
return DB_ERROR;
}
xengine_err_t xengine_table_get_id(const char *table_name,
xengine_id_u64_t *table_id) {
return DB_ERROR;
}
xengine_bool_t xengine_is_positioned(const xengine_request_t xengine_crsr) {
abort();//TODO add by beilou
return false;
}
xengine_bool_t xengine_schema_lock_is_exclusive(
const xengine_trx_t *xengine_trx) {
abort();//TODO add by beilou
return false;
}
xengine_err_t xengine_lock(xengine_request_t xengine_crsr,
xengine_lck_mode_t xengine_lck_mode) {
return DB_ERROR;
}
xengine_err_t xengine_table_lock(xengine_trx_t *xengine_trx,
xengine_id_u64_t table_id,
xengine_lck_mode_t xengine_lck_mode) {
return DB_ERROR;
}
xengine_err_t xengine_set_lock_mode(
xengine_request_t xengine_crsr,
xengine_lck_mode_t xengine_lck_mode) {
abort(); //TODO add by beilou
return DB_SUCCESS;
}
void xengine_set_cluster_access(xengine_request_t xengine_crsr) {
}
void xengine_stmt_begin(xengine_request_t xengine_crsr) {
}
xengine_err_t xengine_tuple_write_double(xengine_tpl_t xengine_tpl,
int col_no,
double val) {
return DB_ERROR;
}
xengine_err_t xengine_tuple_read_double(xengine_tpl_t tpl,
xengine_ulint_t col_no,
double *dval) {
*dval = *(reinterpret_cast<double *>(tpl->data_array_[col_no]));
return DB_SUCCESS;
}
xengine_err_t xengine_tuple_write_float(xengine_tpl_t xengine_tpl,
int col_no,
float val) {
return DB_ERROR;
}
xengine_err_t xengine_tuple_read_float(xengine_tpl_t tpl,
xengine_ulint_t col_no,
float *fval) {
*fval = *(reinterpret_cast<float *>(tpl->data_array_[col_no]));
return DB_SUCCESS;
}
const char *xengine_col_get_name(xengine_request_t req,
xengine_ulint_t i) {
return req->table_def_->col_name_array_[i];
}
const char *xengine_get_idx_field_name(xengine_request_t req,
xengine_iter_t *iter,
xengine_ulint_t i) {
auto db_key_def = static_cast<myx::Xdb_key_def*>(iter->key_def_);
Field *field = db_key_def->get_table_field_for_part_no(
static_cast<TABLE *>(req->table_def_->table_), i);
return field->field_name;
}
xengine_err_t xengine_table_truncate(const char *table_name,
xengine_id_u64_t *table_id) {
return DB_ERROR;
}
int xengine_cfg_get_cfg() {
return 0;
}
xengine_err_t xengine_set_memcached_sync(xengine_request_t xengine_crsr,
xengine_bool_t flag) {
return DB_ERROR;
}
xengine_trx_level_t xengine_cfg_trx_level() {
abort();//TODO add by beilou
return XENGINE_TRX_READ_COMMITTED;
}
xengine_ulint_t xengine_cfg_bk_commit_interval() {
return 0;
}
xengine_u64_t xengine_trx_get_start_time(xengine_trx_t *xengine_trx) {
return 0;
}
const char *xengine_ut_strerr(xengine_err_t num) {
switch (num) {
case DB_SUCCESS:
return "Success";
case DB_SUCCESS_LOCKED_REC:
return "Success, record lock created";
case DB_ERROR:
return "Generic error";
case DB_READ_ONLY:
return "Read only transaction";
case DB_INTERRUPTED:
return "Operation interrupted";
case DB_OUT_OF_MEMORY:
return "Cannot allocate memory";
case DB_OUT_OF_FILE_SPACE:
return "Out of disk space";
case DB_LOCK_WAIT:
return "Lock wait";
case DB_DEADLOCK:
return "Deadlock";
case DB_ROLLBACK:
return "Rollback";
case DB_DUPLICATE_KEY:
return "Duplicate key";
case DB_QUE_THR_SUSPENDED:
return "The queue thread has been suspended";
case DB_MISSING_HISTORY:
return "Required history data has been deleted";
case DB_CLUSTER_NOT_FOUND:
return "Cluster not found";
case DB_TABLE_NOT_FOUND:
return "Table not found";
case DB_MUST_GET_MORE_FILE_SPACE:
return "More file space needed";
case DB_TABLE_IS_BEING_USED:
return "Table is being used";
case DB_TOO_BIG_RECORD:
return "Record too big";
case DB_TOO_BIG_INDEX_COL:
return "Index columns size too big";
case DB_LOCK_WAIT_TIMEOUT:
return "Lock wait timeout";
case DB_NO_REFERENCED_ROW:
return "Referenced key value not found";
case DB_ROW_IS_REFERENCED:
return "Row is referenced";
case DB_CANNOT_ADD_CONSTRAINT:
return "Cannot add constraint";
case DB_CORRUPTION:
return "Data structure corruption";
case DB_CANNOT_DROP_CONSTRAINT:
return "Cannot drop constraint";
case DB_NO_SAVEPOINT:
return "No such savepoint";
case DB_TABLESPACE_EXISTS:
return "Tablespace already exists";
case DB_TABLESPACE_DELETED:
return "Tablespace deleted or being deleted";
case DB_TABLESPACE_TRUNCATED:
return "Tablespace was truncated";
case DB_TABLESPACE_NOT_FOUND:
return "Tablespace not found";
case DB_LOCK_TABLE_FULL:
return "Lock structs have exhausted the buffer pool";
case DB_FOREIGN_DUPLICATE_KEY:
return "Foreign key activated with duplicate keys";
case DB_FOREIGN_EXCEED_MAX_CASCADE:
return "Foreign key cascade delete/update exceeds max depth";
case DB_TOO_MANY_CONCURRENT_TRXS:
return "Too many concurrent transactions";
case DB_UNSUPPORTED:
return "Unsupported";
case DB_INVALID_NULL:
return "NULL value encountered in NOT NULL column";
case DB_STATS_DO_NOT_EXIST:
return "Persistent statistics do not exist";
case DB_FAIL:
return "Failed, retry may succeed";
case DB_OVERFLOW:
return "Overflow";
case DB_UNDERFLOW:
return "Underflow";
case DB_STRONG_FAIL:
return "Failed, retry will not succeed";
case DB_ZIP_OVERFLOW:
return "Zip overflow";
case DB_RECORD_NOT_FOUND:
return "Record not found";
case DB_CHILD_NO_INDEX:
return "No index on referencing keys in referencing table";
case DB_PARENT_NO_INDEX:
return "No index on referenced keys in referenced table";
case DB_FTS_INVALID_DOCID:
return "FTS Doc ID cannot be zero";
case DB_INDEX_CORRUPT:
return "Index corrupted";
case DB_UNDO_RECORD_TOO_BIG:
return "Undo record too big";
case DB_END_OF_INDEX:
return "End of index";
case DB_IO_ERROR:
return "I/O error";
case DB_TABLE_IN_FK_CHECK:
return "Table is being used in foreign key check";
case DB_DATA_MISMATCH:
return "data mismatch";
case DB_SCHEMA_NOT_LOCKED:
return "schema not locked";
case DB_SNAPSHOT_ERROR:
return "snapshot error";
case DB_UNPACK_ERROR:
return "unpack error";
case DB_GET_ERROR:
return "get error";
case DB_NOT_FOUND:
return "not found";
case DB_ONLINE_LOG_TOO_BIG:
return "Log size exceeded during online index creation";
case DB_IDENTIFIER_TOO_LONG:
return "Identifier name is too long";
case DB_FTS_EXCEED_RESULT_CACHE_LIMIT:
return "FTS query exceeds result cache limit";
case DB_TEMP_FILE_WRITE_FAIL:
return "Temp file write failure";
case DB_CANT_CREATE_GEOMETRY_OBJECT:
return "Can't create specificed geometry data object";
case DB_CANNOT_OPEN_FILE:
return "Cannot open a file";
case DB_TABLE_CORRUPT:
return "Table is corrupted";
case DB_FTS_TOO_MANY_WORDS_IN_PHRASE:
return "Too many words in a FTS phrase or proximity search";
case DB_IO_DECOMPRESS_FAIL:
return "Page decompress failed after reading from disk";
case DB_IO_NO_PUNCH_HOLE:
return "No punch hole support";
case DB_IO_NO_PUNCH_HOLE_FS:
return "Punch hole not supported by the file system";
case DB_IO_NO_PUNCH_HOLE_TABLESPACE:
return "Punch hole not supported by the tablespace";
case DB_IO_NO_ENCRYPT_TABLESPACE:
return "Page encryption not supported by the tablespace";
case DB_IO_DECRYPT_FAIL:
return "Page decryption failed after reading from disk";
case DB_IO_PARTIAL_FAILED:
return "Partial IO failed";
case DB_FORCED_ABORT:
return "Transaction aborted by another higher priority"
"transaction";
case DB_WRONG_FILE_NAME:
return "Invalid Filename";
case DB_NO_FK_ON_S_BASE_COL:
return "Cannot add foreign key on the base column"
"of stored column";
case DB_COMPUTE_VALUE_FAILED:
return "Compute generated column failed";
case DB_X_PROTOCOL_INVISIBLE_CONFIG:
return "X PROTOCOL: invisible config";
case DB_X_PROTOCOL_WRONG_VERSION:
return "X PROTOCOL: wrong version";
case DB_X_PROTOCOL_EINVAL:
return "X PROTOCL: invalid argument";
case DB_META_INVAL:
return "meta information in containers table is invalid";
case DB_RES_OVERFLOW:
return "result is overflow";
/* do not add default: in order to produce a warning if new code
is added to the enum but not added here */
}
/* NOT REACHED */
return "Unknown error";
}
xengine_bool_t xengine_is_virtual_table(xengine_request_t crsr) {
return false;
}
void xengine_set_tuple_key(xengine_tpl_t xengine_tpl) {
}