summaryrefslogtreecommitdiff
path: root/storage/mroonga/lib
diff options
context:
space:
mode:
authorKentoku SHIBA <kentokushiba@gmail.com>2014-09-21 00:33:45 +0900
committerKentoku SHIBA <kentokushiba@gmail.com>2014-09-21 00:33:45 +0900
commit0cc855cdc8cd0baa6ba50662632b299a3843ff13 (patch)
treeeaf50856703412b5c1c43f8c0e5a6a5318601c17 /storage/mroonga/lib
parent989dd4d9ec09450ff7b25987b14ee9fdfd21ad4e (diff)
downloadmariadb-git-0cc855cdc8cd0baa6ba50662632b299a3843ff13.tar.gz
Update Mroonga to the latest version on 2014-09-21T00:33:44+0900
Diffstat (limited to 'storage/mroonga/lib')
-rw-r--r--storage/mroonga/lib/Makefile.am23
-rw-r--r--storage/mroonga/lib/libmrn_need_mysql_sources.am25
-rw-r--r--storage/mroonga/lib/libmrn_no_mysql_sources.am8
-rw-r--r--storage/mroonga/lib/libmysqlservices_compat_sources.am2
-rw-r--r--storage/mroonga/lib/mrn_auto_increment_value_lock.cpp42
-rw-r--r--storage/mroonga/lib/mrn_auto_increment_value_lock.hpp36
-rw-r--r--storage/mroonga/lib/mrn_condition_converter.cpp608
-rw-r--r--storage/mroonga/lib/mrn_condition_converter.hpp82
-rw-r--r--storage/mroonga/lib/mrn_debug_column_access.cpp36
-rw-r--r--storage/mroonga/lib/mrn_debug_column_access.hpp38
-rw-r--r--storage/mroonga/lib/mrn_encoding.cpp222
-rw-r--r--storage/mroonga/lib/mrn_encoding.hpp35
-rw-r--r--storage/mroonga/lib/mrn_external_lock.cpp43
-rw-r--r--storage/mroonga/lib/mrn_external_lock.hpp38
-rw-r--r--storage/mroonga/lib/mrn_field_normalizer.cpp142
-rw-r--r--storage/mroonga/lib/mrn_field_normalizer.hpp47
-rw-r--r--storage/mroonga/lib/mrn_index_column_name.cpp96
-rw-r--r--storage/mroonga/lib/mrn_index_column_name.hpp43
-rw-r--r--storage/mroonga/lib/mrn_index_table_name.cpp89
-rw-r--r--storage/mroonga/lib/mrn_index_table_name.hpp43
-rw-r--r--storage/mroonga/lib/mrn_lock.cpp31
-rw-r--r--storage/mroonga/lib/mrn_lock.hpp36
-rw-r--r--storage/mroonga/lib/mrn_match_escalation_threshold_scope.cpp33
-rw-r--r--storage/mroonga/lib/mrn_match_escalation_threshold_scope.hpp35
-rw-r--r--storage/mroonga/lib/mrn_multiple_column_key_codec.cpp548
-rw-r--r--storage/mroonga/lib/mrn_multiple_column_key_codec.hpp70
-rw-r--r--storage/mroonga/lib/mrn_mysqlservices.cpp32
-rw-r--r--storage/mroonga/lib/mrn_parameters_parser.cpp176
-rw-r--r--storage/mroonga/lib/mrn_parameters_parser.hpp59
-rw-r--r--storage/mroonga/lib/mrn_path_mapper.cpp196
-rw-r--r--storage/mroonga/lib/mrn_path_mapper.hpp51
-rw-r--r--storage/mroonga/lib/mrn_smart_grn_obj.cpp53
-rw-r--r--storage/mroonga/lib/mrn_smart_grn_obj.hpp39
-rw-r--r--storage/mroonga/lib/mrn_time_converter.cpp260
-rw-r--r--storage/mroonga/lib/mrn_time_converter.hpp47
-rw-r--r--storage/mroonga/lib/mrn_windows.hpp31
36 files changed, 3395 insertions, 0 deletions
diff --git a/storage/mroonga/lib/Makefile.am b/storage/mroonga/lib/Makefile.am
new file mode 100644
index 00000000000..300131db70a
--- /dev/null
+++ b/storage/mroonga/lib/Makefile.am
@@ -0,0 +1,23 @@
+AM_CPPFLAGS = \
+ -I$(top_builddir) \
+ -I$(top_srcdir) \
+ $(MYSQL_INCLUDES) \
+ $(GROONGA_CFLAGS) \
+ $(MYSQL_VERSION_CFLAGS)
+
+libmrn_need_mysql_la_CXXFLAGS = $(AM_CXXFLAGS) $(MYSQL_CFLAGS)
+
+if WITH_LIBMYSQLSERVICES_COMPAT
+LIBMYSQLSERVICES_COMPAT = libmysqlservices.la
+endif
+
+noinst_LTLIBRARIES = \
+ $(LIBMYSQLSERVICES_COMPAT) \
+ libmrn_no_mysql.la \
+ libmrn_need_mysql.la
+
+include libmrn_no_mysql_sources.am
+include libmrn_need_mysql_sources.am
+if WITH_LIBMYSQLSERVICES_COMPAT
+include libmysqlservices_compat_sources.am
+endif
diff --git a/storage/mroonga/lib/libmrn_need_mysql_sources.am b/storage/mroonga/lib/libmrn_need_mysql_sources.am
new file mode 100644
index 00000000000..9dca2b6fb04
--- /dev/null
+++ b/storage/mroonga/lib/libmrn_need_mysql_sources.am
@@ -0,0 +1,25 @@
+libmrn_need_mysql_la_SOURCES = \
+ mrn_index_table_name.cpp \
+ mrn_index_table_name.hpp \
+ mrn_index_column_name.cpp \
+ mrn_index_column_name.hpp \
+ mrn_debug_column_access.cpp \
+ mrn_debug_column_access.hpp \
+ mrn_auto_increment_value_lock.cpp \
+ mrn_auto_increment_value_lock.hpp \
+ mrn_external_lock.cpp \
+ mrn_external_lock.hpp \
+ mrn_multiple_column_key_codec.cpp \
+ mrn_multiple_column_key_codec.hpp \
+ mrn_field_normalizer.cpp \
+ mrn_field_normalizer.hpp \
+ mrn_encoding.cpp \
+ mrn_encoding.hpp \
+ mrn_parameters_parser.cpp \
+ mrn_parameters_parser.hpp \
+ mrn_lock.cpp \
+ mrn_lock.hpp \
+ mrn_condition_converter.cpp \
+ mrn_condition_converter.hpp \
+ mrn_time_converter.cpp \
+ mrn_time_converter.hpp
diff --git a/storage/mroonga/lib/libmrn_no_mysql_sources.am b/storage/mroonga/lib/libmrn_no_mysql_sources.am
new file mode 100644
index 00000000000..89cfb277595
--- /dev/null
+++ b/storage/mroonga/lib/libmrn_no_mysql_sources.am
@@ -0,0 +1,8 @@
+libmrn_no_mysql_la_SOURCES = \
+ mrn_match_escalation_threshold_scope.cpp \
+ mrn_match_escalation_threshold_scope.hpp \
+ mrn_path_mapper.cpp \
+ mrn_path_mapper.hpp \
+ mrn_windows.hpp \
+ mrn_smart_grn_obj.cpp \
+ mrn_smart_grn_obj.hpp
diff --git a/storage/mroonga/lib/libmysqlservices_compat_sources.am b/storage/mroonga/lib/libmysqlservices_compat_sources.am
new file mode 100644
index 00000000000..bb0712a4add
--- /dev/null
+++ b/storage/mroonga/lib/libmysqlservices_compat_sources.am
@@ -0,0 +1,2 @@
+libmysqlservices_la_SOURCES = \
+ mrn_mysqlservices.cpp
diff --git a/storage/mroonga/lib/mrn_auto_increment_value_lock.cpp b/storage/mroonga/lib/mrn_auto_increment_value_lock.cpp
new file mode 100644
index 00000000000..3bac5e31c6c
--- /dev/null
+++ b/storage/mroonga/lib/mrn_auto_increment_value_lock.cpp
@@ -0,0 +1,42 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "mrn_auto_increment_value_lock.hpp"
+
+#if MYSQL_VERSION_ID >= 50500
+# define AUTO_INCREMENT_VALUE_MUTEX(table_share) (&(table_share->LOCK_ha_data))
+#else
+# define AUTO_INCREMENT_VALUE_MUTEX(table_share) (&(table_share->mutex))
+#endif
+
+namespace mrn {
+ AutoIncrementValueLock::AutoIncrementValueLock(TABLE_SHARE *table_share)
+ : table_share_(table_share),
+ need_lock_(table_share_->tmp_table == NO_TMP_TABLE) {
+ if (need_lock_) {
+ mysql_mutex_lock(AUTO_INCREMENT_VALUE_MUTEX(table_share_));
+ }
+ }
+
+ AutoIncrementValueLock::~AutoIncrementValueLock() {
+ if (need_lock_) {
+ mysql_mutex_unlock(AUTO_INCREMENT_VALUE_MUTEX(table_share_));
+ }
+ }
+}
diff --git a/storage/mroonga/lib/mrn_auto_increment_value_lock.hpp b/storage/mroonga/lib/mrn_auto_increment_value_lock.hpp
new file mode 100644
index 00000000000..8aabe6a8a7f
--- /dev/null
+++ b/storage/mroonga/lib/mrn_auto_increment_value_lock.hpp
@@ -0,0 +1,36 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MRN_AUTO_INCREMENT_VALUE_LOCK_HPP_
+#define MRN_AUTO_INCREMENT_VALUE_LOCK_HPP_
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+
+namespace mrn {
+ class AutoIncrementValueLock {
+ TABLE_SHARE *table_share_;
+ bool need_lock_;
+ public:
+ AutoIncrementValueLock(TABLE_SHARE *table_share);
+ ~AutoIncrementValueLock();
+ };
+}
+
+#endif // MRN_AUTO_INCREMENT_VALUE_LOCK_HPP_
diff --git a/storage/mroonga/lib/mrn_condition_converter.cpp b/storage/mroonga/lib/mrn_condition_converter.cpp
new file mode 100644
index 00000000000..1bfae1d4f8a
--- /dev/null
+++ b/storage/mroonga/lib/mrn_condition_converter.cpp
@@ -0,0 +1,608 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2014 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "mrn_condition_converter.hpp"
+#include "mrn_time_converter.hpp"
+#include "mrn_smart_grn_obj.hpp"
+
+// for debug
+#define MRN_CLASS_NAME "mrn::ConditionConverter"
+
+#ifdef MRN_ITEM_HAVE_ITEM_NAME
+# define MRN_ITEM_FIELD_GET_NAME(item) ((item)->item_name.ptr())
+# define MRN_ITEM_FIELD_GET_NAME_LENGTH(item) ((item)->item_name.length())
+#else
+# define MRN_ITEM_FIELD_GET_NAME(item) ((item)->name)
+# define MRN_ITEM_FIELD_GET_NAME_LENGTH(item) (strlen((item)->name))
+#endif
+
+namespace mrn {
+ ConditionConverter::ConditionConverter(grn_ctx *ctx, grn_obj *table,
+ bool is_storage_mode)
+ : ctx_(ctx),
+ table_(table),
+ is_storage_mode_(is_storage_mode) {
+ GRN_TEXT_INIT(&column_name_, 0);
+ GRN_VOID_INIT(&value_);
+ }
+
+ ConditionConverter::~ConditionConverter() {
+ grn_obj_unlink(ctx_, &column_name_);
+ grn_obj_unlink(ctx_, &value_);
+ }
+
+ bool ConditionConverter::is_convertable(const Item *item) {
+ MRN_DBUG_ENTER_METHOD();
+
+ if (!item) {
+ DBUG_RETURN(false);
+ }
+
+ switch (item->type()) {
+ case Item::COND_ITEM:
+ {
+ const Item_cond *cond_item = reinterpret_cast<const Item_cond *>(item);
+ bool convertable = is_convertable(cond_item);
+ DBUG_RETURN(convertable);
+ }
+ break;
+ case Item::FUNC_ITEM:
+ {
+ const Item_func *func_item = reinterpret_cast<const Item_func *>(item);
+ bool convertable = is_convertable(func_item);
+ DBUG_RETURN(convertable);
+ }
+ break;
+ default:
+ DBUG_RETURN(false);
+ break;
+ }
+
+ DBUG_RETURN(false);
+ }
+
+ bool ConditionConverter::is_convertable(const Item_cond *cond_item) {
+ MRN_DBUG_ENTER_METHOD();
+
+ if (!is_storage_mode_) {
+ DBUG_RETURN(false);
+ }
+
+ if (cond_item->functype() != Item_func::COND_AND_FUNC) {
+ DBUG_RETURN(false);
+ }
+
+ List<Item> *argument_list =
+ const_cast<Item_cond *>(cond_item)->argument_list();
+ List_iterator<Item> iterator(*argument_list);
+ const Item *sub_item;
+ while ((sub_item = iterator++)) {
+ if (!is_convertable(sub_item)) {
+ DBUG_RETURN(false);
+ }
+ }
+
+ DBUG_RETURN(true);
+ }
+
+ bool ConditionConverter::is_convertable(const Item_func *func_item) {
+ MRN_DBUG_ENTER_METHOD();
+
+ switch (func_item->functype()) {
+ case Item_func::EQ_FUNC:
+ case Item_func::LT_FUNC:
+ case Item_func::LE_FUNC:
+ case Item_func::GE_FUNC:
+ case Item_func::GT_FUNC:
+ if (!is_storage_mode_) {
+ DBUG_RETURN(false);
+ }
+ {
+ Item **arguments = func_item->arguments();
+ Item *left_item = arguments[0];
+ Item *right_item = arguments[1];
+ if (left_item->type() != Item::FIELD_ITEM) {
+ DBUG_RETURN(false);
+ }
+ if (!right_item->basic_const_item()) {
+ DBUG_RETURN(false);
+ }
+
+ bool convertable =
+ is_convertable_binary_operation(static_cast<Item_field *>(left_item),
+ right_item,
+ func_item->functype());
+ DBUG_RETURN(convertable);
+ }
+ break;
+ case Item_func::FT_FUNC:
+ DBUG_RETURN(true);
+ break;
+ case Item_func::BETWEEN:
+ if (!is_storage_mode_) {
+ DBUG_RETURN(false);
+ }
+ {
+ Item **arguments = func_item->arguments();
+ Item *target_item = arguments[0];
+ Item *min_item = arguments[1];
+ Item *max_item = arguments[2];
+ if (target_item->type() != Item::FIELD_ITEM) {
+ DBUG_RETURN(false);
+ }
+ if (!min_item->basic_const_item()) {
+ DBUG_RETURN(false);
+ }
+ if (!max_item->basic_const_item()) {
+ DBUG_RETURN(false);
+ }
+
+ bool convertable =
+ is_convertable_between(static_cast<Item_field *>(target_item),
+ min_item,
+ max_item);
+ DBUG_RETURN(convertable);
+ }
+ default:
+ DBUG_RETURN(false);
+ break;
+ }
+
+ DBUG_RETURN(true);
+ }
+
+ bool ConditionConverter::is_convertable_binary_operation(
+ const Item_field *field_item,
+ Item *value_item,
+ Item_func::Functype func_type) {
+ MRN_DBUG_ENTER_METHOD();
+
+ bool convertable = false;
+
+ enum_field_types field_type = field_item->field_type();
+ NormalizedType normalized_type = normalize_field_type(field_type);
+ switch (normalized_type) {
+ case STRING_TYPE:
+ if (value_item->type() == Item::STRING_ITEM &&
+ func_type == Item_func::EQ_FUNC) {
+ convertable = have_index(field_item, GRN_OP_EQUAL);
+ }
+ break;
+ case INT_TYPE:
+ convertable = value_item->type() == Item::INT_ITEM;
+ break;
+ case TIME_TYPE:
+ if (is_valid_time_value(field_item, value_item)) {
+ convertable = have_index(field_item, func_type);
+ }
+ break;
+ case UNSUPPORTED_TYPE:
+ break;
+ }
+
+ DBUG_RETURN(convertable);
+ }
+
+ bool ConditionConverter::is_convertable_between(const Item_field *field_item,
+ Item *min_item,
+ Item *max_item) {
+ MRN_DBUG_ENTER_METHOD();
+
+ bool convertable = false;
+
+ enum_field_types field_type = field_item->field_type();
+ NormalizedType normalized_type = normalize_field_type(field_type);
+ switch (normalized_type) {
+ case STRING_TYPE:
+ if (min_item->type() == Item::STRING_ITEM &&
+ max_item->type() == Item::STRING_ITEM) {
+ convertable = have_index(field_item, GRN_OP_LESS);
+ }
+ break;
+ case INT_TYPE:
+ if (min_item->type() == Item::INT_ITEM &&
+ max_item->type() == Item::INT_ITEM) {
+ convertable = have_index(field_item, GRN_OP_LESS);
+ }
+ break;
+ case TIME_TYPE:
+ if (is_valid_time_value(field_item, min_item) &&
+ is_valid_time_value(field_item, max_item)) {
+ convertable = have_index(field_item, GRN_OP_LESS);
+ }
+ break;
+ case UNSUPPORTED_TYPE:
+ break;
+ }
+
+ DBUG_RETURN(convertable);
+ }
+
+ bool ConditionConverter::is_valid_time_value(const Item_field *field_item,
+ Item *value_item) {
+ MRN_DBUG_ENTER_METHOD();
+
+ MYSQL_TIME mysql_time;
+ bool error = get_time_value(field_item, value_item, &mysql_time);
+
+ DBUG_RETURN(!error);
+ }
+
+ bool ConditionConverter::get_time_value(const Item_field *field_item,
+ Item *value_item,
+ MYSQL_TIME *mysql_time) {
+ MRN_DBUG_ENTER_METHOD();
+
+ bool error;
+ Item *real_value_item = value_item->real_item();
+ switch (field_item->field_type()) {
+ case MYSQL_TYPE_TIME:
+ error = real_value_item->get_time(mysql_time);
+ break;
+ case MYSQL_TYPE_YEAR:
+ mysql_time->year = static_cast<int>(value_item->val_int());
+ mysql_time->month = 1;
+ mysql_time->day = 1;
+ mysql_time->hour = 0;
+ mysql_time->hour = 0;
+ mysql_time->minute = 0;
+ mysql_time->second_part = 0;
+ mysql_time->neg = false;
+ mysql_time->time_type = MYSQL_TIMESTAMP_DATE;
+ error = false;
+ break;
+ default:
+ error = real_value_item->get_date(mysql_time, TIME_FUZZY_DATE);
+ break;
+ }
+
+ DBUG_RETURN(error);
+ }
+
+ ConditionConverter::NormalizedType
+ ConditionConverter::normalize_field_type(enum_field_types field_type) {
+ MRN_DBUG_ENTER_METHOD();
+
+ NormalizedType type = UNSUPPORTED_TYPE;
+
+ switch (field_type) {
+ case MYSQL_TYPE_DECIMAL:
+ type = STRING_TYPE;
+ break;
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ type = INT_TYPE;
+ break;
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ type = UNSUPPORTED_TYPE;
+ break;
+ case MYSQL_TYPE_NULL:
+ type = UNSUPPORTED_TYPE;
+ break;
+ case MYSQL_TYPE_TIMESTAMP:
+ type = TIME_TYPE;
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_INT24:
+ type = INT_TYPE;
+ break;
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_YEAR:
+ case MYSQL_TYPE_NEWDATE:
+ type = TIME_TYPE;
+ break;
+ case MYSQL_TYPE_VARCHAR:
+ type = STRING_TYPE;
+ break;
+ case MYSQL_TYPE_BIT:
+ type = INT_TYPE;
+ break;
+#ifdef MRN_HAVE_MYSQL_TYPE_TIMESTAMP2
+ case MYSQL_TYPE_TIMESTAMP2:
+ type = TIME_TYPE;
+ break;
+#endif
+#ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
+ case MYSQL_TYPE_DATETIME2:
+ type = TIME_TYPE;
+ break;
+#endif
+#ifdef MRN_HAVE_MYSQL_TYPE_TIME2
+ case MYSQL_TYPE_TIME2:
+ type = TIME_TYPE;
+ break;
+#endif
+ case MYSQL_TYPE_NEWDECIMAL:
+ type = STRING_TYPE;
+ break;
+ case MYSQL_TYPE_ENUM:
+ type = INT_TYPE;
+ break;
+ case MYSQL_TYPE_SET:
+ type = INT_TYPE;
+ break;
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ type = STRING_TYPE;
+ break;
+ case MYSQL_TYPE_GEOMETRY:
+ type = UNSUPPORTED_TYPE;
+ break;
+ }
+
+ DBUG_RETURN(type);
+ }
+
+ bool ConditionConverter::have_index(const Item_field *field_item,
+ grn_operator _operator) {
+ MRN_DBUG_ENTER_METHOD();
+
+ grn_obj *column;
+ column = grn_obj_column(ctx_, table_,
+ MRN_ITEM_FIELD_GET_NAME(field_item),
+ MRN_ITEM_FIELD_GET_NAME_LENGTH(field_item));
+ if (!column) {
+ DBUG_RETURN(false);
+ }
+ mrn::SmartGrnObj smart_column(ctx_, column);
+
+ int n_indexes = grn_column_index(ctx_, column, _operator, NULL, 0, NULL);
+ bool convertable = (n_indexes > 0);
+
+ DBUG_RETURN(convertable);
+ }
+
+ bool ConditionConverter::have_index(const Item_field *field_item,
+ Item_func::Functype func_type) {
+ MRN_DBUG_ENTER_METHOD();
+
+ bool have = false;
+ switch (func_type) {
+ case Item_func::EQ_FUNC:
+ have = have_index(field_item, GRN_OP_EQUAL);
+ break;
+ case Item_func::LT_FUNC:
+ have = have_index(field_item, GRN_OP_LESS);
+ break;
+ case Item_func::LE_FUNC:
+ have = have_index(field_item, GRN_OP_LESS_EQUAL);
+ break;
+ case Item_func::GE_FUNC:
+ have = have_index(field_item, GRN_OP_GREATER_EQUAL);
+ break;
+ case Item_func::GT_FUNC:
+ have = have_index(field_item, GRN_OP_GREATER);
+ break;
+ default:
+ break;
+ }
+
+ DBUG_RETURN(have);
+ }
+
+ const Item_func *ConditionConverter::find_match_against(const Item *item) {
+ MRN_DBUG_ENTER_METHOD();
+
+ if (!item) {
+ DBUG_RETURN(NULL);
+ }
+
+ switch (item->type()) {
+ case Item::COND_ITEM:
+ if (is_storage_mode_) {
+ Item_cond *cond_item = (Item_cond *)item;
+ if (cond_item->functype() == Item_func::COND_AND_FUNC) {
+ List_iterator<Item> iterator(*((cond_item)->argument_list()));
+ const Item *sub_item;
+ while ((sub_item = iterator++)) {
+ const Item_func *match_against = find_match_against(sub_item);
+ if (match_against) {
+ DBUG_RETURN(match_against);
+ }
+ }
+ }
+ }
+ break;
+ case Item::FUNC_ITEM:
+ {
+ const Item_func *func_item = (const Item_func *)item;
+ switch (func_item->functype()) {
+ case Item_func::FT_FUNC:
+ DBUG_RETURN(func_item);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ DBUG_RETURN(NULL);
+ }
+
+ void ConditionConverter::convert(const Item *where, grn_obj *expression) {
+ MRN_DBUG_ENTER_METHOD();
+
+ if (!where || where->type() != Item::COND_ITEM) {
+ DBUG_VOID_RETURN;
+ }
+
+ Item_cond *cond_item = (Item_cond *)where;
+ List_iterator<Item> iterator(*((cond_item)->argument_list()));
+ const Item *sub_item;
+ while ((sub_item = iterator++)) {
+ switch (sub_item->type()) {
+ case Item::FUNC_ITEM:
+ {
+ const Item_func *func_item = (const Item_func *)sub_item;
+ switch (func_item->functype()) {
+ case Item_func::EQ_FUNC:
+ convert_binary_operation(func_item, expression, GRN_OP_EQUAL);
+ break;
+ case Item_func::LT_FUNC:
+ convert_binary_operation(func_item, expression, GRN_OP_LESS);
+ break;
+ case Item_func::LE_FUNC:
+ convert_binary_operation(func_item, expression, GRN_OP_LESS_EQUAL);
+ break;
+ case Item_func::GE_FUNC:
+ convert_binary_operation(func_item, expression,
+ GRN_OP_GREATER_EQUAL);
+ break;
+ case Item_func::GT_FUNC:
+ convert_binary_operation(func_item, expression, GRN_OP_GREATER);
+ break;
+ case Item_func::BETWEEN:
+ convert_between(func_item, expression);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ DBUG_VOID_RETURN;
+ }
+
+ void ConditionConverter::convert_binary_operation(const Item_func *func_item,
+ grn_obj *expression,
+ grn_operator _operator) {
+ Item **arguments = func_item->arguments();
+ Item *left_item = arguments[0];
+ Item *right_item = arguments[1];
+ if (left_item->type() == Item::FIELD_ITEM) {
+ const Item_field *field_item = static_cast<const Item_field *>(left_item);
+ append_field_value(field_item, expression);
+ append_const_item(field_item, right_item, expression);
+ grn_expr_append_op(ctx_, expression, _operator, 2);
+ grn_expr_append_op(ctx_, expression, GRN_OP_AND, 2);
+ }
+ }
+
+ void ConditionConverter::convert_between(const Item_func *func_item,
+ grn_obj *expression) {
+ MRN_DBUG_ENTER_METHOD();
+
+ Item **arguments = func_item->arguments();
+ Item *target_item = arguments[0];
+ Item *min_item = arguments[1];
+ Item *max_item = arguments[2];
+
+ grn_obj *between_func = grn_ctx_get(ctx_, "between", strlen("between"));
+ grn_expr_append_obj(ctx_, expression, between_func, GRN_OP_PUSH, 1);
+
+ const Item_field *field_item = static_cast<const Item_field *>(target_item);
+ append_field_value(field_item, expression);
+
+ grn_obj include;
+ mrn::SmartGrnObj smart_include(ctx_, &include);
+ GRN_TEXT_INIT(&include, 0);
+ GRN_TEXT_PUTS(ctx_, &include, "include");
+ append_const_item(field_item, min_item, expression);
+ grn_expr_append_const(ctx_, expression, &include, GRN_OP_PUSH, 1);
+ append_const_item(field_item, max_item, expression);
+ grn_expr_append_const(ctx_, expression, &include, GRN_OP_PUSH, 1);
+
+ grn_expr_append_op(ctx_, expression, GRN_OP_CALL, 5);
+
+ grn_expr_append_op(ctx_, expression, GRN_OP_AND, 2);
+
+ DBUG_VOID_RETURN;
+ }
+
+ void ConditionConverter::append_field_value(const Item_field *field_item,
+ grn_obj *expression) {
+ MRN_DBUG_ENTER_METHOD();
+
+ GRN_BULK_REWIND(&column_name_);
+ GRN_TEXT_PUT(ctx_, &column_name_,
+ MRN_ITEM_FIELD_GET_NAME(field_item),
+ MRN_ITEM_FIELD_GET_NAME_LENGTH(field_item));
+ grn_expr_append_const(ctx_, expression, &column_name_,
+ GRN_OP_PUSH, 1);
+ grn_expr_append_op(ctx_, expression, GRN_OP_GET_VALUE, 1);
+
+ DBUG_VOID_RETURN;
+ }
+
+ void ConditionConverter::append_const_item(const Item_field *field_item,
+ Item *const_item,
+ grn_obj *expression) {
+ MRN_DBUG_ENTER_METHOD();
+
+ enum_field_types field_type = field_item->field_type();
+ NormalizedType normalized_type = normalize_field_type(field_type);
+
+ switch (normalized_type) {
+ case STRING_TYPE:
+ grn_obj_reinit(ctx_, &value_, GRN_DB_TEXT, 0);
+ {
+ String *string;
+ string = const_item->val_str(NULL);
+ GRN_TEXT_SET(ctx_, &value_, string->ptr(), string->length());
+ }
+ break;
+ case INT_TYPE:
+ grn_obj_reinit(ctx_, &value_, GRN_DB_INT64, 0);
+ GRN_INT64_SET(ctx_, &value_, const_item->val_int());
+ break;
+ case TIME_TYPE:
+ grn_obj_reinit(ctx_, &value_, GRN_DB_TIME, 0);
+ {
+ MYSQL_TIME mysql_time;
+ get_time_value(field_item, const_item, &mysql_time);
+ bool truncated = false;
+ TimeConverter time_converter;
+ long long int time =
+ time_converter.mysql_time_to_grn_time(&mysql_time, &truncated);
+ GRN_TIME_SET(ctx_, &value_, time);
+ }
+ break;
+ case UNSUPPORTED_TYPE:
+ // Should not be occurred.
+ DBUG_PRINT("error",
+ ("mroonga: append_const_item: unsupported type: <%d> "
+ "This case should not be occurred.",
+ field_type));
+ grn_obj_reinit(ctx_, &value_, GRN_DB_VOID, 0);
+ break;
+ }
+ grn_expr_append_const(ctx_, expression, &value_, GRN_OP_PUSH, 1);
+
+ DBUG_VOID_RETURN;
+ }
+}
diff --git a/storage/mroonga/lib/mrn_condition_converter.hpp b/storage/mroonga/lib/mrn_condition_converter.hpp
new file mode 100644
index 00000000000..3cf97c62bbe
--- /dev/null
+++ b/storage/mroonga/lib/mrn_condition_converter.hpp
@@ -0,0 +1,82 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MRN_CONDITION_CONVERTER_HPP_
+#define MRN_CONDITION_CONVERTER_HPP_
+
+#include <groonga.h>
+#include <mrn_mysql_compat.h>
+
+namespace mrn {
+ class ConditionConverter {
+ public:
+ ConditionConverter(grn_ctx *ctx, grn_obj *table, bool is_storage_mode);
+ ~ConditionConverter();
+
+ bool is_convertable(const Item *item);
+ const Item_func *find_match_against(const Item *item);
+ // caller must check "where" can be convertable by
+ // is_convertable(). This method doesn't validate "where".
+ void convert(const Item *where, grn_obj *expression);
+
+ private:
+ enum NormalizedType {
+ STRING_TYPE,
+ INT_TYPE,
+ TIME_TYPE,
+ UNSUPPORTED_TYPE,
+ };
+
+ grn_ctx *ctx_;
+ grn_obj *table_;
+ bool is_storage_mode_;
+ grn_obj column_name_;
+ grn_obj value_;
+
+ bool is_convertable(const Item_cond *cond_item);
+ bool is_convertable(const Item_func *func_item);
+ bool is_convertable_binary_operation(const Item_field *field_item,
+ Item *value_item,
+ Item_func::Functype func_type);
+ bool is_convertable_between(const Item_field *field_item,
+ Item *min_item,
+ Item *max_item);
+ bool is_valid_time_value(const Item_field *field_item,
+ Item *value_item);
+ bool get_time_value(const Item_field *field_item,
+ Item *value_item,
+ MYSQL_TIME *mysql_time);
+ bool have_index(const Item_field *field_item, grn_operator _operator);
+ bool have_index(const Item_field *field_item, Item_func::Functype func_type);
+
+ NormalizedType normalize_field_type(enum_field_types field_type);
+
+ void convert_binary_operation(const Item_func *func_item,
+ grn_obj *expression,
+ grn_operator _operator);
+ void convert_between(const Item_func *func_item, grn_obj *expression);
+ void append_field_value(const Item_field *field_item,
+ grn_obj *expression);
+ void append_const_item(const Item_field *field_item,
+ Item *const_item,
+ grn_obj *expression);
+ };
+}
+
+#endif /* MRN_CONDITION_CONVERTER_HPP_ */
diff --git a/storage/mroonga/lib/mrn_debug_column_access.cpp b/storage/mroonga/lib/mrn_debug_column_access.cpp
new file mode 100644
index 00000000000..ed7cacae90f
--- /dev/null
+++ b/storage/mroonga/lib/mrn_debug_column_access.cpp
@@ -0,0 +1,36 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "mrn_debug_column_access.hpp"
+
+namespace mrn {
+ DebugColumnAccess::DebugColumnAccess(TABLE *table, MY_BITMAP *bitmap)
+ : table_(table),
+ bitmap_(bitmap) {
+#ifndef DBUG_OFF
+ map_ = dbug_tmp_use_all_columns(table_, bitmap_);
+#endif
+ }
+
+ DebugColumnAccess::~DebugColumnAccess() {
+#ifndef DBUG_OFF
+ dbug_tmp_restore_column_map(bitmap_, map_);
+#endif
+ }
+}
diff --git a/storage/mroonga/lib/mrn_debug_column_access.hpp b/storage/mroonga/lib/mrn_debug_column_access.hpp
new file mode 100644
index 00000000000..1548b4d8459
--- /dev/null
+++ b/storage/mroonga/lib/mrn_debug_column_access.hpp
@@ -0,0 +1,38 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MRN_DEBUG_COLUMN_ACCESS_HPP_
+#define MRN_DEBUG_COLUMN_ACCESS_HPP_
+
+#include <mrn_mysql.h>
+
+namespace mrn {
+ class DebugColumnAccess {
+ TABLE *table_;
+ MY_BITMAP *bitmap_;
+#ifndef DBUG_OFF
+ my_bitmap_map *map_;
+#endif
+ public:
+ DebugColumnAccess(TABLE *table, MY_BITMAP *bitmap);
+ ~DebugColumnAccess();
+ };
+}
+
+#endif // MRN_DEBUG_COLUMN_ACCESS_HPP_
diff --git a/storage/mroonga/lib/mrn_encoding.cpp b/storage/mroonga/lib/mrn_encoding.cpp
new file mode 100644
index 00000000000..a69a849c053
--- /dev/null
+++ b/storage/mroonga/lib/mrn_encoding.cpp
@@ -0,0 +1,222 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013 Kouhei Sutou <kou@clear-code.com>
+ Copyright(C) 2011-2013 Kentoku SHIBA
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include <mrn_err.h>
+#include "mrn_encoding.hpp"
+
+namespace mrn {
+ namespace encoding {
+ CHARSET_INFO *mrn_charset_utf8 = NULL;
+ CHARSET_INFO *mrn_charset_utf8mb4 = NULL;
+ CHARSET_INFO *mrn_charset_binary = NULL;
+ CHARSET_INFO *mrn_charset_ascii = NULL;
+ CHARSET_INFO *mrn_charset_latin1_1 = NULL;
+ CHARSET_INFO *mrn_charset_latin1_2 = NULL;
+ CHARSET_INFO *mrn_charset_cp932 = NULL;
+ CHARSET_INFO *mrn_charset_sjis = NULL;
+ CHARSET_INFO *mrn_charset_eucjpms = NULL;
+ CHARSET_INFO *mrn_charset_ujis = NULL;
+ CHARSET_INFO *mrn_charset_koi8r = NULL;
+
+ void init(void) {
+ CHARSET_INFO **cs;
+ MRN_DBUG_ENTER_FUNCTION();
+ for (cs = all_charsets; cs < all_charsets + MY_ALL_CHARSETS_SIZE; cs++)
+ {
+ if (!cs[0])
+ continue;
+ if (!strcmp(cs[0]->csname, "utf8"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->name, cs[0]->csname, cs[0]->cset));
+ if (!mrn_charset_utf8)
+ mrn_charset_utf8 = cs[0];
+ else if (mrn_charset_utf8->cset != cs[0]->cset)
+ DBUG_ASSERT(0);
+ continue;
+ }
+ if (!strcmp(cs[0]->csname, "utf8mb4"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->name, cs[0]->csname, cs[0]->cset));
+ if (!mrn_charset_utf8mb4)
+ mrn_charset_utf8mb4 = cs[0];
+ else if (mrn_charset_utf8mb4->cset != cs[0]->cset)
+ DBUG_ASSERT(0);
+ continue;
+ }
+ if (!strcmp(cs[0]->csname, "binary"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->name, cs[0]->csname, cs[0]->cset));
+ if (!mrn_charset_binary)
+ mrn_charset_binary = cs[0];
+ else if (mrn_charset_binary->cset != cs[0]->cset)
+ DBUG_ASSERT(0);
+ continue;
+ }
+ if (!strcmp(cs[0]->csname, "ascii"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->name, cs[0]->csname, cs[0]->cset));
+ if (!mrn_charset_ascii)
+ mrn_charset_ascii = cs[0];
+ else if (mrn_charset_ascii->cset != cs[0]->cset)
+ DBUG_ASSERT(0);
+ continue;
+ }
+ if (!strcmp(cs[0]->csname, "latin1"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->name, cs[0]->csname, cs[0]->cset));
+ if (!mrn_charset_latin1_1)
+ mrn_charset_latin1_1 = cs[0];
+ else if (mrn_charset_latin1_1->cset != cs[0]->cset)
+ {
+ if (!mrn_charset_latin1_2)
+ mrn_charset_latin1_2 = cs[0];
+ else if (mrn_charset_latin1_2->cset != cs[0]->cset)
+ DBUG_ASSERT(0);
+ }
+ continue;
+ }
+ if (!strcmp(cs[0]->csname, "cp932"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->name, cs[0]->csname, cs[0]->cset));
+ if (!mrn_charset_cp932)
+ mrn_charset_cp932 = cs[0];
+ else if (mrn_charset_cp932->cset != cs[0]->cset)
+ DBUG_ASSERT(0);
+ continue;
+ }
+ if (!strcmp(cs[0]->csname, "sjis"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->name, cs[0]->csname, cs[0]->cset));
+ if (!mrn_charset_sjis)
+ mrn_charset_sjis = cs[0];
+ else if (mrn_charset_sjis->cset != cs[0]->cset)
+ DBUG_ASSERT(0);
+ continue;
+ }
+ if (!strcmp(cs[0]->csname, "eucjpms"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->name, cs[0]->csname, cs[0]->cset));
+ if (!mrn_charset_eucjpms)
+ mrn_charset_eucjpms = cs[0];
+ else if (mrn_charset_eucjpms->cset != cs[0]->cset)
+ DBUG_ASSERT(0);
+ continue;
+ }
+ if (!strcmp(cs[0]->csname, "ujis"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->name, cs[0]->csname, cs[0]->cset));
+ if (!mrn_charset_ujis)
+ mrn_charset_ujis = cs[0];
+ else if (mrn_charset_ujis->cset != cs[0]->cset)
+ DBUG_ASSERT(0);
+ continue;
+ }
+ if (!strcmp(cs[0]->csname, "koi8r"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->name, cs[0]->csname, cs[0]->cset));
+ if (!mrn_charset_koi8r)
+ mrn_charset_koi8r = cs[0];
+ else if (mrn_charset_koi8r->cset != cs[0]->cset)
+ DBUG_ASSERT(0);
+ continue;
+ }
+ DBUG_PRINT("info", ("mroonga: %s[%s][%p] is not supported",
+ cs[0]->name, cs[0]->csname, cs[0]->cset));
+ }
+ DBUG_VOID_RETURN;
+ }
+
+ bool set(grn_ctx *ctx, const CHARSET_INFO *charset) {
+ MRN_DBUG_ENTER_FUNCTION();
+ if (!charset)
+ {
+ GRN_CTX_SET_ENCODING(ctx, GRN_ENC_NONE);
+ DBUG_RETURN(true);
+ }
+ if (charset->cset == mrn_charset_utf8->cset)
+ {
+ GRN_CTX_SET_ENCODING(ctx, GRN_ENC_UTF8);
+ DBUG_RETURN(true);
+ }
+ if (mrn_charset_utf8mb4 && charset->cset == mrn_charset_utf8mb4->cset)
+ {
+ GRN_CTX_SET_ENCODING(ctx, GRN_ENC_UTF8);
+ DBUG_RETURN(true);
+ }
+ if (charset->cset == mrn_charset_cp932->cset)
+ {
+ GRN_CTX_SET_ENCODING(ctx, GRN_ENC_SJIS);
+ DBUG_RETURN(true);
+ }
+ if (charset->cset == mrn_charset_eucjpms->cset)
+ {
+ GRN_CTX_SET_ENCODING(ctx, GRN_ENC_EUC_JP);
+ DBUG_RETURN(true);
+ }
+ if (charset->cset == mrn_charset_latin1_1->cset)
+ {
+ GRN_CTX_SET_ENCODING(ctx, GRN_ENC_LATIN1);
+ DBUG_RETURN(true);
+ }
+ if (charset->cset == mrn_charset_latin1_2->cset)
+ {
+ GRN_CTX_SET_ENCODING(ctx, GRN_ENC_LATIN1);
+ DBUG_RETURN(true);
+ }
+ if (charset->cset == mrn_charset_koi8r->cset)
+ {
+ GRN_CTX_SET_ENCODING(ctx, GRN_ENC_KOI8R);
+ DBUG_RETURN(true);
+ }
+ if (charset->cset == mrn_charset_binary->cset)
+ {
+ GRN_CTX_SET_ENCODING(ctx, GRN_ENC_NONE);
+ DBUG_RETURN(true);
+ }
+ if (charset->cset == mrn_charset_ascii->cset)
+ {
+ GRN_CTX_SET_ENCODING(ctx, GRN_ENC_UTF8);
+ DBUG_RETURN(true);
+ }
+ if (charset->cset == mrn_charset_sjis->cset)
+ {
+ GRN_CTX_SET_ENCODING(ctx, GRN_ENC_SJIS);
+ DBUG_RETURN(true);
+ }
+ if (charset->cset == mrn_charset_ujis->cset)
+ {
+ GRN_CTX_SET_ENCODING(ctx, GRN_ENC_EUC_JP);
+ DBUG_RETURN(true);
+ }
+ GRN_CTX_SET_ENCODING(ctx, GRN_ENC_NONE);
+ DBUG_RETURN(false);
+ }
+ }
+}
diff --git a/storage/mroonga/lib/mrn_encoding.hpp b/storage/mroonga/lib/mrn_encoding.hpp
new file mode 100644
index 00000000000..b4f21e1a274
--- /dev/null
+++ b/storage/mroonga/lib/mrn_encoding.hpp
@@ -0,0 +1,35 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MRN_ENCODING_HPP_
+#define MRN_ENCODING_HPP_
+
+#include <groonga.h>
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+
+namespace mrn {
+ namespace encoding {
+ void init(void);
+ bool set(grn_ctx *ctx, const CHARSET_INFO *charset);
+ }
+}
+
+#endif // MRN_ENCODING_HPP_
diff --git a/storage/mroonga/lib/mrn_external_lock.cpp b/storage/mroonga/lib/mrn_external_lock.cpp
new file mode 100644
index 00000000000..b266b6594ca
--- /dev/null
+++ b/storage/mroonga/lib/mrn_external_lock.cpp
@@ -0,0 +1,43 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012 Kentoku SHIBA
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "mrn_external_lock.hpp"
+
+namespace mrn {
+ ExternalLock::ExternalLock(THD *thd, handler *handler, int lock_type)
+ : thd_(thd),
+ handler_(handler),
+ lock_type_(lock_type) {
+ if (lock_type_ != F_UNLCK) {
+ error_ = handler_->ha_external_lock(thd_, lock_type);
+ } else {
+ error_ = 0;
+ }
+ }
+
+ ExternalLock::~ExternalLock() {
+ if (lock_type_ != F_UNLCK) {
+ handler_->ha_external_lock(thd_, F_UNLCK);
+ }
+ }
+
+ int ExternalLock::error() {
+ return error_;
+ }
+}
diff --git a/storage/mroonga/lib/mrn_external_lock.hpp b/storage/mroonga/lib/mrn_external_lock.hpp
new file mode 100644
index 00000000000..f78b436f6e8
--- /dev/null
+++ b/storage/mroonga/lib/mrn_external_lock.hpp
@@ -0,0 +1,38 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012 Kentoku SHIBA
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MRN_EXTERNAL_LOCK_HPP_
+#define MRN_EXTERNAL_LOCK_HPP_
+
+#include <mrn_mysql.h>
+
+namespace mrn {
+ class ExternalLock {
+ THD *thd_;
+ handler *handler_;
+ int lock_type_;
+ int error_;
+ public:
+ ExternalLock(THD *thd, handler *handler, int lock_type);
+ ~ExternalLock();
+ int error();
+ };
+}
+
+#endif // MRN_EXTERNAL_LOCK_HPP_
diff --git a/storage/mroonga/lib/mrn_field_normalizer.cpp b/storage/mroonga/lib/mrn_field_normalizer.cpp
new file mode 100644
index 00000000000..bb91b3ab98d
--- /dev/null
+++ b/storage/mroonga/lib/mrn_field_normalizer.cpp
@@ -0,0 +1,142 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "mrn_field_normalizer.hpp"
+#include "mrn_encoding.hpp"
+
+// for debug
+#define MRN_CLASS_NAME "mrn::FieldNormalizer"
+
+namespace mrn {
+ FieldNormalizer::FieldNormalizer(grn_ctx *ctx, THD *thread, Field *field)
+ : ctx_(ctx),
+ thread_(thread),
+ field_(field) {
+ }
+
+ FieldNormalizer::~FieldNormalizer() {
+ }
+
+ bool FieldNormalizer::should_normalize() {
+ MRN_DBUG_ENTER_METHOD();
+
+ DBUG_PRINT("info",
+ ("mroonga: result_type = %u", field_->result_type()));
+ DBUG_PRINT("info",
+ ("mroonga: charset->name = %s", field_->charset()->name));
+ DBUG_PRINT("info",
+ ("mroonga: charset->csname = %s", field_->charset()->csname));
+ DBUG_PRINT("info",
+ ("mroonga: charset->state = %u", field_->charset()->state));
+ bool need_normalize_p;
+ if (field_->charset()->state & (MY_CS_BINSORT | MY_CS_CSSORT)) {
+ need_normalize_p = false;
+ DBUG_PRINT("info",
+ ("mroonga: should_normalize: false: sort is required"));
+ } else {
+ if (is_text_type()) {
+ need_normalize_p = true;
+ DBUG_PRINT("info", ("mroonga: should_normalize: true: text type"));
+ } else {
+ need_normalize_p = false;
+ DBUG_PRINT("info", ("mroonga: should_normalize: false: no text type"));
+ }
+ }
+
+ DBUG_RETURN(need_normalize_p);
+ }
+
+ bool FieldNormalizer::is_text_type() {
+ MRN_DBUG_ENTER_METHOD();
+ bool text_type_p;
+ switch (field_->type()) {
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_VAR_STRING:
+ text_type_p = true;
+ break;
+ case MYSQL_TYPE_STRING:
+ switch (field_->real_type()) {
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ text_type_p = false;
+ break;
+ default:
+ text_type_p = true;
+ break;
+ }
+ break;
+ default:
+ text_type_p = false;
+ break;
+ }
+ DBUG_RETURN(text_type_p);
+ }
+
+ grn_obj *FieldNormalizer::normalize(const char *string,
+ unsigned int string_length) {
+ MRN_DBUG_ENTER_METHOD();
+ grn_obj *normalizer = find_grn_normalizer();
+ int flags = 0;
+ grn_encoding original_encoding = GRN_CTX_GET_ENCODING(ctx_);
+ encoding::set(ctx_, field_->charset());
+ grn_obj *grn_string = grn_string_open(ctx_, string, string_length,
+ normalizer, flags);
+ GRN_CTX_SET_ENCODING(ctx_, original_encoding);
+ DBUG_RETURN(grn_string);
+ }
+
+ grn_obj *FieldNormalizer::find_grn_normalizer() {
+ MRN_DBUG_ENTER_METHOD();
+
+ const CHARSET_INFO *charset_info = field_->charset();
+ const char *normalizer_name = NULL;
+ const char *default_normalizer_name = "NormalizerAuto";
+ if ((strcmp(charset_info->name, "utf8_general_ci") == 0) ||
+ (strcmp(charset_info->name, "utf8mb4_general_ci") == 0)) {
+ normalizer_name = "NormalizerMySQLGeneralCI";
+ } else if ((strcmp(charset_info->name, "utf8_unicode_ci") == 0) ||
+ (strcmp(charset_info->name, "utf8mb4_unicode_ci") == 0)) {
+ normalizer_name = "NormalizerMySQLUnicodeCI";
+ }
+
+ grn_obj *normalizer = NULL;
+ if (normalizer_name) {
+ normalizer = grn_ctx_get(ctx_, normalizer_name, -1);
+ if (!normalizer) {
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "%s normalizer isn't found for %s. "
+ "Install groonga-normalizer-mysql normalizer. "
+ "%s is used as fallback.",
+ normalizer_name,
+ charset_info->name,
+ default_normalizer_name);
+ push_warning(thread_, Sql_condition::WARN_LEVEL_WARN,
+ HA_ERR_UNSUPPORTED, error_message);
+ }
+ }
+
+ if (!normalizer) {
+ normalizer = grn_ctx_get(ctx_, default_normalizer_name, -1);
+ }
+
+ DBUG_RETURN(normalizer);
+ }
+}
diff --git a/storage/mroonga/lib/mrn_field_normalizer.hpp b/storage/mroonga/lib/mrn_field_normalizer.hpp
new file mode 100644
index 00000000000..5fd8974ce5b
--- /dev/null
+++ b/storage/mroonga/lib/mrn_field_normalizer.hpp
@@ -0,0 +1,47 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MRN_FIELD_NORMALIZER_HPP_
+#define MRN_FIELD_NORMALIZER_HPP_
+
+#include <groonga.h>
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+
+namespace mrn {
+ class FieldNormalizer {
+ public:
+ FieldNormalizer(grn_ctx *ctx, THD *thread, Field *field);
+ ~FieldNormalizer();
+
+ bool should_normalize();
+ grn_obj *normalize(const char *string, unsigned int string_length);
+ grn_obj *find_grn_normalizer();
+
+ private:
+ grn_ctx *ctx_;
+ THD *thread_;
+ Field *field_;
+
+ bool is_text_type();
+ };
+}
+
+#endif // MRN_FIELD_NORMALIZER_HPP_
diff --git a/storage/mroonga/lib/mrn_index_column_name.cpp b/storage/mroonga/lib/mrn_index_column_name.cpp
new file mode 100644
index 00000000000..14e83ec8e34
--- /dev/null
+++ b/storage/mroonga/lib/mrn_index_column_name.cpp
@@ -0,0 +1,96 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2013 Kentoku SHIBA
+ Copyright(C) 2011-2012 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include <mrn_mysql.h>
+
+#include "mrn_index_column_name.hpp"
+
+#define MRN_MIN_INDEX_COLUMN_NAME_LENGTH 65
+
+// for debug
+#define MRN_CLASS_NAME "mrn::IndexColumnName"
+
+namespace mrn {
+ IndexColumnName::IndexColumnName(const char *table_name,
+ const char *mysql_column_name)
+ : table_name_(table_name),
+ mysql_column_name_(mysql_column_name) {
+ uchar encoded_mysql_column_name_multibyte[MRN_MAX_KEY_SIZE];
+ const uchar *mysql_column_name_multibyte =
+ reinterpret_cast<const uchar *>(mysql_column_name_);
+ encode(encoded_mysql_column_name_multibyte,
+ encoded_mysql_column_name_multibyte + MRN_MAX_KEY_SIZE,
+ mysql_column_name_multibyte,
+ mysql_column_name_multibyte + strlen(mysql_column_name_));
+ snprintf(name_, MRN_MAX_KEY_SIZE,
+ "%s-%s", table_name_, encoded_mysql_column_name_multibyte);
+ length_ = strlen(name_);
+ if (length_ < MRN_MIN_INDEX_COLUMN_NAME_LENGTH) {
+ memset(name_ + length_, '-', MRN_MIN_INDEX_COLUMN_NAME_LENGTH - length_);
+ length_ = MRN_MIN_INDEX_COLUMN_NAME_LENGTH;
+ name_[length_] = '\0';
+ }
+ }
+
+ const char *IndexColumnName::c_str() {
+ return name_;
+ }
+
+ size_t IndexColumnName::length() {
+ return length_;
+ }
+
+ uint IndexColumnName::encode(uchar *encoded_start,
+ uchar *encoded_end,
+ const uchar *mysql_string_start,
+ const uchar *mysql_string_end) {
+ MRN_DBUG_ENTER_METHOD();
+ my_charset_conv_mb_wc mb_wc = system_charset_info->cset->mb_wc;
+ my_charset_conv_wc_mb wc_mb = my_charset_filename.cset->wc_mb;
+ DBUG_PRINT("info", ("mroonga: in=%s", mysql_string_start));
+ encoded_end--;
+ uchar *encoded = encoded_start;
+ const uchar *mysql_string = mysql_string_start;
+ while (mysql_string < mysql_string_end && encoded < encoded_end) {
+ my_wc_t wc;
+ int mb_wc_converted_length;
+ int wc_mb_converted_length;
+ mb_wc_converted_length =
+ (*mb_wc)(NULL, &wc, mysql_string, mysql_string_end);
+ if (mb_wc_converted_length > 0) {
+ wc_mb_converted_length = (*wc_mb)(NULL, wc, encoded, encoded_end);
+ if (wc_mb_converted_length <= 0) {
+ break;
+ }
+ } else if (mb_wc_converted_length == MY_CS_ILSEQ) {
+ *encoded = *mysql_string;
+ mb_wc_converted_length = 1;
+ wc_mb_converted_length = 1;
+ } else {
+ break;
+ }
+ mysql_string += mb_wc_converted_length;
+ encoded += wc_mb_converted_length;
+ }
+ *encoded = '\0';
+ DBUG_PRINT("info", ("mroonga: out=%s", encoded_start));
+ DBUG_RETURN(encoded - encoded_start);
+ }
+}
diff --git a/storage/mroonga/lib/mrn_index_column_name.hpp b/storage/mroonga/lib/mrn_index_column_name.hpp
new file mode 100644
index 00000000000..5cd24623abd
--- /dev/null
+++ b/storage/mroonga/lib/mrn_index_column_name.hpp
@@ -0,0 +1,43 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2013 Kentoku SHIBA
+ Copyright(C) 2011-2012 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MRN_INDEX_COLUMN_NAME_HPP_
+#define MRN_INDEX_COLUMN_NAME_HPP_
+
+#include <mrn_constants.hpp>
+
+namespace mrn {
+ class IndexColumnName {
+ public:
+ IndexColumnName(const char *table_name, const char *mysql_column_name);
+ const char *c_str();
+ size_t length();
+ private:
+ const char *table_name_;
+ const char *mysql_column_name_;
+ char name_[MRN_MAX_KEY_SIZE];
+ size_t length_;
+
+ uint encode(uchar *encoded_start, uchar *encoded_end,
+ const uchar *mysql_string_start, const uchar *mysql_string_end);
+ };
+}
+
+#endif /* MRN_INDEX_COLUMN_NAME_HPP_ */
diff --git a/storage/mroonga/lib/mrn_index_table_name.cpp b/storage/mroonga/lib/mrn_index_table_name.cpp
new file mode 100644
index 00000000000..93f4ff8f8fd
--- /dev/null
+++ b/storage/mroonga/lib/mrn_index_table_name.cpp
@@ -0,0 +1,89 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011 Kentoku SHIBA
+ Copyright(C) 2011-2012 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include <mrn_mysql.h>
+
+#include "mrn_index_table_name.hpp"
+
+// for debug
+#define MRN_CLASS_NAME "mrn::IndexTableName"
+
+namespace mrn {
+ IndexTableName::IndexTableName(const char *table_name,
+ const char *mysql_index_name)
+ : table_name_(table_name),
+ mysql_index_name_(mysql_index_name) {
+ uchar encoded_mysql_index_name_multibyte[MRN_MAX_KEY_SIZE];
+ const uchar *mysql_index_name_multibyte =
+ reinterpret_cast<const uchar *>(mysql_index_name_);
+ encode(encoded_mysql_index_name_multibyte,
+ encoded_mysql_index_name_multibyte + MRN_MAX_KEY_SIZE,
+ mysql_index_name_multibyte,
+ mysql_index_name_multibyte + strlen(mysql_index_name_));
+ snprintf(name_, MRN_MAX_KEY_SIZE,
+ "%s-%s", table_name_, encoded_mysql_index_name_multibyte);
+ length_ = strlen(name_);
+ }
+
+ const char *IndexTableName::c_str() {
+ return name_;
+ }
+
+ size_t IndexTableName::length() {
+ return length_;
+ }
+
+ uint IndexTableName::encode(uchar *encoded_start,
+ uchar *encoded_end,
+ const uchar *mysql_string_start,
+ const uchar *mysql_string_end) {
+ MRN_DBUG_ENTER_METHOD();
+ my_charset_conv_mb_wc mb_wc = system_charset_info->cset->mb_wc;
+ my_charset_conv_wc_mb wc_mb = my_charset_filename.cset->wc_mb;
+ DBUG_PRINT("info", ("mroonga: in=%s", mysql_string_start));
+ encoded_end--;
+ uchar *encoded = encoded_start;
+ const uchar *mysql_string = mysql_string_start;
+ while (mysql_string < mysql_string_end && encoded < encoded_end) {
+ my_wc_t wc;
+ int mb_wc_converted_length;
+ int wc_mb_converted_length;
+ mb_wc_converted_length =
+ (*mb_wc)(NULL, &wc, mysql_string, mysql_string_end);
+ if (mb_wc_converted_length > 0) {
+ wc_mb_converted_length = (*wc_mb)(NULL, wc, encoded, encoded_end);
+ if (wc_mb_converted_length <= 0) {
+ break;
+ }
+ } else if (mb_wc_converted_length == MY_CS_ILSEQ) {
+ *encoded = *mysql_string;
+ mb_wc_converted_length = 1;
+ wc_mb_converted_length = 1;
+ } else {
+ break;
+ }
+ mysql_string += mb_wc_converted_length;
+ encoded += wc_mb_converted_length;
+ }
+ *encoded = '\0';
+ DBUG_PRINT("info", ("mroonga: out=%s", encoded_start));
+ DBUG_RETURN(encoded - encoded_start);
+ }
+}
diff --git a/storage/mroonga/lib/mrn_index_table_name.hpp b/storage/mroonga/lib/mrn_index_table_name.hpp
new file mode 100644
index 00000000000..4ac4bfe087b
--- /dev/null
+++ b/storage/mroonga/lib/mrn_index_table_name.hpp
@@ -0,0 +1,43 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011 Kentoku SHIBA
+ Copyright(C) 2011-2012 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MRN_INDEX_TABLE_NAME_HPP_
+#define MRN_INDEX_TABLE_NAME_HPP_
+
+#include <mrn_constants.hpp>
+
+namespace mrn {
+ class IndexTableName {
+ public:
+ IndexTableName(const char *table_name, const char *mysql_index_name);
+ const char *c_str();
+ size_t length();
+ private:
+ const char *table_name_;
+ const char *mysql_index_name_;
+ char name_[MRN_MAX_KEY_SIZE];
+ size_t length_;
+
+ uint encode(uchar *encoded_start, uchar *encoded_end,
+ const uchar *mysql_string_start, const uchar *mysql_string_end);
+ };
+}
+
+#endif /* MRN_INDEX_TABLE_NAME_HPP_ */
diff --git a/storage/mroonga/lib/mrn_lock.cpp b/storage/mroonga/lib/mrn_lock.cpp
new file mode 100644
index 00000000000..94f8a4774af
--- /dev/null
+++ b/storage/mroonga/lib/mrn_lock.cpp
@@ -0,0 +1,31 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "mrn_lock.hpp"
+
+namespace mrn {
+ Lock::Lock(pthread_mutex_t *mutex)
+ : mutex_(mutex) {
+ pthread_mutex_lock(mutex_);
+ }
+
+ Lock::~Lock() {
+ pthread_mutex_unlock(mutex_);
+ }
+}
diff --git a/storage/mroonga/lib/mrn_lock.hpp b/storage/mroonga/lib/mrn_lock.hpp
new file mode 100644
index 00000000000..31dd7b3e53b
--- /dev/null
+++ b/storage/mroonga/lib/mrn_lock.hpp
@@ -0,0 +1,36 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MRN_LOCK_HPP_
+#define MRN_LOCK_HPP_
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+
+namespace mrn {
+ class Lock {
+ public:
+ Lock(pthread_mutex_t *mutex);
+ ~Lock();
+ private:
+ pthread_mutex_t *mutex_;
+ };
+}
+
+#endif /* MRN_LOCK_HPP_ */
diff --git a/storage/mroonga/lib/mrn_match_escalation_threshold_scope.cpp b/storage/mroonga/lib/mrn_match_escalation_threshold_scope.cpp
new file mode 100644
index 00000000000..c944b4a4bc0
--- /dev/null
+++ b/storage/mroonga/lib/mrn_match_escalation_threshold_scope.cpp
@@ -0,0 +1,33 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "mrn_match_escalation_threshold_scope.hpp"
+
+namespace mrn {
+ MatchEscalationThresholdScope::MatchEscalationThresholdScope(
+ grn_ctx *ctx, long long int threshold)
+ : ctx_(ctx),
+ original_threshold_(grn_ctx_get_match_escalation_threshold(ctx_)) {
+ grn_ctx_set_match_escalation_threshold(ctx_, threshold);
+ }
+
+ MatchEscalationThresholdScope::~MatchEscalationThresholdScope() {
+ grn_ctx_set_match_escalation_threshold(ctx_, original_threshold_);
+ }
+}
diff --git a/storage/mroonga/lib/mrn_match_escalation_threshold_scope.hpp b/storage/mroonga/lib/mrn_match_escalation_threshold_scope.hpp
new file mode 100644
index 00000000000..352e6589f0d
--- /dev/null
+++ b/storage/mroonga/lib/mrn_match_escalation_threshold_scope.hpp
@@ -0,0 +1,35 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MRN_MATCH_ESCALATION_THRESHOLD_SCOPE_HPP_
+#define MRN_MATCH_ESCALATION_THRESHOLD_SCOPE_HPP_
+
+#include <groonga.h>
+
+namespace mrn {
+ class MatchEscalationThresholdScope {
+ grn_ctx *ctx_;
+ long long int original_threshold_;
+ public:
+ MatchEscalationThresholdScope(grn_ctx *ctx, long long int threshold);
+ ~MatchEscalationThresholdScope();
+ };
+}
+
+#endif // MRN_MATCH_ESCALATION_THRESHOLD_SCOPE_HPP_
diff --git a/storage/mroonga/lib/mrn_multiple_column_key_codec.cpp b/storage/mroonga/lib/mrn_multiple_column_key_codec.cpp
new file mode 100644
index 00000000000..5ce736a49b8
--- /dev/null
+++ b/storage/mroonga/lib/mrn_multiple_column_key_codec.cpp
@@ -0,0 +1,548 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012-2014 Kouhei Sutou <kou@clear-code.com>
+ Copyright(C) 2013 Kentoku SHIBA
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include <mrn_mysql.h>
+
+#include "mrn_multiple_column_key_codec.hpp"
+#include "mrn_field_normalizer.hpp"
+#include "mrn_smart_grn_obj.hpp"
+
+// for debug
+#define MRN_CLASS_NAME "mrn::MultipleColumnKeyCodec"
+
+#ifdef WORDS_BIGENDIAN
+#define mrn_byte_order_host_to_network(buf, key, size) \
+{ \
+ uint32 size_ = (uint32)(size); \
+ uint8 *buf_ = (uint8 *)(buf); \
+ uint8 *key_ = (uint8 *)(key); \
+ while (size_--) { *buf_++ = *key_++; } \
+}
+#else /* WORDS_BIGENDIAN */
+#define mrn_byte_order_host_to_network(buf, key, size) \
+{ \
+ uint32 size_ = (uint32)(size); \
+ uint8 *buf_ = (uint8 *)(buf); \
+ uint8 *key_ = (uint8 *)(key) + size_; \
+ while (size_--) { *buf_++ = *(--key_); } \
+}
+#endif /* WORDS_BIGENDIAN */
+
+namespace mrn {
+ MultipleColumnKeyCodec::MultipleColumnKeyCodec(grn_ctx *ctx,
+ THD *thread,
+ KEY *key_info)
+ : ctx_(ctx),
+ thread_(thread),
+ key_info_(key_info) {
+ }
+
+ MultipleColumnKeyCodec::~MultipleColumnKeyCodec() {
+ }
+
+ int MultipleColumnKeyCodec::encode(const uchar *mysql_key,
+ uint mysql_key_length,
+ uchar *grn_key,
+ uint *grn_key_length) {
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ const uchar *current_mysql_key = mysql_key;
+ const uchar *mysql_key_end = mysql_key + mysql_key_length;
+ uchar *current_grn_key = grn_key;
+
+ int n_key_parts = KEY_N_KEY_PARTS(key_info_);
+ DBUG_PRINT("info", ("mroonga: n_key_parts=%d", n_key_parts));
+ *grn_key_length = 0;
+ for (int i = 0; i < n_key_parts && current_mysql_key < mysql_key_end; i++) {
+ KEY_PART_INFO *key_part = &(key_info_->key_part[i]);
+ Field *field = key_part->field;
+ DBUG_PRINT("info", ("mroonga: key_part->length=%u", key_part->length));
+
+ if (field->null_bit) {
+ DBUG_PRINT("info", ("mroonga: field has null bit"));
+ *current_grn_key = 0;
+ current_mysql_key += 1;
+ current_grn_key += 1;
+ (*grn_key_length)++;
+ }
+
+ DataType data_type = TYPE_UNKNOWN;
+ uint data_size = 0;
+ get_key_info(key_part, &data_type, &data_size);
+
+ switch (data_type) {
+ case TYPE_UNKNOWN:
+ // TODO: This will not be happen. This is just for
+ // suppressing warnings by gcc -O2. :<
+ error = HA_ERR_UNSUPPORTED;
+ break;
+ case TYPE_LONG_LONG_NUMBER:
+ {
+ long long int long_long_value = 0;
+ switch (data_size) {
+ case 3:
+ long_long_value = (long long int)sint3korr(current_mysql_key);
+ break;
+ case 8:
+ long_long_value = (long long int)sint8korr(current_mysql_key);
+ break;
+ }
+ mrn_byte_order_host_to_network(current_grn_key, &long_long_value,
+ data_size);
+ *((uint8 *)(current_grn_key)) ^= 0x80;
+ }
+ break;
+ case TYPE_NUMBER:
+ mrn_byte_order_host_to_network(current_grn_key, current_mysql_key, data_size);
+ {
+ Field_num *number_field = (Field_num *)field;
+ if (!number_field->unsigned_flag) {
+ *((uint8 *)(current_grn_key)) ^= 0x80;
+ }
+ }
+ break;
+ case TYPE_FLOAT:
+ {
+ float value;
+ float4get(value, current_mysql_key);
+ encode_float(value, data_size, current_grn_key);
+ }
+ break;
+ case TYPE_DOUBLE:
+ {
+ double value;
+ float8get(value, current_mysql_key);
+ encode_double(value, data_size, current_grn_key);
+ }
+ break;
+ case TYPE_BYTE_SEQUENCE:
+ memcpy(current_grn_key, current_mysql_key, data_size);
+ break;
+ case TYPE_BYTE_REVERSE:
+ encode_reverse(current_mysql_key, data_size, current_grn_key);
+ break;
+ case TYPE_BYTE_BLOB:
+ encode_blob(field, current_mysql_key, current_grn_key, &data_size);
+ break;
+ }
+
+ if (error) {
+ break;
+ }
+
+ current_mysql_key += data_size;
+ current_grn_key += data_size;
+ *grn_key_length += data_size;
+ }
+
+ DBUG_RETURN(error);
+ }
+
+ int MultipleColumnKeyCodec::decode(const uchar *grn_key,
+ uint grn_key_length,
+ uchar *mysql_key,
+ uint *mysql_key_length) {
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ const uchar *current_grn_key = grn_key;
+ const uchar *grn_key_end = grn_key + grn_key_length;
+ uchar *current_mysql_key = mysql_key;
+
+ int n_key_parts = KEY_N_KEY_PARTS(key_info_);
+ DBUG_PRINT("info", ("mroonga: n_key_parts=%d", n_key_parts));
+ *mysql_key_length = 0;
+ for (int i = 0; i < n_key_parts && current_grn_key < grn_key_end; i++) {
+ KEY_PART_INFO *key_part = &(key_info_->key_part[i]);
+ Field *field = key_part->field;
+ DBUG_PRINT("info", ("mroonga: key_part->length=%u", key_part->length));
+
+ if (field->null_bit) {
+ DBUG_PRINT("info", ("mroonga: field has null bit"));
+ *current_mysql_key = 0;
+ current_grn_key += 1;
+ current_mysql_key += 1;
+ (*mysql_key_length)++;
+ }
+
+ DataType data_type = TYPE_UNKNOWN;
+ uint data_size = 0;
+ get_key_info(key_part, &data_type, &data_size);
+
+ switch (data_type) {
+ case TYPE_UNKNOWN:
+ // TODO: This will not be happen. This is just for
+ // suppressing warnings by gcc -O2. :<
+ error = HA_ERR_UNSUPPORTED;
+ break;
+ case TYPE_LONG_LONG_NUMBER:
+ {
+ long long int long_long_value = 0;
+ switch (data_size) {
+ case 3:
+ long_long_value = (long long int)sint3korr(current_grn_key);
+ break;
+ case 8:
+ long_long_value = (long long int)sint8korr(current_grn_key);
+ break;
+ }
+ *((uint8 *)(&long_long_value)) ^= 0x80;
+ mrn_byte_order_host_to_network(current_mysql_key, &long_long_value,
+ data_size);
+ }
+ break;
+ case TYPE_NUMBER:
+ {
+ uchar buffer[8];
+ memcpy(buffer, current_grn_key, data_size);
+ Field_num *number_field = (Field_num *)field;
+ if (!number_field->unsigned_flag) {
+ buffer[0] ^= 0x80;
+ }
+ mrn_byte_order_host_to_network(current_mysql_key, buffer,
+ data_size);
+ }
+ break;
+ case TYPE_FLOAT:
+ decode_float(current_grn_key, current_mysql_key, data_size);
+ break;
+ case TYPE_DOUBLE:
+ decode_double(current_grn_key, current_mysql_key, data_size);
+ break;
+ case TYPE_BYTE_SEQUENCE:
+ memcpy(current_mysql_key, current_grn_key, data_size);
+ break;
+ case TYPE_BYTE_REVERSE:
+ decode_reverse(current_grn_key, current_mysql_key, data_size);
+ break;
+ case TYPE_BYTE_BLOB:
+ memcpy(current_mysql_key,
+ current_grn_key + data_size,
+ HA_KEY_BLOB_LENGTH);
+ memcpy(current_mysql_key + HA_KEY_BLOB_LENGTH,
+ current_grn_key,
+ data_size);
+ data_size += HA_KEY_BLOB_LENGTH;
+ break;
+ }
+
+ if (error) {
+ break;
+ }
+
+ current_grn_key += data_size;
+ current_mysql_key += data_size;
+ *mysql_key_length += data_size;
+ }
+
+ DBUG_RETURN(error);
+ }
+
+ uint MultipleColumnKeyCodec::size() {
+ MRN_DBUG_ENTER_METHOD();
+
+ int n_key_parts = KEY_N_KEY_PARTS(key_info_);
+ DBUG_PRINT("info", ("mroonga: n_key_parts=%d", n_key_parts));
+
+ uint total_size = 0;
+ for (int i = 0; i < n_key_parts; ++i) {
+ KEY_PART_INFO *key_part = &(key_info_->key_part[i]);
+ Field *field = key_part->field;
+ DBUG_PRINT("info", ("mroonga: key_part->length=%u", key_part->length));
+
+ if (field->null_bit) {
+ DBUG_PRINT("info", ("mroonga: field has null bit"));
+ ++total_size;
+ }
+
+ DataType data_type = TYPE_UNKNOWN;
+ uint data_size = 0;
+ get_key_info(key_part, &data_type, &data_size);
+ total_size += data_size;
+ if (data_type == TYPE_BYTE_BLOB) {
+ total_size += HA_KEY_BLOB_LENGTH;
+ }
+ }
+
+ DBUG_RETURN(total_size);
+ }
+
+ void MultipleColumnKeyCodec::get_key_info(KEY_PART_INFO *key_part,
+ DataType *data_type,
+ uint *data_size) {
+ MRN_DBUG_ENTER_METHOD();
+
+ *data_type = TYPE_UNKNOWN;
+ *data_size = 0;
+
+ Field *field = key_part->field;
+ switch (field->real_type()) {
+ case MYSQL_TYPE_DECIMAL:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_DECIMAL"));
+ *data_type = TYPE_BYTE_SEQUENCE;
+ *data_size = key_part->length;
+ break;
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_YEAR:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_TINY"));
+ *data_type = TYPE_NUMBER;
+ *data_size = 1;
+ break;
+ case MYSQL_TYPE_SHORT:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_SHORT"));
+ *data_type = TYPE_NUMBER;
+ *data_size = 2;
+ break;
+ case MYSQL_TYPE_LONG:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_LONG"));
+ *data_type = TYPE_NUMBER;
+ *data_size = 4;
+ break;
+ case MYSQL_TYPE_FLOAT:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_FLOAT"));
+ *data_type = TYPE_FLOAT;
+ *data_size = 4;
+ break;
+ case MYSQL_TYPE_DOUBLE:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_DOUBLE"));
+ *data_type = TYPE_DOUBLE;
+ *data_size = 8;
+ break;
+ case MYSQL_TYPE_NULL:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_NULL"));
+ *data_type = TYPE_NUMBER;
+ *data_size = 1;
+ break;
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_NEWDATE:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_DATETIME"));
+ *data_type = TYPE_BYTE_REVERSE;
+ *data_size = key_part->length;
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_LONGLONG"));
+ *data_type = TYPE_NUMBER;
+ *data_size = 8;
+ break;
+ case MYSQL_TYPE_INT24:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_INT24"));
+ *data_type = TYPE_NUMBER;
+ *data_size = 3;
+ break;
+ case MYSQL_TYPE_TIME:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_TIME"));
+ *data_type = TYPE_LONG_LONG_NUMBER;
+ *data_size = 3;
+ break;
+ case MYSQL_TYPE_VARCHAR:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_VARCHAR"));
+ *data_type = TYPE_BYTE_BLOB;
+ *data_size = key_part->length;
+ break;
+ case MYSQL_TYPE_BIT:
+ // TODO
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_BIT"));
+ *data_type = TYPE_NUMBER;
+ *data_size = 1;
+ break;
+#ifdef MRN_HAVE_MYSQL_TYPE_TIMESTAMP2
+ case MYSQL_TYPE_TIMESTAMP2:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_TIMESTAMP2"));
+ *data_type = TYPE_BYTE_SEQUENCE;
+ *data_size = key_part->length;
+ break;
+#endif
+#ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
+ case MYSQL_TYPE_DATETIME2:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_DATETIME2"));
+ *data_type = TYPE_BYTE_SEQUENCE;
+ *data_size = key_part->length;
+ break;
+#endif
+#ifdef MRN_HAVE_MYSQL_TYPE_TIME2
+ case MYSQL_TYPE_TIME2:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_TIME2"));
+ *data_type = TYPE_BYTE_SEQUENCE;
+ *data_size = key_part->length;
+ break;
+#endif
+ case MYSQL_TYPE_NEWDECIMAL:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_NEWDECIMAL"));
+ *data_type = TYPE_BYTE_SEQUENCE;
+ *data_size = key_part->length;
+ break;
+ case MYSQL_TYPE_ENUM:
+ // TODO
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_ENUM"));
+ *data_type = TYPE_NUMBER;
+ *data_size = 1;
+ break;
+ case MYSQL_TYPE_SET:
+ // TODO
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_SET"));
+ *data_type = TYPE_NUMBER;
+ *data_size = 1;
+ break;
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ // TODO
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_BLOB"));
+ *data_type = TYPE_BYTE_BLOB;
+ *data_size = key_part->length;
+ break;
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ // TODO
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_STRING"));
+ *data_type = TYPE_BYTE_SEQUENCE;
+ *data_size = key_part->length;
+ break;
+ case MYSQL_TYPE_GEOMETRY:
+ // TODO
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_GEOMETRY"));
+ *data_type = TYPE_BYTE_SEQUENCE;
+ *data_size = key_part->length;
+ break;
+ }
+ DBUG_VOID_RETURN;
+ }
+
+ void MultipleColumnKeyCodec::encode_float(volatile float value, uint data_size,
+ uchar *grn_key) {
+ MRN_DBUG_ENTER_METHOD();
+ int n_bits = (data_size * 8 - 1);
+ volatile int *int_value_pointer = (int *)(&value);
+ int int_value = *int_value_pointer;
+ int_value ^= ((int_value >> n_bits) | (1 << n_bits));
+ mrn_byte_order_host_to_network(grn_key, &int_value, data_size);
+ DBUG_VOID_RETURN;
+ }
+
+ void MultipleColumnKeyCodec::decode_float(const uchar *grn_key,
+ uchar *mysql_key,
+ uint data_size) {
+ MRN_DBUG_ENTER_METHOD();
+ int int_value;
+ mrn_byte_order_host_to_network(&int_value, grn_key, data_size);
+ int max_bit = (data_size * 8 - 1);
+ *((int *)mysql_key) =
+ int_value ^ (((int_value ^ (1 << max_bit)) >> max_bit) |
+ (1 << max_bit));
+ DBUG_VOID_RETURN;
+ }
+
+ void MultipleColumnKeyCodec::encode_double(volatile double value, uint data_size,
+ uchar *grn_key) {
+ MRN_DBUG_ENTER_METHOD();
+ int n_bits = (data_size * 8 - 1);
+ volatile long long int *long_long_value_pointer = (long long int *)(&value);
+ volatile long long int long_long_value = *long_long_value_pointer;
+ long_long_value ^= ((long_long_value >> n_bits) | (1LL << n_bits));
+ mrn_byte_order_host_to_network(grn_key, &long_long_value, data_size);
+ DBUG_VOID_RETURN;
+ }
+
+ void MultipleColumnKeyCodec::decode_double(const uchar *grn_key,
+ uchar *mysql_key,
+ uint data_size) {
+ MRN_DBUG_ENTER_METHOD();
+ long long int long_long_value;
+ mrn_byte_order_host_to_network(&long_long_value, grn_key, data_size);
+ int max_bit = (data_size * 8 - 1);
+ *((long long int *)mysql_key) =
+ long_long_value ^ (((long_long_value ^ (1LL << max_bit)) >> max_bit) |
+ (1LL << max_bit));
+ DBUG_VOID_RETURN;
+ }
+
+ void MultipleColumnKeyCodec::encode_reverse(const uchar *mysql_key, uint data_size,
+ uchar *grn_key) {
+ MRN_DBUG_ENTER_METHOD();
+ for (uint i = 0; i < data_size; i++) {
+ grn_key[i] = mysql_key[data_size - i - 1];
+ }
+ DBUG_VOID_RETURN;
+ }
+
+ void MultipleColumnKeyCodec::decode_reverse(const uchar *grn_key,
+ uchar *mysql_key,
+ uint data_size) {
+ MRN_DBUG_ENTER_METHOD();
+ for (uint i = 0; i < data_size; i++) {
+ mysql_key[i] = grn_key[data_size - i - 1];
+ }
+ DBUG_VOID_RETURN;
+ }
+
+ void MultipleColumnKeyCodec::encode_blob(Field *field,
+ const uchar *mysql_key,
+ uchar *grn_key,
+ uint *data_size) {
+ FieldNormalizer normalizer(ctx_, thread_, field);
+ if (normalizer.should_normalize()) {
+#if HA_KEY_BLOB_LENGTH != 2
+# error "TODO: support HA_KEY_BLOB_LENGTH != 2 case if it is needed"
+#endif
+ const char *blob_data =
+ reinterpret_cast<const char *>(mysql_key + HA_KEY_BLOB_LENGTH);
+ uint16 blob_data_length = *((uint16 *)(mysql_key));
+ grn_obj *grn_string = normalizer.normalize(blob_data,
+ blob_data_length);
+ mrn::SmartGrnObj smart_grn_string(ctx_, grn_string);
+ const char *normalized;
+ unsigned int normalized_length = 0;
+ grn_string_get_normalized(ctx_, grn_string,
+ &normalized, &normalized_length, NULL);
+ uint16 new_blob_data_length;
+ if (normalized_length <= UINT_MAX16) {
+ memcpy(grn_key, normalized, normalized_length);
+ if (normalized_length < *data_size) {
+ memset(grn_key + normalized_length,
+ '\0', *data_size - normalized_length);
+ }
+ new_blob_data_length = normalized_length;
+ } else {
+ push_warning_printf(thread_,
+ Sql_condition::WARN_LEVEL_WARN,
+ WARN_DATA_TRUNCATED,
+ "normalized data truncated "
+ "for multiple column index: "
+ "normalized-data-size: <%u> "
+ "max-data-size: <%u> "
+ "column-name: <%s> "
+ "data: <%.*s>",
+ normalized_length,
+ UINT_MAX16,
+ field->field_name,
+ blob_data_length, blob_data);
+ memcpy(grn_key, normalized, blob_data_length);
+ new_blob_data_length = blob_data_length;
+ }
+ memcpy(grn_key + *data_size, &new_blob_data_length, HA_KEY_BLOB_LENGTH);
+ } else {
+ memcpy(grn_key + *data_size, mysql_key, HA_KEY_BLOB_LENGTH);
+ memcpy(grn_key, mysql_key + HA_KEY_BLOB_LENGTH, *data_size);
+ }
+ *data_size += HA_KEY_BLOB_LENGTH;
+ }
+}
diff --git a/storage/mroonga/lib/mrn_multiple_column_key_codec.hpp b/storage/mroonga/lib/mrn_multiple_column_key_codec.hpp
new file mode 100644
index 00000000000..fc6ae285357
--- /dev/null
+++ b/storage/mroonga/lib/mrn_multiple_column_key_codec.hpp
@@ -0,0 +1,70 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012-2013 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MRN_MULTIPLE_COLUMN_KEY_CODEC_HPP_
+#define MRN_MULTIPLE_COLUMN_KEY_CODEC_HPP_
+
+#include <groonga.h>
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+
+namespace mrn {
+ class MultipleColumnKeyCodec {
+ public:
+ MultipleColumnKeyCodec(grn_ctx *ctx, THD *thread, KEY *key_info);
+ ~MultipleColumnKeyCodec();
+
+ int encode(const uchar *mysql_key, uint mysql_key_length,
+ uchar *grn_key, uint *grn_key_length);
+ int decode(const uchar *grn_key, uint grn_key_length,
+ uchar *mysql_key, uint *mysql_key_length);
+ uint size();
+
+ private:
+ enum DataType {
+ TYPE_UNKNOWN,
+ TYPE_LONG_LONG_NUMBER,
+ TYPE_NUMBER,
+ TYPE_FLOAT,
+ TYPE_DOUBLE,
+ TYPE_BYTE_SEQUENCE,
+ TYPE_BYTE_REVERSE,
+ TYPE_BYTE_BLOB
+ };
+
+ grn_ctx *ctx_;
+ THD *thread_;
+ KEY *key_info_;
+
+ void get_key_info(KEY_PART_INFO *key_part,
+ DataType *data_type, uint *data_size);
+
+ void encode_float(volatile float value, uint data_size, uchar *grn_key);
+ void decode_float(const uchar *grn_key, uchar *mysql_key, uint data_size);
+ void encode_double(volatile double value, uint data_size, uchar *grn_key);
+ void decode_double(const uchar *grn_key, uchar *mysql_key, uint data_size);
+ void encode_reverse(const uchar *mysql_key, uint data_size, uchar *grn_key);
+ void decode_reverse(const uchar *grn_key, uchar *mysql_key, uint data_size);
+ void encode_blob(Field *field,
+ const uchar *mysql_key, uchar *grn_key, uint *data_size);
+ };
+}
+
+#endif // MRN_MULTIPLE_COLUMN_KEY_CODEC_HPP_
diff --git a/storage/mroonga/lib/mrn_mysqlservices.cpp b/storage/mroonga/lib/mrn_mysqlservices.cpp
new file mode 100644
index 00000000000..9c7af9acfe0
--- /dev/null
+++ b/storage/mroonga/lib/mrn_mysqlservices.cpp
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2; indent-tabs-mode: nil -*- */
+/*
+ Copyright(C) 2011-2013 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+
+/*
+void *thd_alloc(MYSQL_THD thd, unsigned int size)
+{
+ return thd->alloc(size);
+}
+*/
diff --git a/storage/mroonga/lib/mrn_parameters_parser.cpp b/storage/mroonga/lib/mrn_parameters_parser.cpp
new file mode 100644
index 00000000000..9a05097e548
--- /dev/null
+++ b/storage/mroonga/lib/mrn_parameters_parser.cpp
@@ -0,0 +1,176 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2013 Kentoku SHIBA
+ Copyright(C) 2011-2013 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "mrn_parameters_parser.hpp"
+
+#include <mrn_mysql_compat.h>
+
+namespace mrn {
+ class Parameter {
+ public:
+ char *key_;
+ char *value_;
+
+ Parameter(const char *key, unsigned int key_length,
+ const char *value, unsigned int value_length)
+ : key_(my_strndup(key, key_length, MYF(0))),
+ value_(my_strndup(value, value_length, MYF(0))) {
+ };
+ ~Parameter() {
+ if (key_) {
+ my_free(key_, MYF(0));
+ }
+ if (value_) {
+ my_free(value_, MYF(0));
+ }
+ };
+ };
+
+ ParametersParser::ParametersParser(const char *input,
+ unsigned int input_length)
+ : input_(input),
+ input_length_(input_length),
+ parameters_(NULL) {
+ }
+
+ ParametersParser::~ParametersParser() {
+ for (LIST *next = parameters_; next; next = next->next) {
+ Parameter *parameter = static_cast<Parameter *>(next->data);
+ delete parameter;
+ }
+ list_free(parameters_, false);
+ }
+
+ void ParametersParser::parse() {
+ const char *current = input_;
+ const char *end = input_ + input_length_;
+ for (; current < end; ++current) {
+ if (is_white_space(current[0])) {
+ continue;
+ }
+
+ const char *key = current;
+ unsigned int key_length = 0;
+ while (current < end &&
+ !is_white_space(current[0]) &&
+ current[0] != '\'' && current[0] != '"' && current[0] != ',') {
+ ++current;
+ ++key_length;
+ }
+ if (current == end) {
+ break;
+ }
+
+ while (current < end && is_white_space(current[0])) {
+ ++current;
+ }
+ if (current == end) {
+ break;
+ }
+ current = parse_value(current, end, key, key_length);
+ if (!current) {
+ break;
+ }
+
+ while (current < end && is_white_space(current[0])) {
+ ++current;
+ }
+ if (current == end) {
+ break;
+ }
+ if (current[0] != ',') {
+ // TODO: report error
+ break;
+ }
+ }
+ }
+
+ const char *ParametersParser::parse_value(const char *current,
+ const char *end,
+ const char *key,
+ unsigned int key_length) {
+ char quote = current[0];
+ if (quote != '\'' && quote != '"') {
+ // TODO: report error
+ return NULL;
+ }
+ ++current;
+
+ bool found = false;
+ static const unsigned int max_value_length = 4096;
+ char value[max_value_length];
+ unsigned int value_length = 0;
+ for (; current < end && value_length < max_value_length; ++current) {
+ if (current[0] == quote) {
+ Parameter *parameter = new Parameter(key, key_length,
+ value, value_length);
+ list_push(parameters_, parameter);
+ found = true;
+ ++current;
+ break;
+ }
+
+ switch (current[0]) {
+ case '\\':
+ if (current + 1 == end) {
+ break;
+ }
+ switch (current[1]) {
+ case 'b':
+ value[value_length] = '\b';
+ break;
+ case 'n':
+ value[value_length] = '\n';
+ break;
+ case 'r':
+ value[value_length] = '\r';
+ break;
+ case 't':
+ value[value_length] = '\t';
+ break;
+ default:
+ value[value_length] = current[1];
+ break;
+ }
+ break;
+ default:
+ value[value_length] = current[0];
+ break;
+ }
+ ++value_length;
+ }
+
+ if (!found) {
+ // TODO: report error
+ }
+
+ return current;
+ }
+
+ const char *ParametersParser::operator[](const char *key) {
+ for (LIST *next = parameters_; next; next = next->next) {
+ Parameter *parameter = static_cast<Parameter *>(next->data);
+ if (strcasecmp(parameter->key_, key) == 0) {
+ return parameter->value_;
+ }
+ }
+ return NULL;
+ }
+}
diff --git a/storage/mroonga/lib/mrn_parameters_parser.hpp b/storage/mroonga/lib/mrn_parameters_parser.hpp
new file mode 100644
index 00000000000..a15371ca72e
--- /dev/null
+++ b/storage/mroonga/lib/mrn_parameters_parser.hpp
@@ -0,0 +1,59 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2013 Kentoku SHIBA
+ Copyright(C) 2011-2013 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MRN_PARAMETERS_PARSER_HPP_
+#define MRN_PARAMETERS_PARSER_HPP_
+
+#include <mrn_mysql.h>
+#include <my_list.h>
+
+namespace mrn {
+ class ParametersParser {
+ public:
+ ParametersParser(const char *input, unsigned int input_length);
+ ~ParametersParser();
+ void parse();
+ const char *operator[](const char *key);
+
+ private:
+ const char *input_;
+ unsigned int input_length_;
+
+ LIST *parameters_;
+
+ bool is_white_space(char character) {
+ switch (character) {
+ case ' ':
+ case '\r':
+ case '\n':
+ case '\t':
+ return true;
+ break;
+ default:
+ return false;
+ break;
+ }
+ };
+ const char *parse_value(const char *current, const char *end,
+ const char *key, unsigned int key_length);
+ };
+}
+
+#endif /* MRN_PARAMETERS_PARSER_HPP_ */
diff --git a/storage/mroonga/lib/mrn_path_mapper.cpp b/storage/mroonga/lib/mrn_path_mapper.cpp
new file mode 100644
index 00000000000..8856e6f6082
--- /dev/null
+++ b/storage/mroonga/lib/mrn_path_mapper.cpp
@@ -0,0 +1,196 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010 Tetsuro IKEDA
+ Copyright(C) 2011-2013 Kentoku SHIBA
+ Copyright(C) 2011-2012 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "mrn_path_mapper.hpp"
+
+#include <string.h>
+
+#include <mrn_mysql.h>
+
+namespace mrn {
+ char *PathMapper::default_path_prefix = NULL;
+ char *PathMapper::default_mysql_data_home_path = NULL;
+
+ PathMapper::PathMapper(const char *mysql_path,
+ const char *path_prefix,
+ const char *mysql_data_home_path)
+ : mysql_path_(mysql_path),
+ path_prefix_(path_prefix),
+ mysql_data_home_path_(mysql_data_home_path) {
+ db_path_[0] = '\0';
+ db_name_[0] = '\0';
+ table_name_[0] = '\0';
+ mysql_table_name_[0] = '\0';
+ }
+
+ /**
+ * "./${db}/${table}" ==> "${db}.mrn"
+ * "./${db}/" ==> "${db}.mrn"
+ * "/tmp/mysql-test/var/tmp/mysqld.1/#sql27c5_1_0" ==>
+ * "/tmp/mysql-test/var/tmp/mysqld.1/#sql27c5_1_0.mrn"
+ */
+ const char *PathMapper::db_path() {
+ if (db_path_[0] != '\0') {
+ return db_path_;
+ }
+
+ if (mysql_path_[0] == FN_CURLIB && mysql_path_[1] == FN_LIBCHAR) {
+ if (path_prefix_) {
+ strcpy(db_path_, path_prefix_);
+ }
+
+ int i = 2, j = strlen(db_path_), len;
+ len = strlen(mysql_path_);
+ while (mysql_path_[i] != FN_LIBCHAR && i < len) {
+ db_path_[j++] = mysql_path_[i++];
+ }
+ db_path_[j] = '\0';
+ } else if (mysql_data_home_path_) {
+ int len = strlen(mysql_path_);
+ int mysql_data_home_len = strlen(mysql_data_home_path_);
+ if (len > mysql_data_home_len &&
+ !strncmp(mysql_path_, mysql_data_home_path_, mysql_data_home_len)) {
+ int i = mysql_data_home_len, j;
+ if (path_prefix_ && path_prefix_[0] == FN_LIBCHAR) {
+ strcpy(db_path_, path_prefix_);
+ j = strlen(db_path_);
+ } else {
+ memcpy(db_path_, mysql_data_home_path_, mysql_data_home_len);
+ if (path_prefix_) {
+ if (path_prefix_[0] == FN_CURLIB &&
+ path_prefix_[1] == FN_LIBCHAR) {
+ strcpy(&db_path_[mysql_data_home_len], &path_prefix_[2]);
+ } else {
+ strcpy(&db_path_[mysql_data_home_len], path_prefix_);
+ }
+ j = strlen(db_path_);
+ } else {
+ j = mysql_data_home_len;
+ }
+ }
+
+ while (mysql_path_[i] != FN_LIBCHAR && i < len) {
+ db_path_[j++] = mysql_path_[i++];
+ }
+ if (i == len) {
+ memcpy(db_path_, mysql_path_, len);
+ } else {
+ db_path_[j] = '\0';
+ }
+ } else {
+ strcpy(db_path_, mysql_path_);
+ }
+ } else {
+ strcpy(db_path_, mysql_path_);
+ }
+ strcat(db_path_, MRN_DB_FILE_SUFFIX);
+ return db_path_;
+ }
+
+ /**
+ * "./${db}/${table}" ==> "${db}"
+ * "./${db}/" ==> "${db}"
+ * "/tmp/mysql-test/var/tmp/mysqld.1/#sql27c5_1_0" ==>
+ * "/tmp/mysql-test/var/tmp/mysqld.1/#sql27c5_1_0"
+ */
+ const char *PathMapper::db_name() {
+ if (db_name_[0] != '\0') {
+ return db_name_;
+ }
+
+ if (mysql_path_[0] == FN_CURLIB && mysql_path_[1] == FN_LIBCHAR) {
+ int i = 2, j = 0, len;
+ len = strlen(mysql_path_);
+ while (mysql_path_[i] != FN_LIBCHAR && i < len) {
+ db_name_[j++] = mysql_path_[i++];
+ }
+ db_name_[j] = '\0';
+ } else if (mysql_data_home_path_) {
+ int len = strlen(mysql_path_);
+ int mysql_data_home_len = strlen(mysql_data_home_path_);
+ if (len > mysql_data_home_len &&
+ !strncmp(mysql_path_, mysql_data_home_path_, mysql_data_home_len)) {
+ int i = mysql_data_home_len, j = 0;
+ while (mysql_path_[i] != FN_LIBCHAR && i < len) {
+ db_name_[j++] = mysql_path_[i++];
+ }
+ if (i == len) {
+ memcpy(db_name_, mysql_path_, len);
+ } else {
+ db_name_[j] = '\0';
+ }
+ } else {
+ strcpy(db_name_, mysql_path_);
+ }
+ } else {
+ strcpy(db_name_, mysql_path_);
+ }
+ return db_name_;
+ }
+
+ /**
+ * "./${db}/${table}" ==> "${table}" (with encoding first '_')
+ */
+ const char *PathMapper::table_name() {
+ if (table_name_[0] != '\0') {
+ return table_name_;
+ }
+
+ int len = strlen(mysql_path_);
+ int i = len, j = 0;
+ for (; mysql_path_[--i] != FN_LIBCHAR ;) {}
+ if (mysql_path_[i + 1] == '_') {
+ table_name_[j++] = '@';
+ table_name_[j++] = '0';
+ table_name_[j++] = '0';
+ table_name_[j++] = '5';
+ table_name_[j++] = 'f';
+ i++;
+ }
+ for (; i < len ;) {
+ table_name_[j++] = mysql_path_[++i];
+ }
+ table_name_[j] = '\0';
+ return table_name_;
+ }
+
+ /**
+ * "./${db}/${table}" ==> "${table}" (without encoding first '_')
+ */
+ const char *PathMapper::mysql_table_name() {
+ if (mysql_table_name_[0] != '\0') {
+ return mysql_table_name_;
+ }
+
+ int len = strlen(mysql_path_);
+ int i = len, j = 0;
+ for (; mysql_path_[--i] != FN_LIBCHAR ;) {}
+ for (; i < len ;) {
+ mysql_table_name_[j++] = mysql_path_[++i];
+ }
+ mysql_table_name_[j] = '\0';
+ return mysql_table_name_;
+ }
+}
diff --git a/storage/mroonga/lib/mrn_path_mapper.hpp b/storage/mroonga/lib/mrn_path_mapper.hpp
new file mode 100644
index 00000000000..f70cd7b5587
--- /dev/null
+++ b/storage/mroonga/lib/mrn_path_mapper.hpp
@@ -0,0 +1,51 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010 Tetsuro IKEDA
+ Copyright(C) 2010-2013 Kentoku SHIBA
+ Copyright(C) 2011-2012 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MRN_PATH_MAPPER_HPP_
+#define MRN_PATH_MAPPER_HPP_
+
+#include <mrn_constants.hpp>
+
+namespace mrn {
+ class PathMapper {
+ public:
+ static char *default_path_prefix;
+ static char *default_mysql_data_home_path;
+
+ PathMapper(const char *mysql_path,
+ const char *path_prefix=default_path_prefix,
+ const char *mysql_data_home_path=default_mysql_data_home_path);
+ const char *db_path();
+ const char *db_name();
+ const char *table_name();
+ const char *mysql_table_name();
+ private:
+ const char *mysql_path_;
+ const char *path_prefix_;
+ const char *mysql_data_home_path_;
+ char db_path_[MRN_MAX_PATH_SIZE];
+ char db_name_[MRN_MAX_PATH_SIZE];
+ char table_name_[MRN_MAX_PATH_SIZE];
+ char mysql_table_name_[MRN_MAX_PATH_SIZE];
+ };
+}
+
+#endif /* MRN_PATH_MAPPER_HPP_ */
diff --git a/storage/mroonga/lib/mrn_smart_grn_obj.cpp b/storage/mroonga/lib/mrn_smart_grn_obj.cpp
new file mode 100644
index 00000000000..9dbae6528f9
--- /dev/null
+++ b/storage/mroonga/lib/mrn_smart_grn_obj.cpp
@@ -0,0 +1,53 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include <string.h>
+
+#include "mrn_smart_grn_obj.hpp"
+
+namespace mrn {
+ SmartGrnObj::SmartGrnObj(grn_ctx *ctx, grn_obj *obj)
+ : ctx_(ctx),
+ obj_(obj) {
+ }
+
+ SmartGrnObj::SmartGrnObj(grn_ctx *ctx, const char *name, int name_size)
+ : ctx_(ctx),
+ obj_(NULL) {
+ if (name_size < 0) {
+ name_size = strlen(name);
+ }
+ obj_ = grn_ctx_get(ctx_, name, name_size);
+ }
+
+ SmartGrnObj::SmartGrnObj(grn_ctx *ctx, grn_id id)
+ : ctx_(ctx),
+ obj_(grn_ctx_at(ctx_, id)) {
+ }
+
+ SmartGrnObj::~SmartGrnObj() {
+ if (obj_) {
+ grn_obj_unlink(ctx_, obj_);
+ }
+ }
+
+ grn_obj *SmartGrnObj::get() {
+ return obj_;
+ }
+}
diff --git a/storage/mroonga/lib/mrn_smart_grn_obj.hpp b/storage/mroonga/lib/mrn_smart_grn_obj.hpp
new file mode 100644
index 00000000000..c9c86f3e46e
--- /dev/null
+++ b/storage/mroonga/lib/mrn_smart_grn_obj.hpp
@@ -0,0 +1,39 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MRN_SMART_GRN_OBJ_HPP_
+#define MRN_SMART_GRN_OBJ_HPP_
+
+#include <groonga.h>
+
+namespace mrn {
+ class SmartGrnObj {
+ grn_ctx *ctx_;
+ grn_obj *obj_;
+ public:
+ SmartGrnObj(grn_ctx *ctx, grn_obj *obj);
+ SmartGrnObj(grn_ctx *ctx, const char *name, int name_size=-1);
+ SmartGrnObj(grn_ctx *ctx, grn_id id);
+ ~SmartGrnObj();
+
+ grn_obj *get();
+ };
+}
+
+#endif // MRN_SMART_GRN_OBJ_HPP_
diff --git a/storage/mroonga/lib/mrn_time_converter.cpp b/storage/mroonga/lib/mrn_time_converter.cpp
new file mode 100644
index 00000000000..63b2e53766d
--- /dev/null
+++ b/storage/mroonga/lib/mrn_time_converter.cpp
@@ -0,0 +1,260 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2013 Kentoku SHIBA
+ Copyright(C) 2011-2013 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "mrn_time_converter.hpp"
+
+#ifdef min
+# undef min
+#endif
+#ifdef max
+# undef max
+#endif
+
+#include <limits>
+
+// for debug
+#define MRN_CLASS_NAME "mrn::TimeConverter"
+
+namespace mrn {
+ TimeConverter::TimeConverter() {
+ }
+
+ TimeConverter::~TimeConverter() {
+ }
+
+ time_t TimeConverter::tm_to_time_gm(struct tm *time, bool *truncated) {
+ MRN_DBUG_ENTER_METHOD();
+ *truncated = true;
+ struct tm gmdate;
+ time->tm_yday = -1;
+ time->tm_isdst = -1;
+ time_t sec_t = mktime(time);
+ if (time->tm_yday == -1) {
+ DBUG_RETURN(-1);
+ }
+ if (!gmtime_r(&sec_t, &gmdate)) {
+ DBUG_RETURN(-1);
+ }
+ int32 mrn_utc_diff_in_seconds =
+ (
+ time->tm_mday > 25 && gmdate.tm_mday == 1 ? -1 :
+ time->tm_mday == 1 && gmdate.tm_mday > 25 ? 1 :
+ time->tm_mday - gmdate.tm_mday
+ ) * 24 * 60 * 60 +
+ (time->tm_hour - gmdate.tm_hour) * 60 * 60 +
+ (time->tm_min - gmdate.tm_min) * 60 +
+ (time->tm_sec - gmdate.tm_sec);
+ DBUG_PRINT("info", ("mroonga: time->tm_year=%d", time->tm_year));
+ DBUG_PRINT("info", ("mroonga: time->tm_mon=%d", time->tm_mon));
+ DBUG_PRINT("info", ("mroonga: time->tm_mday=%d", time->tm_mday));
+ DBUG_PRINT("info", ("mroonga: time->tm_hour=%d", time->tm_hour));
+ DBUG_PRINT("info", ("mroonga: time->tm_min=%d", time->tm_min));
+ DBUG_PRINT("info", ("mroonga: time->tm_sec=%d", time->tm_sec));
+ DBUG_PRINT("info", ("mroonga: mrn_utc_diff_in_seconds=%d",
+ mrn_utc_diff_in_seconds));
+ if (mrn_utc_diff_in_seconds > 0) {
+ if (sec_t > std::numeric_limits<time_t>::max() - mrn_utc_diff_in_seconds) {
+ DBUG_RETURN(-1);
+ }
+ } else {
+ if (sec_t < std::numeric_limits<time_t>::min() - mrn_utc_diff_in_seconds) {
+ DBUG_RETURN(-1);
+ }
+ }
+ *truncated = false;
+ DBUG_RETURN(sec_t + mrn_utc_diff_in_seconds);
+ }
+
+ long long int TimeConverter::tm_to_grn_time(struct tm *time, int usec,
+ bool *truncated) {
+ MRN_DBUG_ENTER_METHOD();
+
+ long long int sec = tm_to_time_gm(time, truncated);
+
+ DBUG_PRINT("info", ("mroonga: sec=%lld", sec));
+ DBUG_PRINT("info", ("mroonga: usec=%d", usec));
+
+ long long int grn_time = *truncated ? 0 : GRN_TIME_PACK(sec, usec);
+
+ DBUG_RETURN(grn_time);
+ }
+
+ long long int TimeConverter::mysql_time_to_grn_time(MYSQL_TIME *mysql_time,
+ bool *truncated) {
+ MRN_DBUG_ENTER_METHOD();
+
+ int usec = mysql_time->second_part;
+ long long int grn_time = 0;
+
+ *truncated = false;
+ switch (mysql_time->time_type) {
+ case MYSQL_TIMESTAMP_DATE:
+ {
+ DBUG_PRINT("info", ("mroonga: MYSQL_TIMESTAMP_DATE"));
+ struct tm date;
+ memset(&date, 0, sizeof(struct tm));
+ date.tm_year = mysql_time->year - TM_YEAR_BASE;
+ if (mysql_time->month > 0) {
+ date.tm_mon = mysql_time->month - 1;
+ } else {
+ date.tm_mon = 0;
+ *truncated = true;
+ }
+ if (mysql_time->day > 0) {
+ date.tm_mday = mysql_time->day;
+ } else {
+ date.tm_mday = 1;
+ *truncated = true;
+ }
+ DBUG_PRINT("info", ("mroonga: tm_year=%d", date.tm_year));
+ DBUG_PRINT("info", ("mroonga: tm_mon=%d", date.tm_mon));
+ DBUG_PRINT("info", ("mroonga: tm_mday=%d", date.tm_mday));
+ bool tm_truncated = false;
+ grn_time = tm_to_grn_time(&date, usec, &tm_truncated);
+ if (tm_truncated) {
+ *truncated = true;
+ }
+ }
+ break;
+ case MYSQL_TIMESTAMP_DATETIME:
+ {
+ DBUG_PRINT("info", ("mroonga: MYSQL_TIMESTAMP_DATETIME"));
+ struct tm datetime;
+ memset(&datetime, 0, sizeof(struct tm));
+ datetime.tm_year = mysql_time->year - TM_YEAR_BASE;
+ if (mysql_time->month > 0) {
+ datetime.tm_mon = mysql_time->month - 1;
+ } else {
+ datetime.tm_mon = 0;
+ *truncated = true;
+ }
+ if (mysql_time->day > 0) {
+ datetime.tm_mday = mysql_time->day;
+ } else {
+ datetime.tm_mday = 1;
+ *truncated = true;
+ }
+ datetime.tm_hour = mysql_time->hour;
+ datetime.tm_min = mysql_time->minute;
+ datetime.tm_sec = mysql_time->second;
+ DBUG_PRINT("info", ("mroonga: tm_year=%d", datetime.tm_year));
+ DBUG_PRINT("info", ("mroonga: tm_mon=%d", datetime.tm_mon));
+ DBUG_PRINT("info", ("mroonga: tm_mday=%d", datetime.tm_mday));
+ DBUG_PRINT("info", ("mroonga: tm_hour=%d", datetime.tm_hour));
+ DBUG_PRINT("info", ("mroonga: tm_min=%d", datetime.tm_min));
+ DBUG_PRINT("info", ("mroonga: tm_sec=%d", datetime.tm_sec));
+ bool tm_truncated = false;
+ grn_time = tm_to_grn_time(&datetime, usec, &tm_truncated);
+ if (tm_truncated) {
+ *truncated = true;
+ }
+ }
+ break;
+ case MYSQL_TIMESTAMP_TIME:
+ {
+ DBUG_PRINT("info", ("mroonga: MYSQL_TIMESTAMP_TIME"));
+ int sec =
+ mysql_time->hour * 60 * 60 +
+ mysql_time->minute * 60 +
+ mysql_time->second;
+ DBUG_PRINT("info", ("mroonga: sec=%d", sec));
+ grn_time = GRN_TIME_PACK(sec, usec);
+ if (mysql_time->neg) {
+ grn_time = -grn_time;
+ }
+ }
+ break;
+ default:
+ DBUG_PRINT("info", ("mroonga: default"));
+ grn_time = 0;
+ break;
+ }
+
+ DBUG_RETURN(grn_time);
+ }
+
+ void TimeConverter::grn_time_to_mysql_time(long long int grn_time,
+ MYSQL_TIME *mysql_time) {
+ MRN_DBUG_ENTER_METHOD();
+ long long int sec;
+ int usec;
+ GRN_TIME_UNPACK(grn_time, sec, usec);
+ DBUG_PRINT("info", ("mroonga: sec=%lld", sec));
+ DBUG_PRINT("info", ("mroonga: usec=%d", usec));
+ switch (mysql_time->time_type) {
+ case MYSQL_TIMESTAMP_DATE:
+ {
+ DBUG_PRINT("info", ("mroonga: MYSQL_TIMESTAMP_DATE"));
+ struct tm date;
+ time_t sec_t = sec;
+ // TODO: Add error check
+ gmtime_r(&sec_t, &date);
+ DBUG_PRINT("info", ("mroonga: tm_year=%d", date.tm_year));
+ mysql_time->year = date.tm_year + TM_YEAR_BASE;
+ DBUG_PRINT("info", ("mroonga: tm_mon=%d", date.tm_mon));
+ mysql_time->month = date.tm_mon + 1;
+ DBUG_PRINT("info", ("mroonga: tm_mday=%d", date.tm_mday));
+ mysql_time->day = date.tm_mday;
+ }
+ break;
+ case MYSQL_TIMESTAMP_DATETIME:
+ {
+ DBUG_PRINT("info", ("mroonga: MYSQL_TIMESTAMP_DATETIME"));
+ struct tm date;
+ time_t sec_t = sec;
+ // TODO: Add error check
+ gmtime_r(&sec_t, &date);
+ DBUG_PRINT("info", ("mroonga: tm_year=%d", date.tm_year));
+ mysql_time->year = date.tm_year + TM_YEAR_BASE;
+ DBUG_PRINT("info", ("mroonga: tm_mon=%d", date.tm_mon));
+ mysql_time->month = date.tm_mon + 1;
+ DBUG_PRINT("info", ("mroonga: tm_mday=%d", date.tm_mday));
+ mysql_time->day = date.tm_mday;
+ DBUG_PRINT("info", ("mroonga: tm_hour=%d", date.tm_hour));
+ mysql_time->hour = date.tm_hour;
+ DBUG_PRINT("info", ("mroonga: tm_min=%d", date.tm_min));
+ mysql_time->minute = date.tm_min;
+ DBUG_PRINT("info", ("mroonga: tm_sec=%d", date.tm_sec));
+ mysql_time->second = date.tm_sec;
+ mysql_time->second_part = usec;
+ }
+ break;
+ case MYSQL_TIMESTAMP_TIME:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TIMESTAMP_TIME"));
+ if (sec < 0) {
+ mysql_time->neg = true;
+ sec = -sec;
+ }
+ mysql_time->hour = static_cast<unsigned int>(sec / 60 / 60);
+ mysql_time->minute = sec / 60 % 60;
+ mysql_time->second = sec % 60;
+ mysql_time->second_part = usec;
+ break;
+ default:
+ DBUG_PRINT("info", ("mroonga: default"));
+ break;
+ }
+ DBUG_VOID_RETURN;
+ }
+}
diff --git a/storage/mroonga/lib/mrn_time_converter.hpp b/storage/mroonga/lib/mrn_time_converter.hpp
new file mode 100644
index 00000000000..c5c69a0a8ad
--- /dev/null
+++ b/storage/mroonga/lib/mrn_time_converter.hpp
@@ -0,0 +1,47 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2013 Kentoku SHIBA
+ Copyright(C) 2011-2013 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MRN_TIME_CONVERTER_HPP_
+#define MRN_TIME_CONVERTER_HPP_
+
+#include <groonga.h>
+#include <mrn_mysql_compat.h>
+
+namespace mrn {
+ class TimeConverter {
+ public:
+ static const long long int TM_YEAR_BASE = 1900;
+
+ TimeConverter();
+ ~TimeConverter();
+
+ long long int mysql_time_to_grn_time(MYSQL_TIME *mysql_time,
+ bool *truncated);
+
+ long long int tm_to_grn_time(struct tm *time, int usec, bool *truncated);
+
+ void grn_time_to_mysql_time(long long int grn_time, MYSQL_TIME *mysql_time);
+
+ private:
+ time_t tm_to_time_gm(struct tm *time, bool *truncated);
+ };
+}
+
+#endif /* MRN_TIME_CONVERTER_HPP_ */
diff --git a/storage/mroonga/lib/mrn_windows.hpp b/storage/mroonga/lib/mrn_windows.hpp
new file mode 100644
index 00000000000..f6ae4490254
--- /dev/null
+++ b/storage/mroonga/lib/mrn_windows.hpp
@@ -0,0 +1,31 @@
+/* -*- c-basic-offset: 2; indent-tabs-mode: nil -*- */
+/*
+ Copyright(C) 2010 Tetsuro IKEDA
+ Copyright(C) 2010-2013 Kentoku SHIBA
+ Copyright(C) 2011-2013 Kouhei Sutou <kou@clear-code.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef MRN_WINDOWS_HPP_
+#define MRN_WINDOWS_HPP_
+
+#if defined(_WIN32) || defined(_WIN64)
+# define MRN_API __declspec(dllexport)
+#else
+# define MRN_API
+#endif
+
+#endif /* MRN_WINDOWS_HPP_ */